How can I invert my temperature to display in the positive domain? - matlab

The experimental set up and analytical solution I am trying to solve a parabolic PDE with the pdepe function in MATLAB. The code runs fine, but the temperature is in the inverted direction when I use my boundary conditions as it is in the physical situation. I can interpret the results and it matches what I am looking for, but I want to be able to display the temperature in both the correct magnitude and direction. What am I missing?
I can swap the boundary surfaces, that is, swap x=0 and x=L, (while keeping the boundary conditions the same); and the temperature would be in the correct direction but the distance is now inverse.
L = 0.1524;
k = 0.0022;
cp = 1.92;
rho = 0.946;
tend = 18;
Flux = 1.1;
m = 0;
x = linspace(0,L,200);
t = linspace(0,tend,100);
sol = pdepe(m,#pdex1pde,#pdex1ic,#pdex1bc,x,t);
Temperature = sol(:,:,1);
surf(x,t,Temperature)
title('Surface Temperature')
xlabel('Distance x')
ylabel('Time t')
zlabel('Temperature (C)')
function [c,f,s] = pdex1pde(x,t,u,DuDx)
global rho cp k
c = rho*cp;
f = k*DuDx;
s = 0;
function [Temperature] = pdex1ic(x)
Temperature = 25;
function [pl,ql,pr,qr] = pdex1bc(xl,ul,xr,ur,t)
global Flux k
pl = 0;
ql = 1/k;
pr = Flux;
qr = 1;
The temperature is inverse. I expect a range up to 120, I'm getting a line that terminates at about -120.
The result of the numerical solution that shows the inverted temperature

Related

How to implement an guess correcting algorithm when solving a BVP with shooting method?

I have a boundary value problem (specified in the picture below) that is supposed to be solved with shooting method. Note that I am working with MATLAB when doing this question. I'm pretty sure that I have rewritten the differential equation from a 2nd order differential equation to a system of 1st order differential equations and also approximated the missed value for the derivative of this differential equation when x=0 using the secant method correctly, but you could verify this so you'll be sure.
I have done solving this BVP with shooting method and my codes currently for this problem is as follows:
clear, clf;
global I;
I = 0.1; %Strength of the electricity on the wire
L = 0.400; %The length of the wire
xStart = 0; %Start point
xSlut = L/2; %End point
yStart = 10; %Function value when x=0
err = 5e-10; %Error tolerance in calculations
g1 = 128; %First guess on y'(x) when x=0
g2 = 89; %Second guess on y'(x) when x=0
state = 0;
X = [];
Y = [];
[X,Y] = ode45(#calcWithSec,[xStart xSlut],[yStart g1]');
F1 = Y(end,2);
iter = 0;
h = 1;
currentY = Y;
while abs(h)>err && iter<100
[X,Y] = ode45(#calcWithSec,[xStart xSlut],[yStart g2]');
currentY = Y;
F2 = Y(end,2);
Fp = (g2-g1)/(F2-F1);
h = -F2*Fp;
g1 = g2;
g2 = g2 + h;
F1 = F2;
iter = iter + 1;
end
if iter == 100
disp('No convergence')
else
plot(X,Y(:,1))
end
calcWithSec:
function fp = calcWithSec(x,y)
alpha = 0.01; %Constant
beta = 10^13; %Constant
global I;
fp = [y(2) alpha*(y(1)^4)-beta*(I^2)*10^(-8)*(1+y(1)/32.5)]';
end
My problem with this program is that for different given I's in the differential equation, I get strange curves that does not make any sense in physical meaning. For instance, the only "good" graph I get is when I=0.1. The graph to such differential equations is as follows:
But when I set I=0.2, then I get a graph that looks like this:
Again, in physical meaning and according to the given assignment, this should not happen since it gets hotter you closer you get to the middle of the mentioned wire. I want be able to calculate all I between 0.1 and 20, where I is the strength of the electricity.
I have a theory that it has something to do with my guessing values and therefore, my question is about if there is possible to implement an algorithm that forces the program to adjust the guessing values so I can get a graph that is "correct" in physical meaning? Or is it impossible to achieve this? If so, then explain why.
I have struggled with this assignment many days in row now, so all help I can get with this assignment is worth gold to me now.
Thank you all in advance for helping me out of this!

Interpolation using polyfit (Matlab)

My script is supposed to run Runge-Kutta and then interpolate around the tops using polyfit to calculate the max values of the tops. I seem to get the x-values of the max points correct but the y-values are off for some reason. Have sat with it for 3 days now. The problem should be In the last for-loop when I calculate py?
Function:
function funk = FU(t,u)
L0 = 1;
C = 1*10^-6;
funk = [u(2); 2.*u(1).*u(2).^2./(1+u(1).^2) - u(1).*(1+u(1).^2)./(L0.*C)];
Program:
%Runge kutta
clear all
close all
clc
clf
%Given values
U0 = [240 1200 2400];
L0 = 1;
C = 1*10^-6;
T = 0.003;
h = 0.000001;
W = [];
% Runge-Kutta 4
for i = 1:3
u0 = [0;U0(i)];
u = u0;
U = u;
tt = 0:h:T;
for t=tt(1:end-1)
k1 = FU(t,u);
k2 = FU(t+0.5*h,u+0.5*h*k1);
k3 = FU((t+0.5*h),(u+0.5*h*k2));
k4 = FU((t+h),(u+k3*h));
u = u + (1/6)*(k1+2*k2+2*k3+k4)*h;
U = [U u];
end
W = [W;U];
end
I1 = W(1,:); I2 = W(3,:); I3 = W(5,:);
dI1 = W(2,:); dI2 = W(4,:); dI3 = W(6,:);
I = [I1; I2; I3];
dI = [dI1; dI2; dI3];
%Plot of the currents
figure (1)
plot(tt,I1,'r',tt,I2,'b',tt,I3,'g')
hold on
legend('U0 = 240','U0 = 1200','U0 = 2400')
BB = [];
d = 2;
px = [];
py = [];
format short
for l = 1:3
[H,Index(l)]=max(I(l,:));
Area=[(Index(l)-2:Index(l)+2)*h];
p = polyfit(Area,I(Index(l)-2:Index(l)+2),4);
rotp(1,:) = roots([4*p(1),3*p(2),2*p(3),p(4)]);
B = rotp(1,2);
BB = [BB B];
Imax(l,:)=p(1).*B.^4+p(2).*B.^3+p(3).*B.^2+p(4).*B+p(5);
Tsv(i)=4*rotp(1,l);
%px1 = linspace(h*(Index(l)-d-1),h*(Index(l)+d-2));
px1 = BB;
py1 = polyval(p,px1(1,l));
px = [px px1];
py = [py py1];
end
% Plots the max points
figure(1)
plot(px1(1),py(1),'b*-',px1(2),py(2),'b*-',px1(3),py(3),'b*-')
hold on
disp(Imax)
Your polyfit line should read:
p = polyfit(Area,I(l, Index(l)-2:Index(l)+2),4);
More interestingly, take note of the warnings you get about poor conditioning of that polynomial (I presume you're seeing these). Why? Partly because of numerical precision (your numbers are very small, scaled around 10^-6) and partly because you're asking for a 4th-order fit to five points (which is singular). To do this "better", use more input points (more than 5), or a lower-order polynomial fit (quadratic is usually plenty), and (probably) rescale before you use the polyfit tool.
Having said that, in practice this problem is often solved using three points and a quadratic fit, because it's computationally cheap and gives very nearly the same answers as more complex approaches, but you didn't get that from me (with noiseless data like this, it doesn't much matter anyway).

Summing scalars and vectors [MATLAB]

First off; I'm not very well taught in programming, but i tend to learn exactly what I need to learn in order to do what I want when programming, I have moderate experience with python, html/css C and matlab. I've now enrolled in a physics-simulation course where I use matlab to compute the trajectory of 500 particles under the influence of 5 force-fields of different magnitude.
So now to my thing; I need to write the following for all i=1...500 particles
f_i = m*g - sum{(f_k/r_k^2)*exp((||vec(x)_i - vec(p)_k||^2)/2*r_k^2)(vec(x)_i - vec(p)_k)}
I hope its not too cluttered
And here is my code so far;
clear all
close all
echo off
%Simulation Parameters-------------------------------------------
h = 0.01; %Time-step h (s)
t_0 = 0; %initial time (s)
t_f = 3; %final time (s)
m = 1; %Particle mass (kg)
L = 5; %Charateristic length (m)
NT = t_f/h; %Number of time steps
g = [0,-9.81];
f = [32 40 28 16 20]; %the force f_k (N)
r = [0.3*L 0.2*L 0.4*L 0.5*L 0.3*L]; %the radii r_k
p = [-0.2*L 0.8*L; -0.3*L -0.8*L; -0.6*L 0.1*L;
0.4*L 0.7*L; 0.8*L -0.3*L];
%Forcefield origin position
%stepper = 'forward_euler'; % use forward Euler time-integration
fprintf('Simulation Parameters set');
%initialization---------------------------------------------------
for i = 1:500 %Gives inital value to each of the 500 particles
particle{i,1}.x = [-L -L];
particle{i,1}.v = [5,10];
particle{i,1}.m = m;
for k = 1:5
C = particle{i}.x - p(k,:);
F = rdivide(f(1,k),r(1,k)^2).*C
%clear C; %Creates elements for array F
end
particle{i}.fi = m*g - sum(F); %Compute attractive force on particle
%clear F; %Clear F for next use
end
What this code seems to do is that it goes into the first loop with index i, then goes through the 'k'-loop and exits it with a value for F then uses that last value for F(k) to compute f_i.
What I want it to do is to put all the values of F(k) from 1-5 and put into a matrix which columns I can sum for f_i. I'd prefer to sum the columns as the first column should represent all F-components in the x-axis and the second column all F-components in the y-axis.
Note that the expression for F in the k-loop is not done.
I fixed it by defining the index for F(k,:)

Solving PDE with Matlab

`sol = pdepe(m,#ParticleDiffusionpde,#ParticleDiffusionic,#ParticleDiffusionbc,x,t);
% Extract the first solution component as u.
u = sol(:,:,:);
function [c,f,s] = ParticleDiffusionpde(x,t,u,DuDx)
global Ds
c = 1/Ds;
f = DuDx;
s = 0;
function u0 = ParticleDiffusionic(x)
global qo
u0 = qo;
function [pl,ql,pr,qr] = ParticleDiffusionbc(xl,ul,xr,ur,t,x)
global Ds K n
global Amo Gc kf rhop
global uavg
global dr R nr
sum = 0;
for i = 1:1:nr-1
r1 = (i-1)*dr; % radius at i
r2 = i * dr; % radius at i+1
r1 = double(r1); % convert to double precision
r2 = double(r2);
sum = sum + (dr / 2 * (r1*ul+ r2*ur));
end;
uavg = 3/R^3 * sum;
ql = 1;
pl = 0;
qr = 1;
pr = -((kf/(Ds.*rhop)).*(Amo - Gc.*uavg - ((double(ur/K)).^2).^(n/2) ));`
dq(r,t)/dt = Ds( d2q(r,t)/dr2 + (2/r)*dq(r,t)/dr )
q(r, t=0) = 0
dq(r=0, t)/dr = 0
dq(r=dp/2, t)/dr = (kf/Ds*rhop) [C(t) - Cp(at r = dp/2)]
q = solid phase concentration of trace compound in a particle with radius dp/2
C = bulk liquid concentration of trace compound
Cp = trace compound concentration at particle surface
I want to solve the above pde with initial and boundary conditions given. Tried Matlab's pdepe, but does not work satisfactorily. Maybe the boundary conditions is creating problem for me. I also used this isotherm equation for equilibrium: q = K*Cp^(1/n). This is convection-diffusion equation but i could not find any write ups that addresses solving this type of equation properly.
There are two problems with the current implementation.
Incorrect Source Term
The PDE you are attempting to solve has the form
which has the equivalent form
where the last term arises due to the factor of 2 in the original PDE.
The last term needs to be incorporated into pdepe via a source term.
Calculation of q average
The current implementation attempts to calculate the average value of q using the left and right values of q passed to the boundary condition function.
This is incorrect.
The average value of q needs to be calculated from a vector of up-to-date values of the quantity.
However, we have the complication that the only function to receive all mesh values is ParticleDiffusionpde; however, the mesh values passed to that function are not guaranteed to be from the mesh we provided.
Solution: use events (as described in the pdepe documentation).
This is a hack since the event function is meant to detect zero-crossings, but it has the advantage that the function is given all values of q on the mesh we provide.
So, the working example below (you'll notice I set all of the parameters to 1 since I didn't know better) uses the events function to update a variable qStore that can be accessed by the boundary condition function (see here for an explanation), and the boundary condition function performs a vectorized trapezoidal integration for the average calculation.
Working Example
function [] = ParticleDiffusion()
% Parameters
Ds = 1;
q0 = 0;
K = 1;
n = 1;
Amo = 1;
Gc = 1;
kf = 1;
rhop = 1;
% Space
rMesh = linspace(0,1,10);
rMesh = rMesh(:) ;
dr = rMesh(2) - rMesh(1) ;
% Time
tSpan = linspace(0,1,10);
% Vector to store current u-value
qStore = zeros(size(rMesh));
options.Events = #(m,t,x,y) events(m,t,x,y);
% Solve
[sol,~,~,~,~] = pdepe(1,#ParticleDiffusionpde,#ParticleDiffusionic,#ParticleDiffusionbc,rMesh,tSpan,options);
% Use the events function to update qStore
function [value,isterminal,direction] = events(m,~,~,y)
qStore = y; % Value of q on rMesh
value = m; % Since m is constant, it will never be zero (no event detection)
isterminal = 0; % Continue integration
direction = 0; % Detect all zero crossings (not important)
end
function [c,f,s] = ParticleDiffusionpde(r,~,~,DqDr)
% Define the capacity, flux, and source
c = 1/Ds;
f = DqDr;
s = DqDr./r;
end
function u0 = ParticleDiffusionic(~)
u0 = q0;
end
function [pl,ql,pr,qr] = ParticleDiffusionbc(~,~,R,ur,~)
% Calculate average value of current solution
qL = qStore(1:end-1);
qR = qStore(2: end );
total = sum((qL.*rMesh(1:end-1) + qR.*rMesh(2:end))) * dr/2;
qavg = 3/R^3 * total;
% Left boundary
pl = 0;
ql = 1;
% Right boundary
qr = 1;
pr = -(kf/(Ds.*rhop)).*(Amo - Gc.*qavg - (ur/K).^n);
end
end

Simple Phase Shift for Removing Instrument Response

So I have a simple program where I want to shift a simple sine function pi/2. Now I knwo this would be extremely easy by just inserting a bias (i.e. A*sin(2*pi*frequency + bias). But this program is a simple way to test a theory. I need to shift complicated magnetic data, but the shift is frequency dependent. So to figure out how to do that I just want to shift this sin wave by a set shift, but I want to do it in the frequency domain. While the code below doesn't show any errors, it does not shift the data properly and effects magnitude. Code is below. Thank you!
clear all
time = 1:0.01:2*pi; %Create time vector
mag = sin(2*pi*time);
Y = fft(mag); %transform
Pnewr = pi/2;
%t = angle(mag);
t = imag(Y);
%t_fin = t-Pnewr; %Subtract the pahse delay from the original phase vector
R=real(Y);
I=t;
k = I./R
Phi = tan(k);
PhiFinal = Phi-Pnewr;
PhiFinal = PhiFinal'
IFinal = R * atan(PhiFinal);
spec=complex(R,IFinal);
Finalspec = ifft(spec); %Invert the transform
Final = Finalspec;
plot(time,mag);
hold on
plot(time,Final,'r')
grid on
For one thing you are not recombining imaginary and real components properly, since
PhiFinal = PhiFinal'
IFinal = R * atan(PhiFinal);
is effectively a dot product, not an element by element product. In general it doesn't look like you are making correct use of the complex relationships. The following generates a clean phase shift:
time = 1:0.01:2*pi;
mag = sin(2*pi*time);
Y = fft(mag); %transform
Pnewr = pi/2;
R = real(Y);
I = imag(Y);
It = abs(Y);
% It = sqrt(I.^2 + R.^2);
Phi= angle(Y); % <-- using matlab function, equivalent to `Phi = atan2(I, R);`
k = I./R;
Phi0 = atan(k);
figure, subplot(121), plot(Phi0,Phi,'.'), xlabel('Phi from tan'), ylabel('Phi from ''angle'''), grid on, axis('tight')
PhiFinal = Phi-Pnewr; % <-- phase shift
IFinal = It .* sin(PhiFinal);
RFinal = It .* cos(PhiFinal);
spec= RFinal + 1i*IFinal;
Final = ifft(spec); %Invert the transform
subplot(122)
plot(time,mag);
hold on
plot(time,real(Final),'r')
plot(time,imag(Final),'r:')
grid on
axis('tight')
legend('Initial','Final'),xlabel('t'), ylabel('I')
mag*mag' % <-- check that total power is conserved
Final*Final'
These figures show the phase as computed with tan vs matlab's angle (which uses atan2), and the results of the phase shift (right panel):