ODE events where value is not part of the state - matlab

I'm currently working on a simple hybrid dynamical system with discrete state jumps. For that, I'm using ODE events. The problem is that my 'value's' (that which will cross zero) are not directly related to the state of the dynamical system. I'm not able to express these variables alongside the proper state (e.g. position + velocity of angles).
Currently, I'm using global variables but it seems that MATLAB does not decrease the step-size when the 'value' crosses zero. I assume this is because the value is not part of the state. Here is the code for the events;
function [value, isterminal,direction] = leg_events(t,x)
global isSwingL isSwingR frcLegL frcLegR posFooL posFooR frcComL frcComR
value = [];
isterminal = [];
direction = [];
if isSwingL
value = [value; posFooL(2)];
isterminal = [isterminal; 1];
direction = [direction; -1];
else
value = [value; frcComL(2)];
isterminal = [isterminal; 1];
direction = [direction; -1];
end
if isSwingR
value = [value; posFooR(2)];
isterminal = [isterminal; 1];
direction = [direction; -1];
else
value = [value; frcComR(2)];
isterminal = [isterminal; 1];
direction = [direction; -1];
end
end
Does anyone have any suggestions? Please let me know.
The model is implemented in Simulink which doe seem to be able to deal with this kind of thing but I need it specifically in code for optimization purposes.
I've also considered changing the 'MaxStep' but this makes the simulation unnecessary slow and unusable for the optimization.
[some context]: In concrete terms, the problem is that if I print the value of the event function during operation, the values occur as such ->
[0.2 0.12 0.4 -0.2 detected crossing]
Where the event is detected at -0.2. The state at this instance in time is taken to continue with the state but the system has clearly been progressed further making the subsequent dynamics of the system nonsense. I would have expected this ->
[0.2 0.12 0.4 0.1 0.01 0.001 -0.001 detected crossing]
which is what happens when the 'value' in the event function is part of the input arguments of the event function itself. Is it possible to ensure that the step size gets decreased when a 'value' that is not based on an input variable appears to cross the zero line?
Hope this helps

Related

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

Approximating derivative of numerical solution (using ode45) within event function

The issue I have is having to compute the derivative (in real time) of the solution produced by ode45 within the events function.
Some pseudo-code to explain what I'm mean is,
function dx = myfunc(t,x,xevent,ie)
persistent xs
persistent dx2
% xevent is the solution at the event
if isempty(dx2) == 1
dx2 = 0;
end
k = sign(dx2*x(1));
if ie(end) == 1
xs = xevent
elseif ie(end) == 2
xs = xevent
end
dx(1) = x(2);
dx(2) = function of k,x(1),x(2), and xs;
dx2 = dx(2);
end
function [value,isterminal,direction] = myeventfcn(t,x)
% dx2 = some function of x
if dx2*x(1)>=0
position = [dx2*x(1); dx2*x(1)];
isterminal = [1; 1];
direction = [1 ; -1 ];
elseif dx2*x(1)<0
position = [dx2*x(1); dx2*x(1)];
isterminal = [1; 1];
direction = [-1 ; 1 ];
end
I know that if I didn't need to use the solution at the event within myfunc I could just compute dx=myfunc(t,x) within my event function and use dx(2), yet since xevent is used within myfunc I can't input xevent.
I know there is a way of inputting constant parameters within the event function, but since it's the solution at the event location, which also changes, I'm not sure how to go about doing that.
My work around to this is to approximate dx(2) using the solution x. What I wanted to know is if it will be satisfactory to just use a finite difference approximation here, using a small fixed step size relative to the step size od45 takes, which is a variable step size.
As a note, the reason I have myeventfcn split by the if statement is to know what the direction the event is crossed, since it will update within myfunc.
Also, I need to use dx(2) of the previous successful time step and so that's why I have dx2 defined as a persistent variable. I believe having k=sign(dx(2)*x(1)) is okay to do, since my event depends on dx(2)*x(1), and so I won't be introducing any new discontinuities with the sign function.
Thanks for any help!

MATLAB - Event Location fail to work?

