I have a model which takes the root of the input in an matlab function block. The input should always positive; however, sometimes simulink gives a negative number. The reason is that i use an implicit solver (ode15s due to other part of the system being stiff) and simulink have a invalid estimate. My question is: how can I tell simulink that the input is invalid which makes the solver take a smaller step (without stopping)? Can I return a special value (e.g., NaN) or throw an error (without stopping the simulation)?
You can return 0 in your MATLAB Function block if the input is negative:
if u<=0
y = 0;
else
y = sqrt(u);
end
where u is the input and y the output of the function.
Use the Hit Crossing Block to force the solver to take small time steps as your signal approaches zero. This will work assuming your model is correctly set up to force the signal to go no lower than zero (i.e. it works something like an Abs block, which will hit zero and then continue with a positive value).
My solution was to add another output, isInputValid. This is 0 if the input is invalid and 1 if the input is valid. This output is then integrated by a new integration block. It seems like the discontinuity produced by the boolean variable makes sure that the integrator takes smaller steps.
Example:
if ( u<0)
y = -realmax;
isInputValid = 0;
else
y = sqrt(u);
isInputValid = 1;
end
Then attach an integrator to the output of isInputValid.
Related
I'm doing a project in school and I need to evaluate the roots of a 7th order polynomial during a Simulink simulation. For that, I've decided to use the "roots" function but it seems that Simulink doesn't like this function - when running the simulation this error appears:
"Data radius_new is inferred as a variable size matrix, while its properties in the Model Explorer specify its size as inherited or fixed. Please check the 'Variable Size' check box and specify the upper bounds in the size field."
The code I have inside my function block is the following:
p = [A*10.^5 B_3*10.^5 B*10.^5 0 E 0 C*10.^5 0 D*10.^5];
R = roots(p);
radius_new = R(real(R)>=0 & imag(R) == 0);
where A, B...are defined constants changing with time.
I have run this on a normal script and it gives the value I need. For some reason, on Simulink, that does not happen.
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)
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))
I need a Simulink block or a group of blocks to make peak detection: compare each value of an input stream to its previous and post values. If it's larger than the previous AND larger than the next value, output this value.
I've tried to do it with a Matlab Function Block, but I cannot make the required delay. I mean it's not possible, as far as I tried, to store previous values for example.
So, what should I do?
Update: Another example
In responding to the comments, suggested solutions are helpful if I'm dealing with discrete values. So here is another example to represent my need:
A Schmidt Trigger
I need to implement a Matlab function to implement the given scenario. I can do something like
if u >= 2
y = 3;
elseif (u < 2)
y = -3;
But still this is not correct as I need to look at the previous value (hysteresis) of the input, other wise I'll end up having something like the following
PS: I know there is nothing called previous value in analog, but we all know that Simulink is dealing with analog values as a discrete in the end (much larger sampling). So I think maybe there is a way to do it.
I think your code is fine except for one minor mistake:
if u > 2
y = 3;
elseif u < -2
y = -3;
else
y = u;
The variable 'u' in elseif part should get compared with the -2 (upper threshold but with a negative sign)
Hope it helps!
I am trying to find use to Newton-Raphson method to find the roots. It does this by making a guess and then improving the guess after each iteration until you get one of the zeros.
Because the Newton-Raphson method quickly finds the zeros, it gives me a small error immediately and after two or three iterations max it should fail to meet the conditions of the while loop. However, the problem is that when I remove the semi-colon after "error" in my loop, I start getting fractions that should break the while loop, but its like Matlab doesn't know that 123/8328423 is less than 1. It continues to run until I manually force the program to stop running.
How do I fix this? I tried format long, format longe, and using double both in the command window, in the scrip file, and somewhere in the loop.
Thank you in advance for any tips, suggestions, or advice that may help!!
A = [1,2,-4;2,-2,-2;-4,-2,1;];
format longe
% syms x y z
% P = x^4 + 3*x^2*y^2-z^3+y+1;
% feval(symengine,'degree',P,x)
syms x
B = mateigenvalue(A);
f(x) = simplify(matdet(B));
x0 = 1;
error = 10;
while(error > .01)
x1 = x0 - f(x0)/(27*(x0)-3*(x0)^2);
error = abs(((f(x0)-f(x1))/f(x0))*100)
x0 = x1;
end
x0 = double(x0)
I reckon the main problem is with error.
It starts as double but inside the while-loop it turns into a symbolic variable and you can't easily compare symbolic variables with scalar values (the .01 in the while-loop condition).
Check in your workspace if error is symbolic (or type class(error) and check if sym is returned). I guess it is symbolic because a fraction is returned (123/8328423), as instead Matlab treats double values with decimals, not fractions.
If so, try doing (inside the while-loop) a conversion for error that is, under the line
error = abs(((f(x0)-f(x1))/f(x0))*100);
try putting
error=double(error);
So error will be temporarily converted in double and you can easily compare its value with .01 to check the while-loop condition.
Also, it is bad practice to call a variable error since error() is a built-in function in Matlab. By naming a variable error you cannot use the error() function. Same story goes for other built-in functions.