What is the meaning of "Algebraic loop involving integers or booleans" in the error message - modelica

I'm making the PI controller using the Dymola Platform and i met the error message like below
And here's some of my code that consist of valve which calculate the disp and PI controller which control the amount of the disp.
They are communicating each other using the flag
//PI controller///
if flag_input==1 then //flag_input==1 : Stop control / flag_input==0 : Restart control//
control:=0;
else
control:=(P_term+I_term)/unit;
end if;
if error<0 then // error<0 : flag to Valve to restart calculating the disp//
flag_output:=1;
else
flag_output:=0;
end if;
//Valve//
if (26/5)*(thetta/(2*pi))*0.001>0.026 and flag_input==0 then
//restart calculating the disp when received flag==1 from the PI controller//
disp:=0.026;
flag:=1;
elseif (26/5)*(thetta/(2*pi))*0.001<0 and flag_input==0 then
disp:=0;
flag:=1;
else
disp:=(26/5)*(thetta/(2*pi))*0.001;
flag:=0;
end if;
Can someone tell me what is the meaning of algebraic loop error and figure out the problem?

From your code snippet it's hard to tell where exactly the problem is.
Dymola tells you that you created a large algebraic loop over all the variables listed at the top under Unknowns and the equations listed below in the section Equations.
This can happen easily when you create if statements with variables which depend on each other. Often you just have to use pre() at the right place to break the loop.
Let`s use another small example to explain the problem.
For some reason we try to count the full milliseconds, which have passed in the current simulation and stop, once we reach 100.
model count_ms
Integer y(start=0);
equation
if y >= 100 then
y = 100;
else
y = integer(1000*time);
end if;
end count_ms;
This code will produce a similar error as yours:
An algebraic loop involving Integers or Booleans has been detected.
Unknowns: y
Equations: y = (if y >= 100 then 100 else integer(1000*time));
From the error message we see that y can not be solved, due to the equation resulting from the if statement. The equation is not solvable, as y depends on itself. To solve such problems pre was introduced, which gives you access to the value of a variable had when the event was triggered.
To fix the code above, we simply have to use pre when we check for y
if pre(y) >= 100 then
and the model simulates as expected.

Related

Unexpected length of array and plotting error as a result

I wanted to plot the load voltage across the resistor in series with a diode using matlab. This is a rather simple example involving piecewise functions, however I ran into an unexpected error.
t=[0:0.001:10]
vs=4*sin(pi * t)
for i =1:length(vs)
if(vs(i)<=0.7)
v(i)=0;
else
v(i)=vs(i)-0.7;
end
end
plot(t,v)
t is the time, vs is the source voltage, and v is the load voltage. Now, running this gave me an error saying "error, t and v are of different sizes..". Using length() I found out that while t and vs are of lengths 10001, v is somehow of length 1000001.
This is truly baffling to me. How can v and vs possibly differ in size? every element of vs was mapped to an element of v, and yet the size of v comes out to be about 100 times the size of vs.
Being new to matlab, I still am not very comfortable with not explicitly declaring the array v before using it in the for loop. However, I went through with it, because the example I worked on prior to this, used the same thing and it worked without any problems. We simply had a plot a piecewise function:
x=[-2 : 0.00001 : 20];
for i=1: length(x)
if(x(i)>=-2 && x(i)<0)
y(i)=sqrt(x(i)^2+1);
else if(x(i)>=0 && x(i)<10)
y(i)=3*x(i)+1;
else
y(i)=9*sin(5*x(i)-50);
end
end
end
plot(x,y)
This code worked flawlessly, and in my opinion the initial code is fundamentally doing the same thing, so again, I'm clueless as to why it failed.
The original code works if you initialise v to be of the same size as t (and therefore, vs), but still, I want to know why the code involving x,y worked (where y wasn't initialised) and the code involving (t,v) failed.
Also, my friend copy pasted the entire code into the command window of matlab 2016, and it worked. (and I'm using the 2021 version).
Its good practice to initialize variables before entering a loop. It will help avoid undefinied behaviour when you run the script multiple times. If you run the script with different lengths for t, it would fail the second run. One solution would be:
t=0:0.001:10;
vs=4*sin(pi * t);
v=nan(size(t));
for i =1:length(vs)
if(vs(i)<=0.7)
v(i)=0;
else
v(i)=vs(i)-0.7;
end
end
figure;
plot(t,v);
You could also avoid the for loop and use matrix operations instead:
t=0:0.001:10;
vs=4*sin(pi * t);
v=vs-0.7;
v(vs<=0.7)=0;
figure;
plot(t,v);

Post and previous values for an analog input inside a matlab function block in Simulink

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!

Too many input arguments error

I am trying to run my function. it shows
[root, ni]=value1(xu,xl,acceptable)
Error using value1
Too many input arguments.
function[root, ni]=value1(xu,xl,acceptable)
fu=HW10B(xu);
fl=HW10B(xl);
Err=1;
N=0;
if fu*fl>=0
end
while Err>=acceptable;
m=(xu+xl)/2;
fm=HW10B(m)
if fm*fu<0;
fl=m;
else fu=m;
Err=abs(xu-xl)/xu*100;
end
N=N+1;
end
function [ y] = HW10B( x)
%equation of x
y=3*x^3-8*x^2-4*x+9;
end
root=m;
ni=N;
end
function[m, N]=value1(xu,xl,acceptable)
y=#(x)3*x.^3-8.*x.^2-4.*x+9;%//Used anonymous function instead of private
fu=y(xu);%//Used above definition
fl=y(xl);
Err=1;%//Initialise error
N=0;%//Initialise counter
while Err>=acceptable && N<1e4;%//check for convergence
m=(fu+fl)/2;%//Get new midpoint
fm=y(m);%//Get value at midpoint
if fm*fu<0;%//Get left or right value to move
fl=m;
else
fu=m;
Err=abs(fu-fl)/fu*100;%//Calculate the error
end
N=N+1;%//Update iteration counter
end
end
Call it from the command line:
xu=15;xl=2;acceptable=1e-3;
[root, ni]=value1(xu,xl,acceptable)
root =
2.7554
ni =
29
As you can see I cleaned up your code quite a bit. Using the two separate storage variables at the end of the code was just taking up more space than necessary. The if statement fu*fl>0 did not do anything, thus I chucked it out. Finally, you needed to update your values in your functions, thus using the fl, fx and fm, not the xu and xl.
If you call the function exactly as I showed you from the command line (with your own values of course), it should not throw any errors.
What happens in your original code is that you calculate everything once for the input variables, get an error which is larger than acceptable and therefore executes again, taking the same input arguments, returning the same error as before, which is still larger than acceptable. This is what we call an infinite loop. I suggest you check for it using a maximum number of iterations, i.e.
while Err>=acceptable && N<1e4
and change the 1e4 to whatever maximum number of iterations you want to have. If you accidentally end up going infinite, this counter will kill it without having to resort to crtl-c or equivalents.

How to mimic MATLAB/Simulink relay behavior?

I am trying to mimic the behavior of MATLAB's Simulink relay block with just MATLAB code.
My code is as follows (not familiar with persistent variable? click) :
function out = fcn(u,delta)
persistent y;
if isempty(y)
y = 0;
end
if u >= delta
y = 1;
elseif u <= -delta
y = 0;
end
out = y;
When I look to the output and compare with the real relay block I see :
Where does the difference come from?
Both blocks insert the same sample time, does the relay block have something extra to show the discontinuity?
Simulink block diagram download
I'm not quite sure about this explanation, maybe somebody can support it.
The MATLAB function Block does not support Zero-Crossing Detection, the Relay Block does. That means the latter knows in advance, when your sine will reach the threshold delta and sets the output accordingly to the correct time. The MATLAB function Block needs 2 or more steps to detect the slope (respectively the crossing of the threshold). So from one step to another it realizes that the condition for the new output was set and updates the output and you get a ramp, not a step.
C/C++ S-Functions do have Zero-Crossing Detection - though it seems quite complicated.

Confused by when clauses in algorithm section

model try
Real x(start = 1);
algorithm
when x >= 7 then
reinit(x, 5);
end when;
equation
der(x) = 1 ;
end try;
The when statement should be triggered whenever the guard condition is changed from false to true.
But it is not the case in OpenModelica. The example try in OpenModelica showes that when is triggered only once. I was wondering whether it is the bug of OpenModelica or some misunderstanding from my side.
You are correct. I am pretty sure this would be a bug in OpenModelica. The model works as you would expect in Dymola 2013.
My guess is that it is related to the fact that your when condition involves x and the statements inside end up changing x (the same variable). It may be that it somehow fails to notice the reinit in the monitor function used to determine the point at which the when clause should trigger.