Simulation of control system with only matlab script withou simulink

85 views (last 30 days)
I want to simulate coontrol system using PID for a start. I have sets of DAEs. I have tried to simulate closed loop control system without using simulink blocks. But I got an error. I think my script has structural errors and I feel i am missing some things. I have alwys been using Simulink but I this time, I need to do some things and my research group are not familiar with simulink. So I have been requested to write the code uisng only script so that they can understand it since they know python.
Please, I need help on fixing this script given below. I have tried but I am stucked. I want to have freedom in selecting solver choice like ode 45,ode23s etc, I also want to be able to use any reference input for transient simulation.
function solveReactorDAE()
%% Parameters
Sig_x=2.65e-22;
yi=0.061;
yx=0.002;
lamda_x = 2.09e-5;
lamda_I = 2.87e-5;
Sum_f = 0.3358;
%nv=2.2e+3; % average velocisty of neutrons (thermal)
%nu=2.43; % the total number of neutrons liberated per rx
%Sigf=1/(gen*nv*nu); % what is this
l=1.68e-3;
beta = 0.0065;
beta_1 = 2.267510e-4;
beta_2 = 1.22023e-3;
beta_3 = 1.193061e-3;
beta_4=2.785813e-3;
beta_5=1.257395e-3;
beta_6=5.226188e-4;
Lamda_1 = 0.0124;
Lamda_2 = 0.0369;
Lamda_3 = 0.632;
Lamda_4=3.044508e-1;
Lamda_5=8.539933e-1;
Lamda_6=2.868585;
%Gr8 =-2350E-5/180*2; % All drums
Gr4 =-1450E-5/180*2; % half
%Gr2 =-660E-5/180*2; % 1/4
Gr1 =-250E-5/180*2; % one
cp_f=977;
cp_m=1697;
cp_c=5188.6;
M_f=2002;
M_m=11573;
M_c=500;
mu_f=M_f*cp_f;
mu_m=M_m*cp_m;
mu_c=M_c*cp_c;
f_f = 0.96;
P_0 = 20;
Tf0=1105;
Tm0=1087;
T_in=864;
T_out=1106;
Tc0=(T_in+T_out)/2;
K_fm=f_f*P_0/(Tf0-Tm0);
K_mc=P_0/(Tm0-Tc0);
M_dot=1.75E+01;
alpha_f=-2.875e-5;
alpha_m=-3.696e-5;
alpha_c=0.0;
X0=2.35496411413791e10;
% Define your DAE system (example only)
%function [dx, algebraic] = reactorDAE(t, x, u, rho_inf)
function [dx, algebraic] = reactorDAE(t, x, u1, u4)
% Extract state variables
%neutron_flux = x(1);
%temperature = x(2);
%xenon = x(3);
n_r = x(1); Cr1 = x(2); Cr2 = x(3); Cr3 = x(4); Cr4 = x(5);Cr5=x(6);Cr6=x(7);
X = x(8); I = x(9); Tf = x(10); Tm = x(11); Tc = x(12); Rho_d1 = x(13);Rho_d2 = x(14);
% Define inputs (control signals) - here, for simplicity, assume constant
%u1 = 0.01; % Control signal 1 (e.g., PID output)
%u2 = 0.005; % Control signal 2 (e.g., temperature control)
kp = 1; % Proportional gain
ki = 0.1; % Integral gain
kd = 0.01; % Derivative gain
% u1=Kp * error + Ki * error_integrated + Kd * (error - error_prev) / dt;
% %u2=Kp * error + Ki * error_integrated + Kd * (error - error_prev) / dt;
% %u3=Kp * error + Ki * error_integrated + Kd * (error - error_prev) / dt;
% u4=Kp * error + Ki * error_integrated + Kd * (error - error_prev) / dt;
u1=pid(kp,ki,kd);
%u2=pid(kp,ki,kd);
%u3=pid(kp,ki,kd);
u4=pid(kp,ki,kd);
% Compute reactivity
%rho = u(1) + u(2) - rho_inf * (neutron_flux - 1) + alpha_T * (temperature - 300) + alpha_Xe * xenon;
rho = Rho_d1+Rho_d2+alpha_f*(Tf-Tf0)+alpha_c*(Tc-Tc0)+alpha_m*(Tm-Tm0)-Sig_x*(X-X0)/Sum_f;
% Compute derivatives
%dx = zeros(3, 1);
%dx(1) = (beta / Lambda) * rho; % Neutron flux dynamics
%dx(2) = 0.1 * (neutron_flux - 1); % Temperature dynamics (example only)
%dx(3) = 0.0001 * (neutron_flux - 1); % Xenon dynamics (example only)
%define the initial states
dx = zeros(14,1) ;
%%kinetics equations with six-delayed neutron groups
dx(1) = (rho-beta)/l*n_r+beta_1/l*Cr1+beta_2/l*Cr2+beta_3/l*Cr3+beta_4/l*Cr4+beta_5/l*Cr5+beta_6/l*Cr6;
dx(2) = Lamda_1*n_r-Lamda_1*Cr1;
dx(3) = Lamda_2*n_r-Lamda_2*Cr2;
dx(4) = Lamda_3*n_r-Lamda_3*Cr3;
dx(5) = Lamda_4*n_r-Lamda_4*Cr3;
dx(6) = Lamda_5*n_r-Lamda_5*Cr3;
dx(7) = Lamda_6*n_r-Lamda_6*Cr3;
%% Xenon and Iodine dynamics
G = 3.2e-11;
V = 400*200;% i need to confirm the volume to be used
Pi = P_0/(G*Sum_f*V);
% dx(8) = yx*Sum_f*Pi/nX0+lamda_I*I*nI0/nX0-Sig_x*X*Pi/nX0-lamda_x*X;
% dx(9) = yi*Sum_f*Pi/nI0-lamda_I*I;
dx(8) = yx*Sum_f*Pi+lamda_I*I-Sig_x*X*Pi-lamda_x*X;
dx(9) = yi*Sum_f*Pi-lamda_I*I;
%% thermal–hydraulics model of the reactor core
dx(10)=f_f*P_0/mu_f*n_r-K_fm/mu_f*(Tf-Tc);
dx(11)=(1-f_f)*P_0/mu_m*n_r+(K_fm*(Tf-Tm)-K_mc*(Tm-Tc))/mu_m;
dx(12)=K_mc*(Tm-Tc)/mu_c-2*M_dot*cp_c*(Tc-T_in)/mu_c;
dx(13) = Gr1*u1;
dx(14) = Gr4*u4;
% Algebraic equations
algebraic = [];
end
% Define initial conditions
t_span = [0 100];
%x0 = [1; 300; 0]; % Initial neutron flux, temperature, xenon concentration
x0 = [0.121886811335360; 0.121886893341315; 0.121885271145068; 0.121886810283437; 0.0651359556098032;
0.0704553771394268; -0.0244616314872170; 23549641141.3791; 16604965156.7948;
0.000506372787486842; 0.00153255417325857; 863.999999999640; -0.000221924659921813; -0.000221924659921813];
% Define the setpoint
setpoint = 1.0; % Desired neutron flux
neutron_flux_0=x0(1);
% Compute the error
%t_span=[t_start t_end];
%error = setpoint - neutron_flux_0;
%t_start = 0;
%t_end = 100;
%dt = 0.01;
%t = t_start:dt:t_end;
% Initialize arrays
%rho = zeros(size(t));
%neutron_flux = zeros(size(t));
%temperature = zeros(size(t));
%xenon = zeros(size(t));
%error_integrated = 0;
%error_prev = 0;
% Define function handle for DAE solver (e.g., ode15i for index-1 DAEs)
%dae_solver = @ode15i;
% Solve the DAE system
%[t, x] = dae_solver(@(t, x, u) reactorDAE(t, x, [u1; u4], rho_inf), t_span, x0, []);
[t, x] = ode15i(@(t, x, u1, u4) reactorDAE(t, x, u1, u4), t_span, x0, []);
% Plot results
figure;
subplot(4,1,1);
plot(t, x(1,:), 'r');
xlabel('Time (s)');
ylabel('Neutron Flux');
title('Neutron Flux vs Time');
% subplot(4,1,2);
% plot(t, x(2,:), 'g');
% xlabel('Time (s)');
% ylabel('Temperature (°C)');
% title('Temperature vs Time');
%
% subplot(4,1,3);
% plot(t, x(3,:), 'b');
% xlabel('Time (s)');
% ylabel('Xenon concentration (ppm)');
% title('Xenon Concentration vs Time');
%
% % Compute reactivity over time
% rho = zeros(size(t));
% for i = 1:length(t)
% rho(i) = u1 + u2 - rho_inf * (x(1,i) - 1) + alpha_T * (x(2,i) - 300) + alpha_Xe * x(3,i);
% end
%
% subplot(4,1,4);
% plot(t, rho, 'm');
% xlabel('Time (s)');
% ylabel('Reactivity (pcm)');
% title('Reactivity vs Time');
  3 Comments
