Solving DDE with small time steps in for loop - matlab

I want to solve following DDE using a for loop in MATLAB:
xdot(t) = Ax(t) + BKx(t-h)
in which:
A = [0 1 ; -1 0.1];
B = [0 ; 1];
h = 0.2;
K = [-0.0469 -1.7663];
t = [0 5]
Solving this with conventional procedure is simple and the results are acceptable.
sol = dde23(ddefun,lags,history,tspan,options,varargin)
However, when I try to solve it using for loop, the results are wrong. Here is a simple code for my for loop.
time = 0:0.001:5;
for i = 2:5001
x(:,1) = [1 -1];
history(:,1) = [1 -1];
[t h] = ode23(#(t,h)histExam1(t,h,A,B,K),[time(i-1) time(i)],history(:,i-1));
history(:,i)= h(end,:);
sol = dde23(((#(t,y,z)ddefun(t,y,z,A,B,K))),0.2,history(:,i),[time(i-1) time(i)]);
x(:,i)=sol.y(:,end);
end
I think, the only problem in this code is my time steps and delay input. I use same dde function for both codes so It cannot be a problem.The reason I want to solve DDE in a for loop is "BK" value which is state dependent (not in this simple example) and in each time step I need to update "BK".
The correct answer plotted above with conventional method.
And the wrong answer I get using "for loop" is plotted above.
It is interesting to mention that correct answer is sensitive to delay. But delay doesn’t affect the answer from 2nd method.

Ok. After weeks of thinking, finally found a solution.
Simply:
sol = dde23(((#(t,y,z)ddefun(t,y,z,A,B,K))),0.2,[1;-1],[0 time(i)]);
and let the magics happen.
This code helps you with updating states at each time step.
I hope it will help you in the future.
All the Best,
Sina

Related

Strange wrong result for (un)coupled PDEs using MATLAB's pdepe, time is doubled

I am trying to solve two coupled reaction diffusion equations in 1d, using pdpe, namely
$\partial_t u_1 = \nabla^2 u_1 + 2k(-u_1^2+u_2)$
$\partial_t u_2 = \nabla^2 u_1 + k(u_1^2-u_2)$
The solution is in the domain $x\in[0,1]$, with initial conditions being two identical Gaussian profiles centered at $x=1/2$. The boundary conditions are absorbing for both components, i.e. $u_1(0)=u_2(0)=u_1(1)=u_2(1)=0$.
Pdepe gives me a solution without prompting any errors. However, I think the solutions must be wrong, because when I set the coupling to zero, i.e. $k=0$ (and also if I set it to be very small, say $k=0.001$), the solutions do not coincide with the solution of the simple diffusion equation
$\partial_t u = \nabla^2 u$
as obtained from pdepe itself.
Strangely enough, the solutions $u_1(t)=u_2(t)$ from the "coupled" case with coupling set to zero, and the solution for the case uncoupled by construction $u(t')$ coincide if we set $t'=2t$, that is, the solution of the "coupled" case evolves twice as fast as the solution of the uncoupled case.
Here's a minimal working example:
Coupled case
function [xmesh,tspan,sol] = coupled(k) %argument is the coupling k
std=0.001; %width of initial gaussian
center=1/2; %center of gaussian
xmesh=linspace(0,1,10000);
tspan=linspace(0,1,1000);
sol = pdepe(0,#pdefun,#icfun,#bcfun,xmesh,tspan);
function [c,f,s] = pdefun(x,t,u,dudx)
c=ones(2,1);
f=zeros(2,1);
f(1) = dudx(1);
f(2) = dudx(2);
s=zeros(2,1);
s(1) = 2*k*(u(2)-u(1)^2);
s(2) = k*(u(1)^2-u(2));
end
function u0 = icfun(x)
u0=ones(2,1);
u0(1) = exp(-(x-center)^2/(2*std^2))/(sqrt(2*pi)*std);
u0(2) = exp(-(x-center)^2/(2*std^2))/(sqrt(2*pi)*std);
end
function [pL,qL,pR,qR] = bcfun(xL,uL,xR,uR,t)
pL=zeros(2,1);
pL(1) = uL(1);
pL(2) = uL(2);
pR=zeros(2,1);
pR(1) = uR(1);
pR(2) = uR(2);
qL = [0 0;0 0];
qR = [0 0;0 0];
end
end
Uncoupled case
function [xmesh,tspan,sol] = uncoupled()
std=0.001; %width of initial gaussian
center=1/2; %center of gaussian
xmesh=linspace(0,1,10000);
tspan=linspace(0,1,1000);
sol = pdepe(0,#pdefun,#icfun,#bcfun,xmesh,tspan);
function [c,f,s] = pdefun(x,t,u,dudx)
c=1;
f = dudx;
s=0;
end
function u0 = icfun(x)
u0=exp(-(x-center)^2/(2*std^2))/(sqrt(2*pi)*std);
end
function [pL,qL,pR,qR] = bcfun(xL,uL,xR,uR,t)
pL=uL;
pR=uR;
qL = 0;
qR = 0;
end
end
Now, suppose we run
[xmesh,tspan,soluncoupled] = uncoupled();
[xmesh,tspan,solcoupled] = coupled(0); %coupling k=0, i.e. uncoupled solutions
One can directly check by plotting the solutions for any time index $it$ that, even if they should be identical, the solutions given by each function are not identical, e.g.
hold all
plot(xmesh,soluncoupled(it+1,:),'b')
plot(xmesh,solcoupled(it+1,:,1),'r')
plot(xmesh,solcoupled(it+1,:,2),'g')
On the other hand, if we double the time of the uncoupled solution, the solutions are identical
hold all
plot(xmesh,soluncoupled(2*it+1,:),'b')
plot(xmesh,solcoupled(it+1,:,1),'r')
plot(xmesh,solcoupled(it+1,:,2),'g')
The case $k=0$ is not singular, one can set $k$ to be small but finite, and the deviations from the case $k=0$ are minimal, i.e. the solution still goes twice as fast as the uncoupled solution.
I really don't understand what is going on. I need to work on the coupled case, but obviously I don't trust the results if it does not give the right limit when $k\to 0$. I don't see where I could be making a mistake. Could it be a bug?
I found the source of the error. The problem lies in the qL and qR variables of bcfun for the coupled() function. The MATLAB documentation, see here and here, is slightly ambiguous on whether the q's should be matrices or column vectors. I had used matrices
qL = [0 0;0 0];
qR = [0 0;0 0];
but in reality I should have used column vectors
qL = [0;0];
qR = [0;0];
Amazingly, pdpe didn't throw an error, and simply gave wrong results. This should perhaps be fixed by the developers.

MATLAB: Issue with Simulink "does not support code generation"

I have something similar to the following block diagram on Simulink, which looks rather messy especially with an increasing number of blocks.
I want to replace a 3-point summing block with a function block, while keeping the same output.
First I started by placing the code inside the function block:
function y = fcn(u)
sys1 = tf(0.5,[1 0 0 4]);
sys2 = tf([3 0.5],[1 0 15]);
sys3 = tf(1,[1 1]);
y = sys1 + sys2 + sys3;
However I was greeted with an error saying that Simulink does not support code generation.
"The 'tf' class does not support code generation."
I then came across a similar problem here: https://nl.mathworks.com/matlabcentral/answers/74770-is-there-any-way-to-disable-code-generation-in-simulink
I am trying to implement an extrinsic function or 'wrapper function' with some difficulty. I created a new script called myWrapper.m, containing the same code:
function y = myWrapper(u)
sys1 = tf(0.5,[1 0 0 0 4]);
sys2 = tf([3 5],[1 0 15]);
sys3 = tf(1,[1 1]);
y = sys1 + sys2 + sys3;
and the MATLAB Function edited to:
function y1 = fcn(u1)
y1 = myWrapper(u1);
The error persists.
I somehow want to access myWrapper.m file from the MATLAB Function block. Any pointers on how this should be done? Following the previous link given and the official docs I am ending up with something like this in my MATLAB Function block:
function y1 = fcn(u1)coder.extrinsic('myWrapper')
y1 = myWrapper(u1);
The last code above is syntactically incorrect and I am at a loss on how it should be done. MATLAB automaticaly corrects the above code to:
function y1 = fcn(u1,coder,extrinsic, myWrapper )
y1 = myWrapper(u1);
which is not what I want.
Any tips and/or suggestions on how this could be done would be appreciated.
A similar question was asked on the MathWorks forum here, two years ago, with no response.
I was going about tackling this problem completely wrong. Thanks to several helpful comments I realized that in order to replace the summing block, one must NOT remove the Transfer Function blocks which feed into the summing block.
A MATLAB Function does not support code generation (and rightly so) such that a transfer function may be implemented inside it. That is why the blocks simply feed into the MATLAB Function as follows.
The script would very simply be:
function y1 = fcn(u1, u2, u3)
x = (u1 + u2 +u3);
y1 = x;
end

Setting up two events with ode45

Could someone please explain what am I doing wrong when setting up an ode45 event this way?
When I tried running the code it would reach line 6, however it would not stop computing the ode regardless that I set isTerminal=[1,1] on line 7, instead it continues until the end: when the second event z(3) reaches 0 at which point it reaches line 10 and depending on whether I set isTerminal=[1,1] or isTerminal=[0,1] then it stops the computation with isTerminal(1) as the triggered event and isTerminal(2) in the later case.
function [value, isTerminal, direction] = myEvent(t, z)
posObst=100;
dist = z(1)-posObst;
if dist == 0
value = [dist; z(3)];
isTerminal = [1; 1];
direction = [0; -1];
else
value = [dist; z(3)];
isTerminal = [0; 1];
direction = [-1 ; -1];
end
end
My question is why doesn't the ode stop the computations once it reaches line 7? This is the most minimalistic example I could come up with. If there is anything else I should add please let me know.
I found what the problem was. It arises from the line
if dist==0
Should have defined a tolerance and then made the floating point comparison like so:
tol = 1e-4
if dist <= tol

MatLab ode45 explanation

For a project I need to understand a matlab code, but as I am quite new I dont really understand what is happening. I have a function file and a script file.
Function:
function dxdt = sniffer_ode(t,x,par,tu)
X = x(1);
R = x(2);
k1 = par(1);
k2 = par(2);
k3 = par(3);
k4 = par(4);
S = interp1(tu(:,1),tu(:,2),t);
dxdt(1) = k3*S-k4*X;
dxdt(2) = k1*S-k2*X*R;
dxdt = dxdt(:); %dxdt should be column
and the script file:
%sniffer
close all
%initial conditions:
X0=0; R0=0;
x0=[X0 R0];
%parameters:
k1=1; k2=1; k3=1; k4=1;
par=[k1 k2 k3 k4];
%input:
tu=[ 0 , 0
1 , 0
1.01, 1
20 , 1];
[t,x] = ode45(#sniffer_ode,[0 20],x0, [],par,tu);
plot(t,x);
So the question is: What is happening? I also need to plot S in the same figure as X and R. How do I do this?
I appreciate your help!
This is a really basic Matlab question. There is tons of information about your requested topic. I think these slides will help you on the right path.
However, a quick explanation; the first code you provide is the function which describes your ordinary differential equation. This function always has to be of the form x' = f(t,x,...). Herein t is the time and x is the state. After the state (on the place of the dots ...) you can define other input parameters, such as is being done in your ode function. Furthermore, the interp1 function interpolates the data provided.
The second code you provide is the code you start within Matlab. Parameters are defined, after which the ordinary differential equation is solved and plotted.
If you have any further questions I would recommend that you first try to find your answer using a search engine.

How to write many functions depending on each other in matlab

I have some functions are depending on each ther , the functions are from this book page 136 http://www.cs.helsinki.fi/u/ahyvarin/papers/bookfinal_ICA.pdf .. I functions are presented below , How to write following functions in matlab ??
y(t) = W(t-1)*x(t)
h(t) = P(t-1)*y(t)
P(t)=(1/B)*Tri[P(t-1)-m(t)*h^T(t)]
m(t) = h(t)/(B+y^T(t))*h(t))
e(t) = x(t)-W^T(t-1)*y(t)
W(t) = W(t-1) + m(t)*e^T(t)
It is solving the weight matrix W(t) iteratively .. I tried to do like this in matlab but I did not work so may be you can advice to correct the code :
for i=1:10
e=randn(3,5000);
A=[1 0 0;-0.5 0.5 0;0.3 0.1 0.1];
x=A*e;
y(t) = W(t-1)*x(t)
h(t) = P(t-1)*y(t)
P(t)=(1/B)*Tri[P(t-1)-m(t)*h^T(t)]
m(t) = h(t)/(B+y^T(t))*h(t))
e(t) = x(t)-W^T(t-1)*y(t)
W(t) = W(t-1) + m(t)*e^T(t)
end
Thanks
Ok. I can't really understand what you want, but your code shows that you don't understand some moments. I will try to clarify some moments to you:
for i = 2:10
x = rand(3);
y = W(:,:,i-1)*x;
h = P(:,:,i-1)*y;
m=h/(1+y'*h);
P(:,:,i)=P(:,:,i-1)*m*h';
e=x-W(:,:,i-1)'*y;
W(:,:,i)=W(:,:,i-1)+m*e';
end
You must go something like this: 1. you calculate x and use it to calculate other functions.
2. all of them are matrices. So you need to define it first. For example y = ones(3) etc. 3.Thats not y^T or e^T. Its transposing. If you do not feel difference it's early for you to solve this task :)
And the last: Tri function will create a some kind of problems to you, but it's defined at 136 page.
P.S. i missed beta becouse of don't know what is it :)