if statement block in Simulink accumulates last true value - simulink

If statement in Simulink is not like in a programming language, it accumulates last true value untill it occurs again.
As it can be seen here, when random value is lower than 0.5 (if condition) output dosn't give zero as one normally expects from if statement.
What is the proper way to use an if? (Where preferably I don't want to put saturation and matlab function)

The Out block within the If Action subsystem has a property to either hold or reset its output when disabled. The default is to hold; you want it to reset. You'll also need to specify 0 as the initial condition, which is what it'll reset to.

So far what I could do this to use an elementary matlab function;
function y = fcn(u)
if u>0
y = u;
else
y = 0;
end
end
but I wondered it would be a proper way of using if block.

Change out blocks property in If action subsystem to 'reset', it looks like it is 'held' in your current implementation

Related

MATLAB how to write a for loop with 2 conditions, one is "==", the other is "~="?

I am trying to write an S-Function in Simulink, with the inputs "t" for time, and "LIBs" for the amount of material entering the system. There are 2 outputs. The idea is like this in Simulink.
Simulink model concept
What I want to do is that, at a certain time iteration, the input "LIBs" goes to a different output. But during the iteration, there are some special points at which I don't want the input to go to any output.
The code is like this:
MATLAB
function [Batts_Spent, Batts_N_Spent] = BattsL6Y(t, LIBs)
for t = 2011:6:2035
if t ~= 2005:10:2035
Batts_Spent = LIBs;
end
end
for t = 2015:10:2035
if t ~= 2005:6:2035
Batts_N_Spent = LIBs;
end
end
for t = 2011:6:2035
if t == 2015:10:2035
Batts_Spent = LIBs;
end
end
end
I am sure that this code is not correct, but I don't know how to write it correctly.
And also, even if I have several input and output ports, the S-Function block in the Simulink project still remains only one input and output port. Should I change it to a MATLAB Function block?
In your case t is an input parameter, which makes it look like the function is called for each value of t. Then you have a loop iterating over all values of t. Considering your image, you don't need a loop at all. You can use if in combination with mod. For example:
function [Batts_Spent, Batts_N_Spent] = BattsL6Y(t, LIBs)
if mod(t-2005,6)==0 && t>=2005
Batts_Spent = LIBs;
end
end
This is only "Every 6th time the value of LIBs will be assigned to the first output". This isn't a finished solution but should be sufficient to get you started. You need a second if like this for the other output.

Updating value in Simulink

I am currently working on a spacecraft body with actuator, and given the equation below:
J·w_dot = -w^x·J·w + u (1)
where w^x is actually a notation of 3x3 matrix
[ 0 -w3 w2
w3 0 -w1
-w2 w1 0]
By rearranging (1), I got w_dot = (-w^x·J·w + u)/J. And here I face the problem, I need to update value constantly for w_dot but I have no idea how. I have tried the Memory block but it only update every 0.2 seconds which is not appropriate for the system.
This is my current setting:
I was thinking the integrator block could be the one to be updated every single cycle as initial condition could be set.
Yes, your solution seems about right; the integrator block will cause the system to be continuous-time, rather than discrete-time. This will output results as accurately as Simulink can accomplish.
You can set initial values for the integrator by double-clicking on the integrator block, setting the "Initial condition source" to "external", then connecting another input or constant block, output, or whatever else you want providing the initial value.
By the way, is J is the inertia tensor? In that case, you can't simply "divide" by it; you should multiply by its inverse (setting "Matrix" as the "Multiplication" option in the Divide block's options)

Matlab function in Simulink - retain previous non-zero input value

I have a Matlab function block in Simulink that receives 2 inputs and processes it to generate an output. During the course of the simulation, at some time points, one of the inputs is zero. I'd like to use the most recent non-zero input to the function whenever that particular input value is zero. How can I achieve this? I tried creating a persisent variable that updates to most recent non-zero input value but that doesn't seem to work.
EDIT 1 (to include code):
function y = fcn(u)
persistent ref_val
if isEmpty(ref_val)
ref_val=10.0
end
if(u(1)<=25)
y=20.0
else
if(u(2)>0)
y=u(2)
ref_val=u(2)
else
y=ref_val
end
end
EDIT 2: For now, I fixed the issue by writing a C code that uses a static variable to retain the most recent non-zero input value. But I still welcome suggestions/solutions to realize this directly in a Matlab function.
Can't you use something like this in your simulation?
//Find the index of the last non-zero value in the input
[~,last_non_zero] = max(find(input(1:i) > 0))
//Call the function using this input
output = fnc(input(last_non_zero))

Change a constant in ODE calculations under particular conditions with a flag