Kamal
Kamal on 4 Mar 2024
Moved: Sam Chak on 4 Mar 2024
Thank you so much for the insight. I am the only one using MATLAB and doing this. The indentation issue is becasue I copied and pasted it. I have attached the file here instead of copying. Also, I had tried using time-domain PID if you observe that I commented it out. The issues are:
  1. I don't know at what line to write the PID code, is it after the differentilal algebraic equation (DAEs) of my system or where?
  2. I have two control inputs, that is why I wrote two PIDs.
  3. States 13 and 14 are the inputs or used to input the control signals
  4. The error is difference between the set point and output, initializing the first output to calculate the first error is also a challenge for me.
Pardon my ignorance, please because I am migrating from simulink to matlab. Once I get this, I believe I will be able to do subsequent ones
Thank for the inisght
Sam Chak
Sam Chak on 4 Mar 2024
No worries, @Kamal. I suggest presenting the results to your team first and then inquire about their expectations, similar to the questions I raised in my Answer below.

Sign in to comment.

Accepted Answer

Sam Chak
Sam Chak on 4 Mar 2024
Hi @Kamal,
The Reactor system seems to exhibit stability even without any control inputs (u1 = u4 = 0). I'm curious about what specific aspect you intend to control. In other words, what are the desired output responses that you expect to observe in a practical scenario?
tspan = [0 20]; % [0 500] to see the convergence of x2 and x3
x0 = [0.121886811335360; 0.121886893341315; 0.121885271145068; 0.121886810283437; 0.0651359556098032; 0.0704553771394268; -0.0244616314872170; 23549641141.3791; 16604965156.7948; 0.000506372787486842; 0.00153255417325857; 863.999999999640; -0.000221924659921813; -0.000221924659921813];
[t, x] = ode45(@reactorDAE, tspan, x0);
figure(1)
tl1 = tiledlayout(3, 3, 'TileSpacing', 'Compact');
nexttile([1 3])
plot(t, x(:,1)), grid on, title('x_{1}')
nexttile
plot(t, x(:,2)), grid on, title('x_{2}')
nexttile
plot(t, x(:,3)), grid on, title('x_{3}')
nexttile
plot(t, x(:,4)), grid on, title('x_{4}')
nexttile
plot(t, x(:,5)), grid on, title('x_{5}')
nexttile
plot(t, x(:,6)), grid on, title('x_{6}')
nexttile
plot(t, x(:,7)), grid on, title('x_{7}')
title(tl1, 'Six neutron groups'), xlabel(tl1, 'Time (sec)')
figure(2)
tl2 = tiledlayout(2, 1, 'TileSpacing', 'Compact');
nexttile
plot(t, x(:,8)), grid on, title('x_{8}')
nexttile
plot(t, x(:,9)), grid on, title('x_{9}')
title(tl2, 'Xenon and Iodine'), xlabel(tl2, 'Time (sec)')
figure(3)
tl3 = tiledlayout(3, 3, 'TileSpacing', 'Compact');
nexttile
plot(t, x(:,10)), grid on, title('x_{10}')
nexttile([2 2])
plot(t, x(:,10:14)), grid on, title('x_{10} to x_{14}')
nexttile
plot(t, x(:,11)), grid on, title('x_{11}')
nexttile
plot(t, x(:,12)), grid on, title('x_{12}')
nexttile
plot(t, x(:,13)), grid on, title('x_{13}')
nexttile
plot(t, x(:,14)), grid on, title('x_{14}')
title(tl3, 'Thermal–hydraulics states'), xlabel(tl3, 'Time (sec)')
function [dx, algebraic] = reactorDAE(t, x)
%% Parameters
Sig_x = 2.65e-22;
yi = 0.061;
yx = 0.002;
lamda_x = 2.09e-5;
lamda_I = 2.87e-5;
Sum_f = 0.3358;
% nv = 2.2e+3; % average velocisty of neutrons (thermal)
% nu = 2.43; % the total number of neutrons liberated per rx
% Sigf = 1/(gen*nv*nu); % what is this
l = 1.68e-3;
beta = 0.0065;
beta_1 = 2.267510e-4;
beta_2 = 1.22023e-3;
beta_3 = 1.193061e-3;
beta_4 = 2.785813e-3;
beta_5 = 1.257395e-3;
beta_6 = 5.226188e-4;
Lamda_1 = 0.0124;
Lamda_2 = 0.0369;
Lamda_3 = 0.632;
Lamda_4 = 3.044508e-1;
Lamda_5 = 8.539933e-1;
Lamda_6 = 2.868585;
% Gr8 = -2350E-5/180*2; % All drums
Gr4 = -1450E-5/180*2; % half
% Gr2 = -660E-5/180*2; % 1/4
Gr1 = -250E-5/180*2; % one
cp_f = 977;
cp_m = 1697;
cp_c = 5188.6;
M_f = 2002;
M_m = 11573;
M_c = 500;
mu_f = M_f*cp_f;
mu_m = M_m*cp_m;
mu_c = M_c*cp_c;
f_f = 0.96;
P_0 = 20;
Tf0 = 1105;
Tm0 = 1087;
T_in = 864;
T_out = 1106;
Tc0 = (T_in+T_out)/2;
K_fm = f_f*P_0/(Tf0-Tm0);
K_mc = P_0/(Tm0-Tc0);
M_dot = 1.75E+01;
alpha_f = -2.875e-5;
alpha_m = -3.696e-5;
alpha_c = 0.0;
X0 = 2.35496411413791e10;
%% Declaration of state variables, x(i), where i = 1 to 14
n_r = x(1);
Cr1 = x(2);
Cr2 = x(3);
Cr3 = x(4);
Cr4 = x(5);
Cr5 = x(6);
Cr6 = x(7);
X = x(8);
I = x(9);
Tf = x(10);
Tm = x(11);
Tc = x(12);
Rho_d1 = x(13);
Rho_d2 = x(14);
G = 3.2e-11;
V = 400*200;% i need to confirm the volume to be used
Pi = P_0/(G*Sum_f*V);
% Define inputs (control signals) - here, for simplicity, assume constant
% u1 = 0.01; % Control signal 1 (e.g., PID output)
% u2 = 0.005; % Control signal 2 (e.g., temperature control)
% u1 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u2 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u3 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u4 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
kp = 1; % Proportional gain
ki = 0.1; % Integral gain
kd = 0.01; % Derivative gain
% u1 = pid(kp,ki,kd);
% u2 = pid(kp,ki,kd);
% u3 = pid(kp,ki,kd);
% u4 = pid(kp,ki,kd);
u1 = 0; % stability test if the system is control-free
u4 = 0; % stability test if the system is control-free
rho = Rho_d1 + Rho_d2 + alpha_f*(Tf - Tf0) + alpha_c*(Tc - Tc0) + alpha_m*(Tm - Tm0) - Sig_x*(X - X0)/Sum_f;
%% ODEs
dx = zeros(14,1);
%% kinetics equations with six-delayed neutron groups
dx(1) = (rho-beta)/l*n_r+beta_1/l*Cr1+beta_2/l*Cr2+beta_3/l*Cr3+beta_4/l*Cr4+beta_5/l*Cr5+beta_6/l*Cr6;
dx(2) = Lamda_1*n_r-Lamda_1*Cr1;
dx(3) = Lamda_2*n_r-Lamda_2*Cr2;
dx(4) = Lamda_3*n_r-Lamda_3*Cr3;
dx(5) = Lamda_4*n_r-Lamda_4*Cr3;
dx(6) = Lamda_5*n_r-Lamda_5*Cr3;
dx(7) = Lamda_6*n_r-Lamda_6*Cr3;
%% Xenon and Iodine dynamics
dx(8) = yx*Sum_f*Pi+lamda_I*I-Sig_x*X*Pi-lamda_x*X;
dx(9) = yi*Sum_f*Pi-lamda_I*I;
%% thermal–hydraulics model of the reactor core
dx(10) = f_f*P_0/mu_f*n_r-K_fm/mu_f*(Tf-Tc);
dx(11) = (1-f_f)*P_0/mu_m*n_r+(K_fm*(Tf-Tm)-K_mc*(Tm-Tc))/mu_m;
dx(12) = K_mc*(Tm-Tc)/mu_c-2*M_dot*cp_c*(Tc-T_in)/mu_c;
dx(13) = Gr1*u1;
dx(14) = Gr4*u4;
% Algebraic equations
algebraic = [];
end
  22 Comments
