How to implement nested if statements in Modelica? - modelica

I am trying to implement a fault inclusive model of an HVAC system. The fault starts at a user defined time, in this case faultTime = 1000. However, the first part of the if statement is not implemented at all. The following is a snippet of code that is relevant to the question
fcuModel FCU;
Modelica.Blocks.Continuous.LimPID PI(k = 300, Ti = 1, yMax = 1, yMin = 1e-4);
parameter Real faultTime = 1000;
// fault modes: 0-normal, 1-fan failed, 2-valve stuck shut...
parameter Integer faultMode = 1;
equation
connect(PI.u_m,FCU.Ts_zon); // connects zone temperature to PID measurement
PI.u_s = 21; // set-point for zone temperature
if time<faultTime then
PI.y = FCU.val;
PI.y = FCU.fs;
else
if faultMode == 0 then
PI.y = FCU.val;
PI.y = FCU.fs;
elseif faultMode == 1 then
PI.y = FCU.val;
FCU.fs = 1e-4;
end if;
end if;
When I simulate, it runs without error but the it directly goes to the equations under faultMode == 1, without simulating the fault-free state for the first 1000 seconds.

I modified your model to make it work directly by introducing some variables and changing some parameters. Which resulted to be:
model FCU
Modelica.Blocks.Continuous.LimPID PI(k = 0.1, Ti = 1, yMax = 1, yMin = 1e-4);
parameter Real faultTime = 1000;
parameter Integer faultMode = 1;
Real val;
Real fs;
equation
PI.u_s = 21; // set-point for zone temperature
PI.u_m = 20.9999; // no feedback as no system available
if time<faultTime then
PI.y = val;
PI.y = fs;
else
if faultMode == 0 then
PI.y = val;
PI.y = fs;
elseif faultMode == 1 then
PI.y = val;
fs = 1e-4;
else
assert(false,"Unknown faultMode");
end if;
end if;
annotation (experiment(StopTime=2000), uses(Modelica(version="3.2.2")));
end FCU;
The result below (simulated in Dymola) seem to be what I would expect.
Hope this helps...

Related

MATLAB Neural Network - Forward Propagation

I am creating a Forward Propagation In the feedforward step, an input pattern is propagated through the network to obtain an output. I have written this in pseudo code and currently attempting to implement this within MATLAB.
There are two errors I currently receive.
Patterns = x'; Desired = y; NHIDDENS = 1; prnout=Desired;
% Patterns become x so number of inputs becomes size of patterns
[NINPUTS,NPATS] = size(Patterns); [NOUTPUTS,NP] = size(Desired);
%apply the backprop here...
LearnRate = 0.15; Momentum = 0; DerivIncr = 0; deltaW1 = 0; deltaW2 = 0;
% Keeps the tan ordering of the examples of x
Inputs1= [Patterns;ones(1,NPATS)]; %Inputs1 = [ones(1,NPATS); Patterns];
% Weight initialisation
Weights1 = 0.5*(rand(NHIDDENS,1+NINPUTS)-0.5);
Weights2 = 0.5*(rand(1,1+NHIDDENS)-0.5);
TSS_Limit = 0.02;
for epoch = 1:10
% FORWARD LOOP
size(NOUTPUTS)
size(NPATS)
for ii = 0: ii < length(NINPUTS)
NOUTPUTS(ii+1) = NPATS(ii);
% Sets bias to 1
NOUTPUTS(1) = 1;
end
for ii = NHIDDENS: ii < NINPUTS
sum = 0;
for ij = 0: ij < ii
sum = sum + deltaW1(ii,ij) * NOUTPUTS(ij);
NOUTPUTS(ii) = tanh(sum);
end
end
Unable to perform assignment because the
left and right sides have a different
number of elements.
Error in mlpts (line 66)
NOUTPUTS(i+1) = NPATS(i);
i am still new to MATLAB and trying to become use to it.
After iterating through the loop
NOUTPUTS = 0 and the error is displayed. I am confused as I am trying to increment NOUTPUTS with ii by 1 through each loop.
I have been able to create the forward propagation with a loop.
for i =3:NNODES
summ = 0;
for j=1:i-1
summ = summ + weights(i,j) * Node_outputs(j);
end
if i == NNODES
Node_outputs(i) = summ
else
Node_outputs(i) = sigmoid(summ);
end
end
Out = Node_outputs(NNODES);
% BOut = ((Node_outputs(NNODES)) * (1 - Node_outputs));
BOut=zeros(1,6);
DeltaWeight = zeros(6,6);

Initialization error when compiling code with three equation containing array