The event location function fail in finding an easy event when solving a 4 variables system of ode. Here's the code:
options1 = odeset('RelTol',1e-5,'AbsTol',1e-9,'Events',#evento1);
[T_ode1,X_ode1,te]=ode15s(#Seno,[0 2],[0 0 0 0 0],options1);
function [y] = Seno(t,x)
%Parameters
V=20;
R=1e6;
epsilon=8.87e-12;
d=4.5e-5;
k_sp=10;
gamma1=0.04;
gamma2=0.1;
m=66e-3;
A=0.1;
omega=80;
h=3.8e-6;
l=2e-3;
N=142;
%Variable redefinition
%x=[x,xpunto,q,y,ypunto]
X=x(1);
Xp=x(2);
Q=x(3);
Y=x(4);
Yp=x(5);
%sistema eq differenziali
y(1)=Xp; %y1(1)=position1
y(2)=-(2*k_sp*X/m)-(gamma1*Xp/m)+((epsilon*2*d*h*N*l)*X*V^2/((d^2-X^2)^2))+A*sin(omega*t); %y1(2)=velocity1
y(3)=1/R*(V-Q*(d^2-X^2)/(epsilon*2*d*h*N*l)); %y1(3)=charge
y(4)=Yp; %position 2
y(5)=-gamma2*Yp; %velocity2
y=y';
end
function [condition,ends,directions] = evento1(t,y)
a=2e-6;
c=2e-6;
b=1.5e-6;
condition= [(y(1)^2)-(a+c)^2, (y(4)^2)-(y(1)+b)^2, (y(4)^2)-(y(1)-b)^2];
ends = [1, 1, 1]; % Halt integration
directions = [1, -1, 1];
end
Setting all the initial condition to 0, as you can see, the first event that the event function should find is when the tird condition when y(1) pass for 1.5e-6 (y(4) is 0). Unfortunally ode ignore that event and stop the solution when the 1st one is satisfied.
I can't see why this happen! I tryed the debugging mode and the systems properly pass across 1.5e-6 but doesn't consider it as an event (ie it doesn't start to evaluate the solution in more points near the event).
Thanks for your time and sorry for my english.
As I mentioned in the comments, you can plot your event conditions after simulating the system:
options1 = odeset('RelTol',1e-5,'AbsTol',1e-9,'Events',#evento1);
[T_ode1,X_ode1,te] = ode15s(#Seno,[0 2],[0 0 0 0 0],options1);
a = 2e-6;
c = 2e-6;
b = 1.5e-6;
y = X_ode1;
condition = [y(:,1).^2-(a+c)^2 y(:,4).^2-(y(:,1)+b).^2 y(:,4).^2-(y(:,1)-b).^2];
figure;
plot(T_ode1,condition);
hold on;
plot(T_ode1([1 end]),[0 0],'k--',te,0,'k*');
legend('Condition 1','Condition 2','Condition 3','Location','W');
xlabel('Time');
ylabel('State');
ylim([-1.8e-11 2e-12]);
This results in a plot that looks like this:
If you zoom in on the plot you'll see that the third condition (yellow) never crosses zero and thus never triggers an event. Eventually the first event (blue) crosses zero and does trigger an event. Adjusting the integration tolerances doesn't appear to change this behavior (at best the third condition might asymptotically touch, but not cross, zero). If you want the third condition to trigger an event, you'll either need to change your parameters, change the condition, change your initial conditions, or change your ODEs.
I'm not sure if or why you think the third condition should cross zero, but if the system is numerically sensitive, then you may need to compensate for this by specifying parameter more precisely or artificially biasing the point of zero crossing.

Simulation of Markov chains

I have the following Markov chain:
This chain shows the states of the Spaceship, which is in the asteroid belt: S1 - is serviceable, S2 - is broken. 0.12 - the probability of destroying the Spaceship by a collision with an asteroid. 0.88 - the probability of that a collision will not be critical. Need to find the probability of a serviceable condition of the ship after the third collision.
Analytical solution showed the response - 0.681. But it is necessary to solve this problem by simulation method using any modeling tool (MATLAB Simulink, AnyLogic, Scilab, etc.).
Do you know what components should be used to simulate this process in Simulink or any other simulation environment? Any examples or links.
First, we know the three step probability transition matrix contains the answer (0.6815).
% MATLAB R2019a
P = [0.88 0.12;
0 1];
P3 = P*P*P
P(1,1) % 0.6815
Approach 1: Requires Econometrics Toolbox
This approach uses the dtmc() and simulate() functions.
First, create the Discrete Time Markov Chain (DTMC) with the probability transition matrix, P, and using dtmc().
mc = dtmc(P); % Create the DTMC
numSteps = 3; % Number of collisions
You can get one sample path easily using simulate(). Pay attention to how you specify the initial conditions.
% One Sample Path
rng(8675309) % for reproducibility
X = simulate(mc,numSteps,'X0',[1 0])
% Multiple Sample Paths
numSamplePaths = 3;
X = simulate(mc,numSteps,'X0',[numSamplePaths 0]) % returns a 4 x 3 matrix
The first row is the X0 row for the starting state (initial condition) of the DTMC. The second row is the state after 1 transition (X1). Thus, the fourth row is the state after 3 transitions (collisions).
% 50000 Sample Paths
rng(8675309) % for reproducibility
k = 50000;
X = simulate(mc,numSteps,'X0',[k 0]); % returns a 4 x 50000 matrix
prob_survive_3collisions = sum(X(end,:)==1)/k % 0.6800
We can bootstrap a 95% Confidence Interval on the mean probability to survive 3 collisions to get 0.6814 ± 0.00069221, or rather, [0.6807 0.6821], which contains the result.
numTrials = 40;
ProbSurvive_3collisions = zeros(numTrials,1);
for trial = 1:numTrials
Xtrial = simulate(mc,numSteps,'X0',[k 0]);
ProbSurvive_3collisions(trial) = sum(Xtrial(end,:)==1)/k;
end
% Mean +/- Halfwidth
alpha = 0.05;
mean_prob_survive_3collisions = mean(ProbSurvive_3collisions)
hw = tinv(1-(0.5*alpha), numTrials-1)*(std(ProbSurvive_3collisions)/sqrt(numTrials))
ci95 = [mean_prob_survive_3collisions-hw mean_prob_survive_3collisions+hw]
maxNumCollisions = 10;
numSamplePaths = 50000;
ProbSurvive = zeros(maxNumCollisions,1);
for numCollisions = 1:maxNumCollisions
Xc = simulate(mc,numCollisions,'X0',[numSamplePaths 0]);
ProbSurvive(numCollisions) = sum(Xc(end,:)==1)/numSamplePaths;
end
For a more complex system you'll want to use Stateflow or SimEvents, but for this simple example all you need is a single Unit Delay block (output = 0 => S1, output = 1 => S2), with a Switch block, a Random block, and some comparison blocks to construct the logic determining the next value of the state.
Presumably you must execute the simulation a (very) large number of times and average the results to get a statistically significant output.
You'll need to change the "seed" of the random generator each time you run the simulation.
This can be done by setting the seed to be "now" (or something similar to that).
Alternatively you could quite easily vectorize the model so that you only need to execute it once.
If you want to simulate this, it is fairly easy in matlab:
servicable = 1;
t = 0;
while servicable =1
t = t+1;
servicable = rand()<=0.88
end
Now t represents the amount of steps before the ship is broken.
Wrap this in a for loop and you can do as many simulations as you like.
Note that this can actually give you the distribution, if you want to know it after 3 times, simply add && t<3 to the while condition.

MATLAB - understanding structure of Event location function

In my textbook I have encountered an example of a function I am supposed to use when specifying an event location for a system of ODEs. The function example is as follows:
function [value, isterminal, dircn] = proj(t,z,flag);
g = 9.81;
if nargin < 3 | isempty(flag)
value = [z(2); 0; z(4); -g];
else
switch flag
case 'events'
value = z(3);
isterminal = 1;
dircn = -1;
otherwise
error('function not programmed for this event');
end
end
There is one part of the logic here which I don't understand. Say that I activate the "events" option and then run ode45. How, then, can ode45 actually read the system of equations (which is specified in the above function as value = [z(2); 0; z(4); -g];)? I have ran ode45 based on the above function, after specifying tspan and inital conditions of course, and it works like a charm. But I don't understand how ode45 can read the system properly when it is only presented in the "if"-part of the script above.
If anyone can explain the logic here, I would greatly appreciate it!
Well I think I can explain some parts. As I wrote above it is strange that the dimension of value changes.
given your statespace and the names of your variables it looks like 2 dimensional motion.
in the case of no flag it seems that state space is:
horizontal position (x)
horizontal speed (vx)
vertical position (y)
vertical speed (vy)
correction
It seems that ode can send 'events' when you specify them. So your function outputs 3rd component of the state space. Look at this site explaining it: http://www.mathworks.de/help/techdoc/math/f1-662913.html
unless you specify it beforehand ode can't send 'events' to the function so this part will not be called.
But your function won't work anyway - as the derivative would need to have same dimension as the statespace (4x1). But has only 1x1.
But I really don't know what you mean by "specifying an event location". Maybe the secret is hidden there.
With some creativity I think you could use the function to extract the 3rd component of the state space.
The answer is in the if command:
if nargin < 3 | isempty(flag)
value = [z(2); 0; z(4); -g];
else
If number of arguments is less than 3 or if variable flag is empty, then set variable value to [z(2); 0; z(4); -g]. Otherwise, if variable flag is 'events', then set variable value to z(3), and when flag is not 'events', report an error. So this function always assigns some return value for variable value or, reports an error using error command.
I can supplement a bit more information about how we proceed after writing the function above. We then define, say:
tspan = [0 6];
z0 = [0, 5*cos(pi/4), 0, 5*sin(pi/4)];
options = odeset('events','on');
[t y] = ode42('proj',tspan,z0,options)
By writing this the output is 5 columns, 1 column for tspan , and 1 column for each of the z-values (z(1), z(2), z(3) and z(4)). When z(3) hits zero, the calculations are terminated since the "event" occurs.
If, on the other hand I do not include the options = odeset('events','on') line, and simply write:
[t y] = ode42('proj',tspan,z0)
The calculations are performed for the entire tspan range.
Yet, I still fail to see how ode42 is capable of calculating all the output vectors when we activate "events" since it then looks logical me that MatLab should only execute the "else"-statement in the "proj"-function. And in this part of the function, the actual system of the differential equations is not included.