Sam Chak
Sam Chak on 10 Mar 2024
I observed that the reactorDAE block in Figure 1 implements the exact dynamics as coded in MATLAB. This likely explains why the results matched in both MATLAB's ode45 and the Simulink's reactorDAE model. Could you please demonstrate how you and your research team generated the results shown in Figure 2 using two PID controllers?
If you are confident that the system model is accurate, you can try using two PID controller blocks to connect the reactorDAE system using the and channels in the Simulink model. By using the Desired Power profile as the Reference Input signal, you should obtain the same result as successfully simulated in Figure 2.
Figure 1: Reactor's dynamic system model in Simulink
Figure 2: Result of x1 under PID control simulated in Simulink.
Kamal
Kamal on 10 Mar 2024
@Sam Chak Yes this exactly what I have been trying to explain. The simulink model has no issue for me. I do not want to use the simulink at all. I only want to use only MATLAB script with no simulink block to generate figure 2 above. My questions are:
  1. can I wriite Matlab code for the PID algorthim to generate signals that I will feed into states x13 and x14 within the same matlab code above ?. It could be a single signal u_pid that I will use to multiply state x13 and x14.
  2. Concerning how I generated figure 2, I used the PID block and tuned it to generate the signal that is fed into the system. The signal is used to multiply the state x13 and x14.
