I am trying to migrate an existing Simulink simulation to pure Matlab, which is necessary for several reasons. It is a stiff system of 10 – 50 ordinary, first-order, non-linear differential equations and a couple of algebraic equations, formulated as a level-2 C-Code S-function.
A simplified version of the corresponding Simulink flowsheet (strangely enough, I cannot upload slx files here):
Which produces the following plot:
Consider this MWE for illustration purposes (Matlab version of the Simulink sheet):
% simpleStorageTankModel_Matlab Test of Matlab Solver for Simulink problem
contOutlet = @(t) 0.03*t.^2 - 0.05*t + 0.01;t1 = 0:1e-2:12;stairs(t1, periodicDiscreteInlet(t1), 'b'); hold on% Formulate ODE
solverOptions = odeset('MaxStep', 1e-2);tic; fillingLevel = ode15s(@(t,y) periodicDiscreteInlet(t) - contOutlet(t),... t1, 0.5, solverOptions); tocplot(t1, 0.03*t1.^2 - 0.05*t1 + 0.01, 'k');plot(fillingLevel.x, fillingLevel.y, 'r');legend({'Inlet', 'Outlet', 'Filling level'}, 'Location', 'NorthWest');function perDisInp = periodicDiscreteInlet(t) amplitude = 4; phaseDelay = 0; pulseWidth = 0.5; t_cyc = t - floor(t); if numel(t) > 1 numberOfTimePoints = length(t_cyc); perDisInp = zeros(numberOfTimePoints, 1); for timeIndex = 1:numberOfTimePoints if (t_cyc(timeIndex) >= phaseDelay) && (t_cyc(timeIndex) <... 1 - pulseWidth + phaseDelay) perDisInp(timeIndex) = amplitude; end end else if (t_cyc >= phaseDelay) && (t_cyc < 1 - pulseWidth + phaseDelay) perDisInp = amplitude; else perDisInp = 0; end endend
An annoying problem is that, if do not set the MaxStep option to something below, say, 1e-2, then the solution beyond t > 6 becomes inaccurate, as if the solver is missing some of the square waves. This seems to have occured to others before .
However, my main problem is with ode15s ignoring the time vector argument I am providing, probably due to the right-hand side of the ODE ( periodicDiscreteInlet) being discrete, i.e., not continuously differentiable (in my simulation, the input is actually a non-periodic square wave). Thus, although t1 is a 1×1201 double vector, I get a 1×1224 double solution. I know I could write a function to extract the values I need, but this would add a significant performance penalty. In my case, Simulink takes just about a tenth of the simulation time of pure Matlab!
Is there a built-in function to "round off" the square-wave edges, making the input continuous (I don't mean as round as via Fourier transform)? Or a stiff Matlab solver that can handle discrete right-hand sides? Why can Simulink handle this problem with such ease, but Matlab can't? Any help is appreciated.
Best Answer