How to work variables outside function

79 views (last 30 days)
Nuno Nunes
Nuno Nunes on 6 Oct 2022
Commented: Walter Roberson on 7 Oct 2022
Hello Everybody,
I have an issue here. I'm working with the built-in Differential Equation Solver ode45 and I have it like:
close all
Vs = 14 * (1852 / 3600); % [m/s] Ship approach speed (reasonable value)
t = (0:250); % Manouevre time
y0 = [Vs 0 0 0 0 0 0]; % Inital condition - surge valocity is equal to the approach speed
option = menu('Choose a Manoeuvre:','Straight Run','Exit Menu');
if option == 1 % Choosing Straight Run
[T,Y] = ode45 ('StraightRun' , t , y0); % Calls Straight Run Function
figure % 1 % Ship Trajectory
box on;
grid on;
hold on;
axis([0 2500 -500 500])
plot(Y(:,4) , Y(:,5));
xlabel('X pos [m]');
ylabel('Y pos [m]');
legend('Ship Trajectory in Straight Run');
elseif option == 2 % Exit the Menu
in which everything is well defined and working fine.
y0 is the array displaying the initial conditions,
t is time.
StraightRun is a function:
function [dy] = StraightRun(t,y)
What I'm hoping for is that I am able to read a few variables outside the function like, for the X and Y position, I have the need to define X_AH and X_AS inside StraightRun.
How can I plot a graph of those (and other) variables outside the function. Without them having to go through ode45.
dpb on 6 Oct 2022
It was perfectly clear heading this way; I don't think you understood the response going back... <vbg>
An extra parameter is only part of the DE if you incorporate it in the dy array; anything else is just whatever it is...but it's not clear from what you've posted so far just what X_A, X_H are -- computed temporaries, constants, inputs, outputs...??? You've got X_A as a constant in computing Res which is, in fact, dy so it is by definition part of the DEs and had have come from somewhere for the above to have run.
But, as the above note also points out, you can make things global and have access to them anywhere; or if you create your function to do whatever it is you want to do as an internal function inside StraightRun, then it shares its name space and you have access to anything inside it (and vice versa).
Read the doc and the examples linked to carefully...I'm pretty sure the answer to your dilemma is there; depending on just what it is you're after, precisely, as to which technique(s) may be most useful.
Nuno Nunes
Nuno Nunes on 6 Oct 2022
Edited: Nuno Nunes on 6 Oct 2022
X_A and X_H (along with all the other variables I intend to call outside ode45) are variables computed on StraightRun.
Because StraightRun calls for external scripts (data.m / wind.m) which, themselves, calculate a bunch of other variables needed to fully calculate X_A.
This is all kind of a big mess, but it works, and I just want to get access to these final values (X_A and X_H).
From what I can see in ode45 on "Pass Extra Parameters to ODE Function", I need to define X_A outside ode45 and include them on the call for the StraightRun function through ode45:
X_A = 345;
if option == 1
[T,Y] = ode45 ('StraightRun' , t , y0);
Even though
function [dy] = StraightRun(t,y,X_AS)
I've done so, but when I run the "option 1", and I type in the Command Window X_A, it just gives me the value I assigned it (in this case 345).
It doesn't save the value obtained from the function.

Sign in to comment.

Answers (1)

Walter Roberson
Walter Roberson on 6 Oct 2022
People often ask to be able to get a copy outside the ode function of all of the values they computed inside the ode function. It is understandable that people ask that... but it turns out to be the wrong thing to do in the great majority of cases.
ode45() and similar functions always internally have a "current" point -- a current time and current set of boundary conditions. At each step, the ode*() functions have a current step size, h. The ode*() evaluate the ode function at several different carefully chosen locations near the current point, with the locations determined by the stepsize relative to the current point. For example they might evaluate at (t*(1+h), boundary*(1+h/5)), (t*(1+2*h), boundary*(1-h/7)) and others. These are not points that are intended to become current points: these are more like a blind person swinging their cane in a careful pattern to figure out the general shape of the land. Using the results of evaluating at several points, ode*() makes a prediction about yet another point, and then it tests whether the prediction is "close enough" to the actual value. If it is close enough to the actual then ode*() "accepts" the point of prediction as the new point, and increases the step-size; if the prediction is not "close enough" then ode*() "rejects" the point and reduces the step size and tries again from where it was. In steep areas it might end up shrinking the stepsize a number of times in a row -- and at each attempt ode45() is evaluating the ode function at 6 different locations.
ode*() records the values at each "accepted" point. But by default, unless the user knew to set the Refine option to 1 (which I had never even heard of until recently), ode*() also takes the ode point and the newly accepted point, and generates several intermediate points that it records in the output, without ever having evaluated the function at those locations. So there are usually output points recorded for which ode*() never evaluated the ode function (so there could not be a record of the values of the intermediate variables at those locations)... and the complete record of values of intermediate variables would include evaluations at lots of locations where ode*() never intended the point to be accepted.
A record of the intermediate variables would therefore typically be incomplete (the function never having been evaluated for 3/4 of the output locations by default), and the record of intermediate variables would typically have a lot of junk, places never intended to be permanent.
Yes, you might potentially want a complete record of the intermdiate variables if you intended to do a surface plot of the shape of the surface. But mostly the complete record would be too useless for practical work.
For these reasons, what the great majority of people should do is not try to record the intermediate variables during ode*() evaluation, and instead should afterwards take each of the output t and y rows and calculate the intermediate variables related to those positions.
Walter Roberson
Walter Roberson on 7 Oct 2022
In that case you probably have a singularity.
In some cases, singularities are unavoidable. For example if you were calculating force of gravity between two objects in which the center of gravity is right at the surface, and one is falling towards the other, then unless something else acts to disturb the system, G*m1*m2/r^2 is going to eventually encounter r = 0 and you might not be able to recover from the infinity. In such cases, it is inherent in the system that with those equations a singularity will occur... unless, that is, due to round-off error the system steps over the singularity without noticing it, and so generates what is effectively the wrong answer...
In other cases, singularities are path dependent. A ball might roll very close to a hole without quite falling in, but the numeric approximation of the system might lead it to fall in while a higher resolution approximation might have it miss the hole. In some cases, reducing the tolerance to accept points can force it to be more accurate (but taking longer to compute). In other cases, there just might not be any practical double precision solution -- the band of velocities to miss the hole might be +/- 1 part in 10^20 of a particular value for example, and you cannot drive a double precision simulation that precisely. (Running an ode using the symbolic toolbox might help in such cases.)

Sign in to comment.


Find more on Programming in Help Center and File Exchange




Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!