Now how do this affect the output, look into this equation
rho = Rho_d1 + Rho_d2 + alpha_f*(Tf - Tf0) + alpha_c*(Tc - Tc0) + alpha_m*(Tm - Tm0) - Sig_x*(X - X0)/Sum_f;
Note the first two terms on the right handside, you will notice that they are state x13 and x14. The state x13 and x14 are generated by multiplying the input signal with a constant as given here dx(13) = Gr1*u1; dx(14) = Gr4*u4 and integral gives x13 and x14, if you check the simulink implementation. The remaining terms are inherent feedbacks into the system. Now note the term on the left handside, you will see that it is the one in the state x(1); dx(1) = (rho-beta)/l*n_r+beta_1/l*Cr1+beta_2/l*Cr2+beta_3/l*Cr3+beta_4/l*Cr4+beta_5/l*Cr5+beta_6/l*Cr6; That is how we influence the output state x1 with control input.
So it is the control input i want to generate with matlab script only WITHOUT SIMULINK BLOCKS.
In summary, what I want is to add control algrithm such as PID to the above MATLAB script that is working.
Note all the bolded

Sign in to comment.

More Answers (2)

Sam Chak
Sam Chak on 11 Mar 2024
I've developed a custom function called 'pidController()' to mimic the PID controller based on the control equation provided by your Control Design team. This function takes {setpoint, Kp, Ki, Kd, dt} as additional parameters in the input argument. Scroll to the bottom of the script.
However, it appears that the chosen gain values in the PID controller have destabilized the Reactor system. It might be wise to double-check with your Control Design team to validate the PID control design and compare the results against the original Simulink model that you previously executed successfully for PID, SMC, and MPC, as illustrated in Figure 2.
%% Parameters
setpoint = 1; % Reference input (actual one to be supplied by the user)
Kp = 1; % Proportional gain
Ki = 0.1; % Integral gain
Kd = 0.01; % Derivative gain
dt = 1e-4; % ideally it should be the time elapsed between the current and previous time steps
%% Call ode45
tspan = [0 20];
x0 = [0.121886811335360; 0.121886893341315; 0.121885271145068; 0.121886810283437; 0.0651359556098032; 0.0704553771394268; -0.0244616314872170; 23549641141.3791; 16604965156.7948; 0.000506372787486842; 0.00153255417325857; 863.999999999640; -0.000221924659921813; -0.000221924659921813];
[t, x] = ode45(@(t, x) reactorDAE(t, x, pidController(t, x, setpoint, Kp, Ki, Kd, dt)), tspan, x0);
Warning: Failure at t=3.009812e-01. Unable to meet integration tolerances without reducing the step size below the smallest value allowed (8.881784e-16) at time t.
%% Plot result
figure(1)
plot(t, x(:,1)), grid on, xlabel('Time'), title('x_{1}')
%% Reactor dynamics
function [dx, algebraic] = reactorDAE(t, x, u)
%% Parameters
Sig_x = 2.65e-22;
yi = 0.061;
yx = 0.002;
lamda_x = 2.09e-5;
lamda_I = 2.87e-5;
Sum_f = 0.3358;
% nv = 2.2e+3; % average velocisty of neutrons (thermal)
% nu = 2.43; % the total number of neutrons liberated per rx
% Sigf = 1/(gen*nv*nu); % what is this
l = 1.68e-3;
beta = 0.0065;
beta_1 = 2.267510e-4;
beta_2 = 1.22023e-3;
beta_3 = 1.193061e-3;
beta_4 = 2.785813e-3;
beta_5 = 1.257395e-3;
beta_6 = 5.226188e-4;
Lamda_1 = 0.0124;
Lamda_2 = 0.0369;
Lamda_3 = 0.632;
Lamda_4 = 3.044508e-1;
Lamda_5 = 8.539933e-1;
Lamda_6 = 2.868585;
% Gr8 = -2350E-5/180*2; % All drums
Gr4 = -1450E-5/180*2; % half
% Gr2 = -660E-5/180*2; % 1/4
Gr1 = -250E-5/180*2; % one
cp_f = 977;
cp_m = 1697;
cp_c = 5188.6;
M_f = 2002;
M_m = 11573;
M_c = 500;
mu_f = M_f*cp_f;
mu_m = M_m*cp_m;
mu_c = M_c*cp_c;
f_f = 0.96;
P_0 = 20;
Tf0 = 1105;
Tm0 = 1087;
T_in = 864;
T_out = 1106;
Tc0 = (T_in+T_out)/2;
K_fm = f_f*P_0/(Tf0-Tm0);
K_mc = P_0/(Tm0-Tc0);
M_dot = 1.75E+01;
alpha_f = -2.875e-5;
alpha_m = -3.696e-5;
alpha_c = 0.0;
X0 = 2.35496411413791e10;
%% Declaration of state variables, x(i), where i = 1 to 14
n_r = x(1);
Cr1 = x(2);
Cr2 = x(3);
Cr3 = x(4);
Cr4 = x(5);
Cr5 = x(6);
Cr6 = x(7);
X = x(8);
I = x(9);
Tf = x(10);
Tm = x(11);
Tc = x(12);
Rho_d1 = x(13);
Rho_d2 = x(14);
G = 3.2e-11;
V = 400*200;% i need to confirm the volume to be used
Pi = P_0/(G*Sum_f*V);
%% Define inputs (control signals) - here, for simplicity, assume constant
% u1 = 0.01; % Control signal 1 (e.g., PID output)
% u2 = 0.005; % Control signal 2 (e.g., temperature control)
% u1 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u2 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u3 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u4 = Kp*error + Ki*error_integrated + Kd*(error - error_prev)/dt;
% u1 = pid(kp,ki,kd);
% u2 = pid(kp,ki,kd);
% u3 = pid(kp,ki,kd);
% u4 = pid(kp,ki,kd);
%% The extra parameter u in reactorDAE(t, x, u) comes from the pidController()
u1 = u; % actuation thru channel x13, both PID controllers are the same
u4 = u; % actuation thru channel x14
%% ODEs
dx = zeros(14,1);
rho = Rho_d1 + Rho_d2 + alpha_f*(Tf - Tf0) + alpha_c*(Tc - Tc0) + alpha_m*(Tm - Tm0) - Sig_x*(X - X0)/Sum_f;
%% kinetics equations with six-delayed neutron groups
dx(1) = (rho-beta)/l*n_r+beta_1/l*Cr1+beta_2/l*Cr2+beta_3/l*Cr3+beta_4/l*Cr4+beta_5/l*Cr5+beta_6/l*Cr6;
dx(2) = Lamda_1*n_r-Lamda_1*Cr1;
dx(3) = Lamda_2*n_r-Lamda_2*Cr2;
dx(4) = Lamda_3*n_r-Lamda_3*Cr3;
dx(5) = Lamda_4*n_r-Lamda_4*Cr3;
dx(6) = Lamda_5*n_r-Lamda_5*Cr3;
dx(7) = Lamda_6*n_r-Lamda_6*Cr3;
%% Xenon and Iodine dynamics
dx(8) = yx*Sum_f*Pi+lamda_I*I-Sig_x*X*Pi-lamda_x*X;
dx(9) = yi*Sum_f*Pi-lamda_I*I;
%% thermal–hydraulics model of the reactor core
dx(10) = f_f*P_0/mu_f*n_r-K_fm/mu_f*(Tf-Tc);
dx(11) = (1-f_f)*P_0/mu_m*n_r+(K_fm*(Tf-Tm)-K_mc*(Tm-Tc))/mu_m;
dx(12) = K_mc*(Tm-Tc)/mu_c-2*M_dot*cp_c*(Tc-T_in)/mu_c;
dx(13) = Gr1*u1;
dx(14) = Gr4*u4;
%% Algebraic equations
algebraic = [];
end
%% PID controller
function u = pidController(t, x, setpoint, Kp, Ki, Kd, dt)
persistent integral_error prev_error prev_time;
if isempty(integral_error)
integral_error = 0;
prev_error = 0;
prev_time = 0;
end
error = setpoint - x(1);
integral_error = integral_error + error*(t - prev_time);
derivative_error = (error - prev_error)/dt;
prev_error = error;
prev_time = t;
% user-supplied PID control equation
u = Kp*error + Ki*integral_error + Kd*derivative_error;
end
  7 Comments