I am trying to prepare a modelica code to understand array and for loop.
When I am compiling the code, I get following error.
The initialization problem is inconsistent due to the following equation: 0 != 1 = 1.0 - I[0]
Error in initialization. Storing results and exiting.
Use -lv=LOG_INIT -w for more information.
Simulation process failed. Exited with code -1.
I have tried to adjust array numbers to see if this solves. Could not trace the reason why the code is failing.
class flu
parameter Real beta = 10.0/(40*8*24);
parameter Real gamma= 3.0/(15*24);
parameter Real dt = 0.1;
parameter Real D = 30;
parameter Integer N_t = integer(D*24/dt);
parameter Integer array = integer(N_t*dt);
//parameter Real time[array];
Real S[array] ;
Real I[array] ;
Real R[array] ;
initial equation
S[0] = 50;
I[0] = 1;
R[0] = 0;
equation
for n in 0:(array-1) loop
S[n+1] = S[n] - dt*beta*S[n]*I[n];
I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n];
R[n+1] = R[n] + dt*gamma*I[n];
end for;
annotation(
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl"));end flu;
I am expecting to get three curves as a result .
There seems to be a few things wrong here. First of all, it seems OpenModelica does not output the index of the equation so the debugger can be opened.
But more importantly, you are setting
I[0] = 1
I[1] is the first index in Modelica... I don't know why this wouldn't give any warning in OpenModelica. Probably some edge case in an if equation that never triggers and thus no warning/error in this case.
class flu
parameter Real beta = 10.0/(40*8*24);
parameter Real gamma= 3.0/(15*24);
parameter Real dt = 0.1;
parameter Real D = 30;
parameter Integer N_t = integer(D*24/dt);
parameter Integer array = integer(N_t*dt);
//parameter Real time[array];
Real S[array] ;
Real I[array] ;
Real R[array] ;
equation
S[1] = 50;
I[1] = 1;
R[1] = 0;
equation
for n in 1:(array-1) loop
S[n+1] = S[n] - dt*beta*S[n]*I[n];
I[n+1] = I[n] + dt*beta*S[n]*I[n] - dt*gamma*I[n];
R[n+1] = R[n] + dt*gamma*I[n];
end for;
end flu;
class flu
parameter Real beta = 10.0/(40*8*24);
parameter Real gamma= 3.0/(15*24);
Real S(start = 50) ;
Real I(start = 1) ;
Real R(start = 0) ;
equation
der(S)= -beta*S*I;
der(I)=(beta*S*I) - (gamma*I);
der(R)=gamma*I;
annotation(
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl"));end flu;

Differential part of PID and its low pass filter- time domain

I programmed PID in MATLAB:
classdef PID < handle
properties
Kp = 0
Ki = 0
Kd = 0
SetPoint = 1
Dt = 0.01
end
properties (Access = private)
IState = 0
PreErr = 0
end
methods
function obj = PID(Kp, Ki, Kd, SetPoint, Dt)
if nargin == 0
return;
end
obj.Kp = Kp;
obj.Ki = Ki;
obj.Kd = Kd;
obj.SetPoint = SetPoint;
obj.Dt = Dt;
end
function output = update(obj, measuredValue, t)
err = obj.SetPoint - measuredValue;
P = obj.getP(err);
I = obj.getI(err);
val = lowPass(obj,t);
D = obj.getD(err*val);
output = P + I + D;
end
function val = getP(obj, err)
val = obj.Kp*err;
end
function val = getI(obj, err)
obj.IState = obj.IState + err * obj.Dt;
val = obj.Ki * obj.IState;
end
function val = getD(obj, err)
val = obj.Kd * (err - obj.PreErr) / obj.Dt;
obj.PreErr = err;
end
function val = lowPass(obj,t)
N = 10;
val = 1-exp(-N*t);
end
end
end
And tested it using a random low pass filter as the plant:
function r = getResponse(t)
r = 1 - exp(-5*t);
end
The test code:
sr = 1e2; % sampling rate 100Hz
st = 10; % sampling time 10s
ss = st*sr+1; % sample size
t = 0:1/sr:st; % time
input = ones(1,ss)*100;
output = zeros(1,ss);
measured = 0;
pid = PID(0,1,1,input(1),t(2)-t(1));
for i = 2:ss
rPID(i) = pid.update(measured, t(i));
output(i) = rPID(i)*getResponse(t(i));
measured = output(i);
end
figure
plot(t,output)
hold on;
plot(t,input)
plot(t,rPID)
legend('Output','Input','PID')
Note that the parameters are set to kp=0;ki=1;kd=1;. I'm only testing the differential part here. The result is very wrong:
Notice the Y-axis is scaled by 10^307. It gets too big that after ~1.6s the PID value exceeds the range of double precision and therefore, the curve stops.
I have ensured that both P and I parts work well enough (see this question I asked a while ago).
From the curve for the D component (see figure below), one can clearly see that it starts to oscillate heavy from the very beginning; its value reaches >50k after the 5th timestamp at 0.04s:
I'm almost certain I must have made a mistake in implementing the low pass filter, but I also noticed that even with the low pass filter removed, the differential values still behave similarly.
To have some sort of reference and comparison, I also made a Simulink simulation of the same system, using the exact same PID gains (i.e. kp=0;ki=1;kd=1;). Below is the block diagram (left), figure for input and output (top right figure) and figure for PID values (bottom right)
Note that there is no top/lower limit in the gain blocks and the initial inputs/outputs are set to zeros.
These PID gains are nowhere near optimised but they give completely different results in the simulation and coded PID.
Therefore the big question is am I doing something wrong here? Why is there a difference between the two results?
The implementation of the low pass filter is not correct. The difference equation of a low pass filter is as shown:
The call of the getResponse function could look like this:
pid = PID(0,1,1,input(1),t(2)-t(1));
for i = 2:ss
rPID(i) = pid.update(measured, t(i));
alpha = getResponse(0.25,0.01);
output(i) = rPID(i)*alpha+(1-alpha)*output(i-1);
measured = output(i);
end
Thus getResponse is equivalent to alpha
function r = getResponse(wc,Ts)
r = 1 - exp(-wc*Ts);
end
Further you have to modify the lowPass function in the PID class.
function output = update(obj, measuredValue)
err = obj.SetPoint - measuredValue;
P = obj.getP(err);
I = obj.getI(err);
val = lowPass(obj,err,0.1,0.01);
D = obj.getD(val);
output = P + I + D;
end
% ...
function val = lowPass(obj,err,wc,Ts)
alpha = getResponse(wc,Ts);
output = err*alpha+(1-alpha)*obj.output_1;
obj.output_1 = output;
val = output;
end

MATLAB 'parfor' Loops Very Slow When Compared With 'for' loop

I have a script that I'm running, and at one point I have a loop over n objects, where I want n to be fairly large.
I have access to a server, so I put in a parfor loop. However, this is incredibly slow compared with a standard for loops.
For example, running a certain configuration ( the one below ) with the parfor loop on 35 workers took 68 seconds, whereas the for loop took 2.3 seconds.
I know there's stuff to do with array-broadcasting that can cause issues, but I don't know a lot about this.
n = 20;
r = 1/30;
tic
X = rand([2,n-1]);
X = [X,[0.5;0.5]];
D = sq_distance(X,X);
A = sparse((D < r) - eye(n));
% Infected set I
I = n;
[S,C] = graphconncomp(A);
compnum = C(I);
I_new = find(C == compnum);
I = I_new;
figure%('visible','off')
gplot(A,X')
hold on
plot(X(1,I),X(2,I),'r.')
hold off
title('time = 0')
axis([0,1,0,1])
time = 0;
t_max = 10; t_int = 1/100;
TIME = 1; T_plot = t_int^(-1) /100;
loops = t_max / T_plot;
F(loops) = struct('cdata',[],'colormap',[]);
F(1) = getframe;
% Probability of healing in interval of length t_int
heal_rate = 1/3; % (higher number is faster heal)
p_heal = t_int * heal_rate;
numhealed = 0;
while time < t_max
time = time+t_int;
steps = poissrnd(t_int,[n,1]);
parfor k = 1:n
for s = 1:steps(k)
unit_vec = unif_unitvector;
X_new = X(:,k) + unit_vec*t_int;
if ( X_new < 1 == ones(2,1) ) ...
& ( X_new > 0 == ones(2,1) )
X(:,k) = X_new;
end
end
end
D = sq_distance(X,X);
A = sparse((D < r) - eye(n));
[S,C] = graphconncomp(A);
particles_healed = binornd(ones(length(I),1),p_heal);
still_infected = find(particles_healed == 0);
I = I(still_infected);
numhealed = numhealed + sum(particles_healed);
I_new = I;
% compnum = zeros(length(I),1);
for i = 1:length(I)
compnum = C(I(i));
I_new = union(I_new,find(C == compnum));
end
I = I_new;
if time >= T_plot*TIME
gplot(A,X')
hold on
plot(X(1,I),X(2,I),'r.')
hold off
title(sprintf('time = %1g',time))
axis([0,1,0,1])
% fprintf('number healed = %1g\n',numhealed)
numhealed = 0;
F(TIME) = getframe;
TIME = TIME + 1;
end
end
toc

MATLAB: Inputting enough arguments, still getting a "not enough input arguments" error

I'm having problems with the class constructor for my CoaxLine class. I pass it all the arguments it needs, but when I create an object in another program, I get the error:
Error using length Not enough input arguments.
Error in CoaxLine (line 23) function obj = CoaxLine(pow,len,h,freq,x1,x2,y1,y2,dir,split)
Error in Test2 (line 38) coax1 = CoaxLine(3.9,100,4.75,1800,10,110,10,10,0,1);
I got this same error with length even when I removed all the argument requirements for the constructor, and created the object with no inputs. This is my first time building a class in MATLAB, so it is likely that I missed something silly. I appreciate the help.
Here is the code for CoaxLine:
classdef CoaxLine
%UNTITLED2 Summary of this class goes here
% Detailed explanation goes here
properties
%Default values
PA = 3.9;
orientation = 0; %0 for East-West, 1 for North-South
splitter = 1; %0 for left side, 1 for right side
length = 90;
frequency = 1800; %in MHz
height = 4.75;
Ce = 8.77; %Hardcoded for now
Lint = .13; %Hardcoded
nearFieldLength = 2*(length^2)/((3.0*10^8)/(frequency*10^6));
X1 = 10; %Will be points in the simulation axis
X2 = 110;
Y1 = 10;
Y2 = 10;
%loss = 10;
end
methods
function obj = CoaxLine(pow,len,h,freq,x1,x2,y1,y2,dir,split)
%if nargin > 0
obj.PA = pow;
obj.length = len;
obj.height = h;
obj.frequency = freq;
obj.X1 = x1;
obj.X2 = x2;
obj.Y1 = y1;
obj.Y2 = y2;
obj.orientation = dir;
obj.splitter = split;
%end
end
function r = contribution(px,py)
if(obj.orientation == 0)
if(obj.splitter)
if(abs(py - obj.Y1) <= obj.nearFieldLength && px > obj.X1 && px < obj.X2)
H = abs(py - obj.Y1);
x = px - obj.X1;
r = NearFieldPropagation(obj.PA,obj.length,obj.frequency,H,obj.height,obj.Ce,obj.Lint,x);
end
else
if(abs(py - obj.Y1) <= obj.nearFieldLength && px < obj.X1 && px > obj.X2)
H = abs(py - obj.Y1);
x = obj.X1 - px;
r = NearFieldPropagation(obj.PA,obj.length,obj.frequency,H,obj.height,obj.Ce,obj.Lint,x);
end
end
%else
end
end
end
end
The error stems from this line:
nearFieldLength = 2*(length^2)/((3.0*10^8)/(frequency*10^6));
MATLAB thinks that you're trying to call the function length. That requires an argument whose length will be returned.
The use of frequency will give you headaches too. To properly handle this kind of properties you should declare your nearFieldLength as Dependent: http://www.mathworks.com/help/matlab/matlab_oop/access-methods-for-dependent-properties.html and then write a getter for it that will calculate its value on the fly.
Also, as excaza noted, you'll have further errors because you don't declare obj as argument in contribution.
This is my idea on how the code should look like:
classdef CoaxLine
properties
PA = 3.9;
orientation = 0;
splitter = 1;
length = 90;
frequency = 1800;
height = 4.75;
Lint = .13;
X1 = 10;
X2 = 110;
Y1 = 10;
Y2 = 10;
end;
properties(Dependent, SetAccess=private)
Ce;
nearFieldLength;
end;
methods
%//Constructor
function obj = CoaxLine(pow,len,h,freq,x1,x2,y1,y2,dir,split)
if nargin > 0
obj.PA = pow;
obj.length = len;
obj.height = h;
obj.frequency = freq;
obj.X1 = x1;
obj.X2 = x2;
obj.Y1 = y1;
obj.Y2 = y2;
obj.orientation = dir;
obj.splitter = split;
end;
end;
%//Getters for dependent properties
function val = get.Ce(obj) %#ok<MANU>
val = 8.77; %//this can be changed later
end;
function val = get.nearFieldLength(obj)
val = 2*(obj.length^2)/(3E8/(obj.frequency*1E6));
end;
%//Normal methods
function r = contribution(obj, px, py)
r = []; % some default value
if obj.orientation == 0
if obj.splitter
if abs(py - obj.Y1) <= obj.nearFieldLength ...
&& px > obj.X1 ...
&& px < obj.X2
H = abs(py - obj.Y1);
x = px - obj.X1;
r = NearFieldPropagation(obj.PA,obj.length,obj.frequency,H,obj.height,obj.Ce,obj.Lint,x);
end;
else
if abs(py - obj.Y1) <= obj.nearFieldLength ...
&& px < obj.X1 ...
&& px > obj.X2
H = abs(py - obj.Y1);
x = px - obj.X1;
r = NearFieldPropagation(obj.PA,obj.length,obj.frequency,H,obj.height,obj.Ce,obj.Lint,x);
end;
end;
end;
end;
end;
end