I have an ODE for calculating how acidicity changes. Everything is working just fine, only I would like to change a constant whenever acidicity reaches a critical point. It is supposed to be some kind of irreversible effect I wish to simulate.
My constants are coming from a structure file (c) I load once in the ODE function.
[Time,Results] = ode15s(#(x, c) f1(x, c),[0 c.length],x0,options);
The main problem I have here is not telling Matlab to change the constant but remember if it happened already during the simulation once. so Matlab should take the irreversibly changed constant rather than the one I supply at the beginning.
I would like to write a flag that is saved while the ODE is running and an if condition, "if flag exists, change constant". How to do that?
UPDATE I:
PROBLEM SOLVED
Here a first own solution, it is not polished and requires a structure file approach. Which means, the constants which should suddenly changed upon an event, must be struct files which are handed in the ODE function into the function that should be evaluated (look above for the ODE syntax). The function accepts the inputs like this:
function [OUTPUT] = f1(t, x, c)
% So here, the constants all start with c. followed by the variable name. (because they are structs instead of globals)
%% write a flag when that event happens
if c.someODEevent <= 999 && exist ('flag.txt') == 0
dlmwrite ('flag.txt',1);
end
%% next iteration will either write the flag again or not. more importantly, if it exists, the constant will change because of this.
if exist ('flag.txt') == 2
c.changingconstant = c.changingconstant/2;
end
end
Please look into Horchlers kind answer where you have to take care that such a step may introduce inaccuracies and you have to be careful to check if your code does what it is supposed to do.
To do this accurately, you should use event detection within the ODE solver. I can't give you a specific answer because you've only provided the ode15s call it in your question, but you'll need to write an events function and then specify it via odeset. Something like this:
function acidity_main
% load c data
...
x0 = ...
options = odeset('Events',#events); % add any other options too
% integrate until critical value and stop
[Time1,Results1] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
x0 = Results(end,:); % set new initial conditions
% pass new parameters -it's not clear how you're passing parameters
% if desired, change options to turn off events for faster integration
[Time2,Results2] = ode15s(#(x,c)f1(x,c),[0 c.length],x0,options);
% append outputs, last of 1 is same as first of 2
Time = [Time1;Time2(2:end)];
Results = [Results1;Results2(2:end,:)];
...
function y=f1(x,c)
% your integration function
...
function [value,isterminal,direction] = events(x,c)
value = ... % crossing condition, evaluates to zero at event condition
isterminal = 1; % stop integration when event detected
direction = ... % see documentation
You'll want to use the events to integrate right to the point where the "acidicity reaches a critical point" and stop the integration. Then call ode15s again with the new value and continue the integration. This may seem crude, but it how this sort of thing can be done accurately.
You can see an example of basic event detection here. Type ballode in your command window to see the code for this. You can see a slightly more complex version of this demo in my answer here. Here's an example of using events to accurately change an ODE at specified times (rather than your case of specified state values).
Note: I find it strange that you're passing what you call "constants", c, as the second argument to ode15s. This function has strict input argument requirements: the first is the independent variable (often time), and the second is the array of state variables (same as your initial condition vector). Also if f1 only takes two arguments, #(x,c)f1(x,c) is superfluous – it's sufficient to pass in #f1.

Getting into an infinite loop in MATLAB function

I'm trying to plot a function on matlab that's defined such that:
Y=-100t ; 0>=t>=0.15
Y=-15 ; t>.15
I'm using the following code:
function [ Y ] = Gain( t )
for t=[0:0.01:0.15]
Y=-100*t
end
for t=0.15:0.01:2
Y=-15
end
plot (Gain)
but I'm going into an infinite loop!
Would someone please solve this problem for me.
Thank you.
Functions don't work like that in MATLAB, unfortunately. (Or at least I don't think they do). Try something like this:
function Y = Gain(t)
Y = -100*t;
Y(t >= 0.15) = -15;
end
x = 0:0.01:2;
plot(x, Gain(x))
MATLAB still uses C-esque functions, so you have to define it that way, using C-style syntax, instead of more math-like syntax, unfortunately. I'm multiplying the input values by -100, then for the ones that match up to where t is greater than 15, I replace those with -15. MATLAB is weird.
Edit: Sorry, previous code sample also used the wrong syntax.. MATLAB is weird.
I'm not certain what you're TRYING to do, but when you call the Gain function "from outside", so to speak,...
You enter the Gain function
The first for loop executes, overwriting passed-in value of t with each iteration. (Therefore, the value of t that you passed in is completely ignored, the way that you have this code written.)
The second for-loop executes, and
You call plot(Gain), which forces Gain to be called again, this time with no arguments. Back to 1.
Repeat forever.