Sam Chak
Sam Chak on 11 Mar 2024
The generation of the reference input signal seems to be a separate issue. Instead of treating it as a control problem, I recommend posting it as a new problem focusing on the MATLAB coding aspect. Users who excel at loop structures would likely provide faster responses. Additionally, please include the expected shape or form of the reference input signal in your post.
Kamal
Kamal on 12 Mar 2024
@Sam Chak Alright I will do that. Thank you so much for your effort, time, patience. I really appreciate.

Sign in to comment.


Sam Chak
Sam Chak on 12 Mar 2024
Below, you will notice a slight perceptible difference in the results between the Ideal PID controller and the PID Control Emulator when simulating a stably-damped mass-spring system. I should emphasize that the code for the PID Control Emulator, which utilizes the 'persistent' variables technique, only approximates the Ideal PID controller with limited accuracy.
The reason the PID Control Emulator cannot precisely replicate the Ideal PID controller's results lies in the fact that declaring the 'persistent' variables is merely a programming technique, without taking into consideration for the true mathematics governing the dynamics of the Ideal PID controller:
Ideal PID controller: ,
where e (error signal) is the difference between the desired (setpoint) and measured outputs.
Additionally, while the ode45 solver employs an adaptive timestep integration method, the 'integral_error' term in the PID Control Emulator relies on the less accurate forward Euler method for numerical integration, known for its first-order accuracy. Furthermore, as mentioned by @Torsten and @Jan in this thread, the concept of a "previous timestep" in ODE45's adaptive timestep execution holds no meaningful relevance.
For now, you can enhance the accuracy of the results from the PID Control Emulator by adjusting the value of the delta time 'dt'. Determine the delta time so that it evenly divides the simulation time by the number of time intervals. The number of time intervals equals the number of elements in the computed time vector minus one, which can be checked by examining the size of the time vector, 't'.
%% Parameters
setpoint = 1; % Reference input
Kp = 0.75; % Proportional gain
Ki = 0.5; % Integral gain
Kd = 0.125; % Derivative gain
dt = 10/1080; % delta time (simulation time / number of time spacing)
%% Generate result from Ideal PID controller (requires Control System Toolbox)
Gp = tf(1, [1, 2, 1]); % plant
Gc = pid(Kp, Ki, Kd); % ideal PID controller
Gcl = feedback(Gc*Gp, 1); % closed-loop system
tt = linspace(0, 10, 1001);
y = step(Gcl, tt); % step response
%% Generate result from PID Control Emulator using ode45
tspan = [0 10]; % simulation time span
x0 = [0; 0]; % initial values of the state variables
[t, x] = ode45(@(t, x) systemDyn(t, x, pidEmulator(t, x, setpoint, Kp, Ki, Kd, dt)), tspan, x0);
size_t = size(t)
size_t = 1x2
1081 1
%% Plot results for comparison
plot(tt, y), hold on
plot(t, x(:,1)), grid on,
legend('Ideal PID controller', 'PID control emulator')
xlabel('Time'), ylabel('x_{1}'), title('Comparison')
%% System Dynamics
function [dx, y] = systemDyn(t, x, u)
% 'x' is the state variables
% 'u' is the control input signal
A = [0, 1; % state matrix
-1, -2];
B = [0; % input matrix
1];
C = [1, 0]; % output matrix
D = [0]; % direct matrix
% State-space model
dx = A*x + B*u;
y = C*x + D*u;
end
%% PID Control Emulator
function u = pidEmulator(t, x, setpoint, Kp, Ki, Kd, dt)
persistent integral_error prev_error prev_time;
if isempty(integral_error)
integral_error = 0;
prev_error = 0;
prev_time = 0;
end
error = setpoint - x(1); % feedback loop
integral_error = integral_error + error*(t - prev_time); % Euler method
derivative_error = (error - prev_error)/dt; % de/dt
prev_error = error; % previous error value
prev_time = t; % previous time value
% PID control equation
u = Kp*error + Ki*integral_error + Kd*derivative_error;
end
  3 Comments
Kamal
Kamal on 12 Mar 2024
@Sam Chak I simulated for 2000s and the initial oscilation was not captured. Is there anyway in the code to select desired decimation point of my data just like in the ToFile block of Simulink that I can select decimation point. Also, is there any means to save data generated to file instead of workspace or both with the code?
Sam Chak
Sam Chak on 12 Mar 2024
Hi @Kamal, I'm not familiar with the process of selecting the decimation point in the To File block in Simulink. I suggest copying and pasting the MATLAB code and creating a new question to address this issue. By doing so, you can seek assistance from experts in ode solvers who can provide insights and help resolve the problem.

Sign in to comment.

Categories

Find more on Programming in Help Center and File Exchange

Products


Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!