I have a problem regarding putting a PID controller in my simulink file.
In my simulink file, i used pid controller to control my process. I used s-function as my process block diagram.
According Ziegler-Nichols method, for the first step we set k equal to the smallest value (0.5) so I put 0.5 in my proportional value . but there is no different between the result with controller and without controller.Even i increase or decrease proportional value.
Why this problem occur? hope someone can help me.Thank you.
my block diagram is look like below picture.refer to this picture
http://s1009.photobucket.com/albums/af218/syarinazulkifeli/?action=view¤t=Untitled-1.png
Here is my s-function file:
function [sys,x0,str,ts]= reactor_sfcn(t,x,u,flag)
switch flag
case 0
[sys,x0,str,ts]=mdlInitializeSizes;
case 1,
sys = mdlDerivatives(t,x,u);
case 3,
sys = mdlOutputs(t,x,u);
case 9
sys =[];
end
function [sys,x0,str,ts] = mdlInitializeSizes()
s = simsizes;
s.NumContStates = 11;
s.NumDiscStates = 0;
s.NumOutputs = 11;
s.NumInputs = 1;
s.DirFeedthrough = 0;
s.NumSampleTimes = 1;
sys = simsizes(s) ;
x0 = [0.0258,0,0,0,0,0,0,0,8.83,303.15,303.15];
str=[] ;
ts = [0 0];
function sys = mdlDerivatives (t,x,u)
Tjo = u;
sys = reactor(t,x,Tjo);
function sys = mdlOutputs(t,x,u)
% sys(1)=x(1);
% sys(2)=x(2);
% sys(3)=x(3);
% sys(4)=x(4);
% sys(5)=x(5);
% sys(6)=x(6);
% sys(7)=x(7);
% sys(8)=x(8);
% sys(9)=x(9);
% sys(10)=x(10);
% sys(11)=x(11);
sys = x;
Link of s-function file
function DXDT = reactor(t,x,Tjo)
% -------------------------------------------- %
% Parameters definition
% -------------------------------------------- %
I = x(1); X = x(2); P0 = x(3);
P1 = x(4); P2 = x(5); Q0 = x(6);
Q1 = x(7); Q2 = x(8); M = x(9);
Tjo = x(10); T = x(11);
% ---------------------------------------
% Constants
% =======================================
%constant
M0 = 8.83;
I0 = 0.0258;
Qh = 60.44;
MMWm = 100.3;
U0 = 55.1;
% Densities
dp = 1200;
dm = 968-1.225*(T-273.15);
Rhoc = 998;
% volume expansion factor
Fev = (dm - dp)./dp ;
% volume fraction
Fvm = (1 - X)./(1 + Fev*X);
Fvp = X*(1-Fev)./(1+Fev*X);
% Total reactant mixture density
Rho = dm*Fvm + dp*Fvp;
% Reactor and jacket volume
Vc = 2;
V = 2;
% Reactor dimension
At =3.1416*0.15*0.113;
% coolant flow rate
Mc = 0.41/18;
%
Cpc = 77.22;
Cp = 199.13;
% Average coolant temperature
Tji = 303.15;
Tj =(Tji+Tjo)/2;
% Overall heat transfer coeff
alpha = 0.4;
U = U0-alpha*X;
delHp = 57800;
% ---------------------------------------
% Rates of reaction
% =======================================
% Fujita-Doolittle equation
Tgp = 114 +273.25 ;
A = 0.168-8.21e-6*(T-Tgp)^2;
B = 0.03;
g = exp(2.303*Fvm/(A + B*Fvm));
% Dissociation rate
F = 0.58;
Kd = (6.32e16*exp(-15.43e3/T));
% Propagation rate
Tep = 5.4814e-16*exp(13982/T);
Kp0 = 2.952e7*exp(-4353/(1.987*T));
Kp = (Kp0*g)./(g + (Tep*P0.*Kp0));
% Termination rate
Tet = (1.1353e-22*exp(17420/T))./I0;
Kt0 = 5.88e9*exp(-701/(1.987*T));
Kt = (Kt0*g)./(g + (Tet*P0.*Kt0));
Ktc = 0;
Ktd = Kt ;
% -------------------------------------------- %
% ODE's
% -------------------------------------------- %
dIdt = -Kd*I - ((Fev*I.*P0.*(1 - X)*Kp)./(1 + Fev*X));
dXdt = Kp*(1 - X).*P0;
dP0dt = (-Fev*P0.*P0.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P0;
dP1dt = (-Fev*P0.*P1.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P1 + (Kp*M0*(1 - X)./(1 + Fev*X)).*P0;
dP2dt = (-Fev*P0.*P2.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P2 + (Kp*M0*(1 - X)./(1 + Fev*X)).*(2*P1 + P0);
dQ0dt = (-Fev*P0.*Q0.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P0 + 0.5*Ktc*P0.*P0;
dQ1dt = (-Fev*P0.*Q1.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P1 + Ktc*P0.*P1;
dQ2dt = (-Fev*P0.*Q2.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P2 + Ktc*(P1.*P0 + P1.^2);
dMdt = (-Kp*P0*M0*(1 - X)./(1 + Fev*X)).*((Fev*(1 - X)./(1 + Fev*X)) + 1);
Rm = (-delHp)*dMdt;
dTjodt = (Mc*Cpc*(Tji-Tjo)+ U*At*(T-Tj))/(Vc*Rhoc*Cpc/18);
dTdt = (Qh+(Rm*V*MMWm)-(U*At*(T-Tj)))/(V*Rho*Cp);
DXDT =[dIdt;dXdt;dP0dt;dP1dt;dP2dt;dQ0dt;dQ1dt;dQ2dt;dMdt;dTjodt;dTdt];
First I woult check if the s-function for the process is working as expected. Disconnect the PID controller and connect a step, ramp or a sin block. This could give you a hint if the block for the process is OK and how large the static coefficient is.
A second hint: the Ziegler-Nichols method says one should increase the Kp until the system gets marginaly stable. Have you tested only one value for the proportional gain? Depending on the plant 0.5 can be really small value and way under the levels you need to control the system.
You change the Kp term but there is no change...did you give the system a step command? Is the actual and desired signal error being fed back to the PID controller? If these are satisfied and the system is still insensitive to Kp you may need to go through your model block by block to find the issue. Also, why are you modelling your plant with an S function? Implementing these can be tricky. I would much rather see the plant model in diagram form, or at least in embedded m.
For the step input I would recommend this link or google it. You need to set the Kp fairly high and then give it a step command input to destabilize the system and then vary Kp until it's stable and measure the period of oscillation.
I put together a toy model for you to test, I am inclined as well to beleive your s-function is at fault here. If you want to post/send the sfunction, I'd be glad to look at it. However, if you want to learn Ziegler-Nichols, start with a very simple model and follow the steps in the Ziegler-Nichols process. Here's the output for some of my data with a Kp = 200 and a plant of 1/(s+1):
So you can see the oscillation above. Kp = 200 is way too high, you'd have to reduce it quite a bit for Ziegler-Nichols, but I just wanted to give you an example.
EDIT I downloaded your readtor_sfcn and reactor function into two files named
reactor_sfcn.m and reactor.m Right away, I can tell why you never see any
change in the input. In the reactor_sfcn mdlDerivatives, you pass the input
to the system u as the third parameter to the reactor function. In the
reactor function I can see that the third parameter, Tjo is never read,
but overwritten with x(10). So, if Tjo is supposed to be the input parameter
it shouldn't also be a state. That will be up to you to solve that problem,
it is specific to your implementation of the plant. I've got a test model
I've used to look at your files, I'll try to put it somewhere you can get
access to it soon, but it likely won't be as useful as you analyzing what
the plant is supposed to be doing. Hope this helps!
Thanks!
Related
I'm trying to avoid the function tf() from Matlab since it requires specific toolboxes to run.
The transfer function that I'm using is quite simple. Is the model for a heatsink temperature.
H(s) = (Rth/Tau)/(s + 1/Tau)
In order to avoid the tf() function, I've tried to substitute the transfer function with a state space model coded in Matlab.
I've used the function ss() to get te values of A,B,C and D. And I've tried to compare the results from tf() and my function.
Here's the code that I've used:
Rth = 8.3220e-04; % ºC/W
Tau = 0.0025; % s
P = rand(1,10)*1000; % Losses = input
t = 0:1:length(P)-1; % Time array
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Transfer function %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
H = tf([0 Rth/Tau],[1 1/Tau]);
Transfer_func = lsim(H,P,t);
figure, plot(Transfer_func),grid on,grid minor, title('Transfer func')
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% My función ss %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
% Preallocate for speed
x(1:length(P)) = 0;
y(1:length(P)) = 0;
u = P;
sys = ss(H);
A = sys.A;
B = sys.B;
C = sys.C;
D = sys.D;
for k = 1:length(u)
x(k+1) = A*x(k) + B*u(k);
y(k) = C*x(k) + D*u(k);
end
figure, plot(y), grid on,grid minor, title('With my función')
I know that the values from A,B,C and D are ok, since I've checked them using
H = tf([0 Rth/Tau],[1 1/Tau]);
sys = ss(H);
state_space_sys = ss(sys.A,sys.B,sys.C,sys.D);
state_space = lsim(state_space_sys,P,t);
figure, plot(state_space),grid on,grid minor, title('State space')
As you can see, the results obtained from my funtion and the function tf() are very different.
Is there any mistakes on the approach?
If it's not possible to avoid the tf() function in this way, is there any other way?
At the end, I found another solution. I'm posting this here, so if someone has the same problem, can use this approach.
If you take the transfer function, and develop it, we reach to the following expresion
H(s) = deltaT(s)/P(s) = (Rth/Tau)/(s + 1/Tau)
deltaT(s) * (s + 1/Tau) = (Rth/Tau) * P(s)
deltaT(s) * s = (Rth/Tau) * P(s) - deltaT(s)/Tau
Now, we know that 1/s is equal to integrate. So in the end, we have to integrate the right side of the equation. The code would be like this.
Cth = Tau/Rth;
deltaT = zeros(size(P));
for i = 2:length(P)
deltaT(i) = (1/Cth * (P(i)-deltaT(i-1)/Rth))*(time(i)-time(i-1)) + deltaT(i-1);
end
This integral has the same output as the function tf().
I have model with "matlab function block" in which I have recursive least square method. Recursive algorithm needs to know length of incoming signal in order to work correctly. But when I use command N=length(y) it returns me length N= 1. But I think it should give me higher length.
Simulink model
Matlab function block code "rls_iden6"
function [P,N] = fcn(u,y)
%%
N = length(y);
sigma=1;
C = sigma*eye(2); %p
P = ones(2,1);
z= [y; u];
lamda=1;
for n=1:N
sample_out = y(n);
C = (C - ( (C*z*z'*C)/( lamda+(z'*C*z) ) ))/lamda;
P = P + (C*z* (sample_out - (z'*P)));
end
My final code should look like it's shown below, because it works in matlab workspace. Simulink should give me 5 parameters instead of just 2.
load data_cela.mat
u=U; %input
y=Y; %output
%%
input = 3;
output = 2;
system = input + output;
N = length(y);
%initial conditions
sigma = 1;
C = sigma*eye(system);
P = ones(system,1);
lamda = 1; %forgetting factor
for n=3:N
for i=1:2
W(i) = y(n-i); %output
end
for i=1:3
V(i) = u(n-i+1); %input
end
z = [V';W'];
sample_out = y(n);
pom(n)= z' * P;
error(n) = y(n) - pom(n);
C = (C - ( (C*z*z'*C)/( lamda+(z'*C*z) ) ))/lamda;
P = P + (C*z* (sample_out - (z'*P) ) );
change(1:system,n) = P;
end
f_param = [P(1:3);-P(4:5)];
num = [P(1:3,1)];
den = [1;-P(4:5,1)];
num1 = num(3,1);
trasferfunction = tf(num1,den',1)
Result:
0.002879
----------------------
z^2 - 1.883 z + 0.8873
You will need to add a buffer before signal to convert the scalar to matrix. Then after the buffer has been added set the buffer size to the amount of data you want, i.e. by setting it to 2 will make 2 rows and 1 column. This will help you to get the data however, for setting delay properly you will require to set buffer overlap to 1.
Hope this helps.
I have some reference data against which I want to fit some model data. I have developed a 5-param model for this purpose. The job now is to optimize the model params using Matlab. However, I have very poor fit for ref vs model data (r^2 in the range 0.6 only). I tried using fminsearch and nlinfit algorithms.
One probable reason might be that my params are not of similar order of magnitude (while 1 param is of range e-09, another is ~e03). I am unsure whether to use scaling/normalization of params, and if so how to go about it. Can anyone help?
Here's my code for your perusal:
voltage = xlsread('co_content_29_07_avik.xlsx','A9:A99'); % voltage
current = xlsread('co_content_29_07_avik.xlsx','B9:B99'); % current
% Cell characteristics from manufacturer's datasheet
V_oc = 0.665; %V
I_sc = 5.75; %A
V_mp = 0.56; % V
I_mp = 5.35; % A
a = 1.2 % educated guess
% Calculate thermal voltage
k = 1.3806e-23; %Boltzmann constant - Joule/Kelvin
T = 298;
q = 1.602e-19; %electron charge - Coulomb
n_cell = 1; % no. of cells
V_t = n_cell*k*T/q;
% Calculate unoptimized cell parameters (R_s, R_sh, I_0, I_ph, n)
A = a*V_t/I_mp;
B = -(V_mp*(2*I_mp - I_sc)/(V_mp*I_sc + V_oc*(I_mp - I_sc)));
C = -((2*V_mp - V_oc)/a*V_t) + (V_mp*I_sc - V_oc*I_mp)/(V_mp*I_sc + V_oc*(I_mp - I_sc));
D = (V_mp-V_oc)/(a*V_t);
R_s = A*lambertw((B*exp(C) - (D+C)))
R_sh_num = (V_mp-I_mp*R_s)*(V_mp - R_s*(I_sc-I_mp) - a*V_t);
R_sh_den = (V_mp-I_mp*R_s)*(I_sc-I_mp) - a*V_t*I_mp;
R_sh = R_sh_num/R_sh_den
I_0 = (I_sc*(R_sh + R_s) - V_oc)/(R_sh*exp(V_oc/(a*V_t)))
I_ph = (R_sh+R_s)*I_sc/R_sh
len = length(voltage);
for i=1:1:len
non_exp1 = R_s*R_sh*I_0/(a*V_t*(R_s + R_sh));
lambexp1 = R_sh*(R_s*I_ph + R_s*I_0 + voltage(i,1))/(a*V_t*(R_s + R_sh));
lambarg1 = non_exp1*exp(lambexp1);
firstterm1 = -voltage(i,1)/(R_s + R_sh);
midterm1 = -(lambertw(lambarg1)*a*V_t/R_s);
third1 = R_sh*(I_0 + I_ph)/(R_s + R_sh);
I_1(i,1) = firstterm1 + midterm1 + third1;
end
% Optimize using fminsearch algo
fun = #(p) sum((current - (voltage/(p(1)+p(2)) - (lambertw((p(1)*p(2)*p(3))/(p(5)*V_t*(p(1)+p(2)))))*exp((p(2)*(p(1)*p(4)+p(1)*p(3)+voltage))/(p(5)*V_t*(p(1)+p(2))))*p(5)*V_t/p(1) + (p(2)*(p(3)+p(4))/(p(1)+p(2))))).^2);
% initial guess for param
pguess = [0.005,4.75,0.000000001,5.75,1.2];
%optimize
[x,fval,exitflag,output] = fminsearch(fun,pguess,optimset('MaxFunEvals',1000))
I am trying to solve a 2nd order differential equation in Matlab. I was able to do this using the forward Euler method, but since this requires quite a small time step to get accurate results I have looked into some other options. More specifically the Improved Euler method (Heun's method).
I understand the principle of Improved Euler method, that it first estimates the velocity and then uses that information to correct it to the current condition. But I am not totally sure if what I have written is totally correct.
1)Can you check if my code utilizes the Improved Euler method correctly?
2)In my code, the last line before the end, the second B(ii) should be B(ii+1)?
I have written a simplified code for both options. Here it is:
t = 0:0.01:100;
dt = t(2)-t(1); % Time step
%Constants%
M = 20000;
m_a = 10000;
c= 15000;
k_spring = 40000;
B = rand(1,length(t)+1);
%% Forward Euler Method %%
x = zeros(1,length(t)+1); % Pre-allocation
u = zeros(1,length(t)+1); % Pre-allocation
x(1) = 1; % Initial condition
u(1) = 0; % Initial condition
for ii = 1:length(t)
x(ii+1) = x(ii) + dt*u(ii);
u(ii+1) = u(ii) + dt * ((1/(M+m_a)) * -(c+k_spring+B(ii))*x(ii));
end
%% Improved Euler Method %%
x1 = zeros(1,length(t)+1); % Pre-allocation
u1 = zeros(1,length(t)+1); % Pre-allocation
x1(1) = 1; % Initial condition
u1(1) = 0; % Initial condition
for ii = 1:length(t)
x1(ii+1) = x1(ii) + dt*u1(ii);
u1(ii+1) = u1(ii) + dt * ((1/(M+m_a)) * -(c+k_spring+B(ii))*x1(ii)); %Estimate
u1(ii+1) = u1(ii) + (dt/2) * ( ((1/(M+m_a)) * -(c+k_spring+B(ii))*x1(ii)) + ((1/(M+m_a)) * -(c+k_spring+B(ii))*x1(ii+1)) ); %Correction
end
Thanks!
You should follow the principal programming idea to make things that are used repeatedly into extra procedures. Suppose you did so and the function evaluating the ODE function is called odefunc.
function [dotx, dotu] = odefunc(x,u,B)
dotx = u;
dotu =(1/(M+m_a)) * -(c+k_spring+B)*x);
end
Then
for ii = 1:length(t)
%% Predictor
[dotx1,dotu1] = odefunc(x1(ii), u1(ii), B(ii));
%% One corrector step
[dotx2,dotu2] = odefunc(x1(ii)+dotx1*dt, u1(ii)+dotu1*dt, B(ii+1));
x1(ii+1) = x1(ii) + 0.5*(dotx1+dotx2)*dt;
u1(ii+1) = u1(ii) + 0.5*(dotu1+dotu2)*dt;
end
Im tying to find the fundamental frequency of a note using harmonic product spectrum. This is the part that implements the HPS algorithm
seg_fft = seg_fft(1 : size(seg_fft,1)/2 ); % FFT data
seg_fft = abs(seg_fft);
seg_fft2 = ones(size(seg_fft));
seg_fft3 = ones(size(seg_fft));
seg_fft4 = ones(size(seg_fft));
seg_fft5 = ones(size(seg_fft));
for i = 1:floor((length(seg_fft)-1)/2)
seg_fft2(i,1) = (seg_fft(2*i,1) + seg_fft((2*i)+1,1))/2;
end
for i = 1:floor((length(seg_fft)-2)/3)
seg_fft3(i,1) = (seg_fft(3*i,1) + seg_fft((3*i)+1,1) + seg_fft((3*i)+2,1))/3;
end
for i = 1:floor((length(seg_fft)-3)/4)
seg_fft4(i,1) = (seg_fft(4*i,1) + seg_fft((4*i)+1,1) + seg_fft((4*i)+2,1) + seg_fft((4*i)+3,1))/4;
end
for i = 1:floor((length(seg_fft)-4)/5)
seg_fft5(i,1) = (seg_fft(5*i,1) + seg_fft((5*i)+1,1) + seg_fft((5*i)+2,1) + seg_fft((5*i)+3,1) + seg_fft((5*i)+4,1))/5;
end
f_ym = (seg_fft) .* (seg_fft2) .* (seg_fft3) .* (seg_fft4) .*(seg_fft5);
Now when i play F4, the 2nd harmonic(698 -F5) has a higher amplitude. So HPS is supposed to help me detect the fundamental which is F4 and NOT F5.
When i do the HPS these are the graphs I get:
The figures above show the plots of seg_fft2, seg_fft3, seg_fft4 and seg_fft5 respectively.
But what I dont understand is how come the frequency points obtained in these graphs are not factors of the original spectrum?? Isn't that how HPS is supposed to work??
This is the plot I obtained when I took the product of all 5.
the peak is at 698Hz.. But shouldn't it be at 349Hz instead??
But after the whole code is run, I do get the fundamental as F4.. Its all very confusing.... Can someone tell me why my graphs are different from what is expected yet I get the correct fundamental please????
This is the rest of the code
%HPS, PartIII: find max
f_y1 = max(f_ym)
for c = 1 : length(f_ym)
if(f_ym(c,1) == f_y1)
index = c;
end
end
% Convert that to a frequency
f_y(h) = (index / NFFT) * FS;
h=h+1;
%end
V = abs(f_y);
Please do help...... Thanx in advance....