ODE OutputFcn returning fewer points than expected
4 views (last 30 days)
Show older comments
Hi,
I'm using OutputFcn to return exta information from ode45 and whilst the returned signal looks as I expected it to it's only comprised of 93 points rather than 1001.
tvec is my tspan vector and contains 1001 points for a run of 0 to 5 seconds at 200 Hz.
The ODE setup is:
% Set up ODE function to pass to solver
odeFcn = @(t, x) Three_DOF_Half_Car_ODE(t, x, ix, iz, ip, tvec, mb, Iby, lf, lr, h, ...
kfz, cfz, kfx, cfx, adf, adf_dbz, krz, crz, krx, crx, adr, adr_dbz, Fxr_max);
% Set up options for output function
options = odeset('OutputFcn',@(t, x, flag) myOutputFcn(t, x, flag, ix, tvec, lr, ...
krx, crx, adr, adr_dbz, Fxr_max));
% Run solver
[T,x] = ode45(odeFcn, tvec, x0, options);
The intention is that Fxr is calculated during integration and its value capped under certain conditions (I'm aware this is an abuse of the ODE solver). I want Fxr out so I repeat the same equations in the output function, which contains:
function status = myOutputFcn(t, x, flag, ix, tvec, lr, krx, crx, adr, adr_dbz, Fxr_max)
persistent Fxr_out
ix = interp1(tvec, ix, t); % interpolates ix at t within tvec
switch flag
case 'init'
tanadr = tan(deg2rad(adr_dbz.*(x(1)+lr.*x(3))+adr)); % anti-dive tangent wrt body displacement
xir = (x(1)+lr.*x(3)).*tanadr; % contact patch longitudinal displacement...
xdotir = (x(4)+lr.*x(6)).*tanadr; % ..and velocity
Fxr = krx.*(-xir-x(2))+crx.*(-xdotir-x(5)); % rear axle longitudinal force
if ix ~= 0 % if longitudinal acceleration is negative...
if Fxr < Fxr_max % if Fxr exceeds limit...
Fxr = Fxr_max; % cap Fxr to Fxr_max
end
end
Fxr_out = Fxr;
case ''
tanadr = tan(deg2rad(adr_dbz.*(x(1)+lr.*x(3))+adr)); % anti-dive tangent wrt body displacement
xir = (x(1)+lr.*x(3)).*tanadr; % contact patch longitudinal displacement...
xdotir = (x(4)+lr.*x(6)).*tanadr; % ..and velocity
Fxr = krx.*(-xir-x(2))+crx.*(-xdotir-x(5)); % rear axle longitudinal force
if ix ~= 0 % if longitudinal acceleration is negative...
if Fxr < Fxr_max % if Fxr exceeds limit...
Fxr = Fxr_max; % cap Fxr to Fxr_max
end
end
Fxr_out = [Fxr_out, Fxr];
case 'done' % when it's done
assignin('base','Fxr',Fxr_out); % get the data to the workspace.
end
status = 0;
As i say, the resulting data in Fxr is correct. However, it only contains a fraction of the expected number of points. Why is this?
Regards,
Simon.
0 Comments
Answers (1)
Jan
on 26 Jan 2021
Edited: Jan
on 26 Jan 2021
The code looks okay. Check again if tspan has really 1001 time points.
Use the debugger to check, what's going on. Set a breakpoint in the output function and see, when it is triggered.
I'd stay away from using assignin to create a variable in the base workspace. What about:
function status = myOutputFcn(t, x, flag, ix, tvec, lr, krx, crx, adr, adr_dbz, Fxr_max)
persistent Fxr_out
...
status = 0;
switch flag
case 'init'
...
case ''
...
case 'done'
% Nothing
case 'flush'
status = Fxr_out;
Fxr_out = [];
end
end
Then calling this function after the integration to flush the internal persistent buffer is save, because the data are actively requested. Poking it by assignin into the base workspace is susceptible as all global access to variables: If there is another forgotton assignin anywhere in your code, the confusion is perfect.
Note: tand() is nicer than tand(deg2rad()).
4 Comments
See Also
Categories
Find more on Dialog Boxes 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!