Is the MATLAB command lsim good for linearized state space models? - matlab

A state space model is on the form:
dx = Ax + Bu
y = Cx + Du
Nonlinear state space models which is linearized is on this form:
dΔx = AΔx + BΔu
Δy = CΔx + DΔu
Where:
Δx = [x1 - x10; x2 - x20; x3 - x30; .... ; xn - xn0]
Δu = [u1 - u10; u2 - u20; u3 - u30; .... ; um - um0]
The x10, x20, x30, xn0, u10, u20, u30, um0 is constants/initial values for the linearization.
So! The question is about the MATLAB command "lsim":
lsim (sys, u, t, x0)
In this case, sys is the A, B, C, D matrices from the lineraized state space model. u is the insignal vector, t is the time vector. But x0....can i say that x0 is x10, x20, x30, .... ,xn0?
Can I also say that u = u - u0 , and u0 is , u10 u10, u20, u30,... , um0 ?
Example:
u = linspace(5, 5, 100); % insignal 5
t = linspace(0, 100, 100); % 100 seconds
u0 = [0.2; -1.2; -3];
u = u - u0; %
x0 = [-2; 2; -1]
lsim (sys, u, t, x0)
This will results:
Δx = [x1 - 2; x2 + 2; x3 - 1]
Δu = [u1 + 0.2; u2 - 1.2; u3 - 3]
Am I right?

There is a readily available Simulink S-Function dsfunc.m which is the simulation of a State Space model, and which can be easily adapted for included linearized State Space matrices, changing at every time step.
Just build a simulink file dsfunc.slx and run it with the sim command sim('dsfunc') command.
The good part is the S-Function deals properly with the state, and you just adapt the State Space model each time, keeping the state from one iteration to another.
Also you can do it equally easily with a single for loop. Linearizing constant are included as shown.
function [t,u,x,y]=example2
% Start
dt=0.001;
N=1000;
n=2;
r=1;
t=(0:N-1)'*dt;
u=rand(N,r);
% First
[A,B,C,D,x0,y0]=ABCD(t(1),zeros(n,1),u(1,:)');
x(1,:)=x0';
y(1,:)=(C*x(1,:)'+D*u(1,:)'+y0)';
% Cycle
for i=2:N
[A,B,C,D,x0,y0]=ABCD(t(i),x(i-1,:)',u(i-1,:)');
x(i,:)=(A*x(i-1,:)'+B*u(i-1,:)'+x0)';
y(i,:)=(C*x(i,:)'+D*u(i,:)'+y0)';
end
plot(t,[u x y]);legend({'u' 'x1' 'x2' 'y'});
function [A,B,C,D,x0,y0]=ABCD(t,x,u)
A=[0.1 -0.9;0 0.1];
B=0.5*ones(2,1);
C=[1 1];
x0=[0];y0=[0];

Related

Solving a 4 ODE system in MATLAB using ode45

I am not very used to MATLAB and I'm trying to solve the following problem using MATLAB ode45, however, it's not working.
I was working on a problem in reaction engineering, using a Semi-Batch Reactor.
The reaction is given by
A + B ---> C + D
A is placed in the reactor and B is being continuously added into the reactor with a flowrate of v0 = 0.05 L/s. Initial volume is V0 = 5 L. The reaction is elementary. The reaction constant is k = 2.2 L/mol.s.
Initial Concentrations: for A: 0.05 M, for B: 0.025 M.
Performing a mole balance of each species in the reactor, I got the following 4 ODEs, and the expression of V (volume of the reactor is constantly increasing)
Solving this system and plotting the solution against time, I should get this
Note that plots of C(C) and C(D) are the same.
And let's set tau = v0/V.
Now for the MATLAB code part.
I have searched extensively online, and from what I've learned, I came up with the following code.
First, I wrote the code for the ODE system
function f = ODEsystem(t, y, tau, ra, y0)
f = zeros(4, 1);
f(1) = ra - tau*y(1);
f(2) = ra + tau*(y0(2) - y(2));
f(3) = -ra - tau*y(3);
f(4) = -ra - tau*y(4);
end
Then, in the command window,
t = [0:0.01:5];
v0 = 0.05;
V0 = 5;
k = 2.2;
V = V0 + v0*t;
tau = v0./V;
syms y(t);
ra = -k*y(1)*y(2);
y0 = [0.05 0.025 0 0];
[t, y] = ode45(#ODEsystem(t, y, tau, ra, y0), t, y0);
plot(t, y);
However, I get this...
Please if anyone could help me fix my code. This is really annoying :)
ra should not be passed as parameter but be computed inside the ODE system. V is likewise not a constant. Symbolic expressions should be used for formula transformations, not for numerical methods. One would also have to explicitly evaluate the symbolic expression at the wanted numerical values.
function f = ODEsystem(t, y, k, v0, V0, cB0)
f = zeros(4, 1);
ra = -k*y(1)*y(2);
tau = v0/(V0+t*v0);
f(1) = ra - tau*y(1);
f(2) = ra + tau*(cB0 - y(2));
f(3) = -ra - tau*y(3);
f(4) = -ra - tau*y(4);
end
Then use the time span of the graphic, start with all concentrations zero except for A, use the concentration B only for the inflow.
t = [0:1:500];
v0 = 0.05;
V0 = 5;
k = 2.2;
cB0 = 0.025;
y0 = [0.05 0 0 0];
[t, y] = ode45(#(t,y) ODEsystem(t, y, k, v0, V0, cB0), t, y0);
plot(t, y);
and get a good reproduction of the reference image

Solve simultaneous differential equations with imbedded functions and a parameter estimation

The aim is to solve the below equations and plot m with time, i.e. dm/dt
k is unknown and needs to be estimated. For the parameter estimation, the below values for m versus t can be used. This is a dummy dataset, as I would like to get an idea if this problem is solvable. If needed, an initial guesstimate for k can be provided 6e-5 m2/bar.hr.
I have added an initial idea for the code, but not sure if my implementation of the A(H) and P(H) functions in the odes is correct. Also I need a way to estimate for k whilst fitting to the provided m vs t data.
function dydt = diffunTAR(~,y,k, h, A_H, P_H, rho_h, rho_o, wo)
dydt = zeros (2,1);
D = 2.64/1000 %mm/1000 to convert to m
r=D/2
rho_o = 1320 %kg/m3
rho_h = 1000 % kg/m3
wo=648/1000000 %weight component 1 in mg converted to kg
h= 1.5/1000 %1.5mm expressed in m
function A_H= pi*(D/2)^2 + (2/r)*(1+(rho_o/rho_h*y(2)))*(wo/rho_o);
end
function P_H = 5004.6*y(2) + 150.39;
end
%dV/dt
dydt(1)= (k/h)* function A_H* function P_H;
%dH/dt
dydt(2)= (rho_h*k/wo*h)*function A_H*function P_H;
end
tspan = linspace(0,21*24); %time in hrs for 21 days
y0 = [0 6.4800e-04];
[t,y]=ode45(#(t,y) diffunTAR(t,y, k, h, A_H0, rho_h, rho_o, wo), tspan, y0);
updated code after help
function dydt = diffunTAR(~,y,k,h,rho_h,rho_o,wo,L,r)
dydt = zeros (2,1);
%dV/dt
dydt(1)= k/h* AH * PH;
%dH/dt
dydt(2)= (rho_h*k/wo*h) * AH * PH;
AH
PH
function PH
(5004.6*y(2))+150.3;
end
function AH
pi*(r^2)+(2/r)*(1+(rho_o/rho_h*y(2)))*(wo/rho_o);
setInitialConditions (AH, 2*pi*(r)*L+2*pi*(r)^2);
end
end
D = 2.64/1000 %mm/1000 to convert to m
r=D/2
L = 10.6/100 %cm/100 to convert to m
wo=648/1000000 %weight osmotic tablets in mg converted to kg
k=6e-5 %guess for permeability
h= 1.5/1000 %1.5mm expressed in m
rho_o = 1320 %kg/m3
rho_h = 1000 % kg/m3
tspan = linspace(0,21*24); %time in hrs for 21 days
y0 = [0 6.4800e-04];
[t,y]=ode45(#(t,y) diffunTAR(t,y,k,h,rho_h,rho_o,wo,L,r), tspan, y0);

Solving System of Second Order Ordinary Differential Equation in Matlab

Introduction
I am using Matlab to simulate some dynamic systems through numerically solving systems of Second Order Ordinary Differential Equations using ODE45. I found a great tutorial from Mathworks (link for tutorial at end) on how to do this.
In the tutorial the system of equations is explicit in x and y as shown below:
x''=-D(y) * x' * sqrt(x'^2 + y'^2)
y''=-D(y) * y' * sqrt(x'^2 + y'^2) + g(y)
Both equations above have form y'' = f(x, x', y, y')
Question
However, I am coming across systems of equations where the variables can not be solved for explicitly as shown in the example. For example one of the systems has the following set of 3 second order ordinary differential equations:
y double prime equation
y'' - .5*L*(x''*sin(x) + x'^2*cos(x) + (k/m)*y - g = 0
x double prime equation
.33*L^2*x'' - .5*L*y''sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
A single prime is first derivative
A double prime is second derivative
L, g, m, k, and C are given parameters.
How can Matlab be used to numerically solve a set of second order ordinary differential equations where second order can not be explicitly solved for?
Thanks!
Your second system has the form
a11*x'' + a12*y'' = f1(x,y,x',y')
a21*x'' + a22*y'' = f2(x,y,x',y')
which you can solve as a linear system
[x'', y''] = A\f
or in this case explicitly using Cramer's rule
x'' = ( a22*f1 - a12*f2 ) / (a11*a22 - a12*a21)
y'' accordingly.
I would strongly recommend leaving the intermediate variables in the code to reduce chances for typing errors and avoid multiple computation of the same expressions.
Code could look like this (untested)
function dz = odefunc(t,z)
x=z(1); dx=z(2); y=z(3); dy=z(4);
A = [ [-.5*L*sin(x), 1] ; [.33*L^2, -0.5*L*sin(x)] ]
b = [ [dx^2*cos(x) + (k/m)*y-g]; [-.33*L^2*C*cos(x) + .5*g*L*sin(x)] ]
d2 = A\b
dz = [ dx, d2(1), dy, d2(2) ]
end
Yes your method is correct!
I post the following code below:
%Rotating Pendulum Sym Main
clc
clear all;
%Define parameters
global M K L g C;
M = 1;
K = 25.6;
L = 1;
C = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
e_0 = 1;
ed_0 = 0;
theta_0 = 0;
thetad_0 = .5;
initialValues = [e_0, ed_0, theta_0, thetad_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .01;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#RotSpngHndl, timeSpan, initialValues);
%initialize variables
e = zeros(N,1);
ed = zeros(N,1);
theta = zeros(N,1);
thetad = zeros(N,1);
T = zeros(N,1);
V = zeros(N,1);
x = zeros(N,1);
y = zeros(N,1);
for i = 1:N
e(i) = z(i, 1);
ed(i) = z(i, 2);
theta(i) = z(i, 3);
thetad(i) = z(i, 4);
T(i) = .5*M*(ed(i)^2 + (1/3)*L^2*C*sin(theta(i)) + (1/3)*L^2*thetad(i)^2 - L*ed(i)*thetad(i)*sin(theta(i)));
V(i) = -M*g*(e(i) + .5*L*cos(theta(i)));
E(i) = T(i) + V(i);
end
figure(1)
plot(t, T,'r');
hold on;
plot(t, V,'b');
plot(t,E,'y');
title('Energy');
xlabel('time(sec)');
legend('Kinetic Energy', 'Potential Energy', 'Total Energy');
Here is function handle file for ode45:
function dz = RotSpngHndl(~, z)
% Define Global Parameters
global M K L g C
A = [1, -.5*L*sin(z(3));
-.5*L*sin(z(3)), (1/3)*L^2];
b = [.5*L*z(4)^2*cos(z(3)) - (K/M)*z(1) + g;
(1/3)*L^2*C*cos(z(3)) + .5*g*L*sin(z(3))];
X = A\b;
% return column vector [ed; edd; ed; edd]
dz = [z(2);
X(1);
z(4);
X(2)];

Code wont produce the value of a definite integral in MATLAB

I've had problems with my code as I've tried to make an integral compute, but it will not for the power, P2.
I've tried using anonymous function handles to use the integral() function on MATLAB as well as just using int(), but it will still not compute. Are the values too small for MATLAB to integrate or am I just missing something small?
Any help or advice would be appreciated to push me in the right direction. Thanks!
The problem in the code is in the bottom of the section labelled "Power Calculations". My integral also gets quite messy if that makes a difference.
%%%%%%%%%%% Parameters %%%%%%%%%%%%
n0 = 1; %air
n1 = 1.4; %layer 1
n2 = 2.62; %layer 2
n3 = 3.5; %silicon
L0 = 650*10^(-9); %centre wavelength
L1 = 200*10^(-9): 10*10^(-9): 2200*10^(-9); %lambda from 200nm to 2200nm
x = ((pi./2).*(L0./L1)); %layer phase thickness
r01 = ((n0 - n1)./(n0 + n1)); %reflection coefficient 01
r12 = ((n1 - n2)./(n1 + n2)); %reflection coefficient 12
r23 = ((n2 - n3)./(n2 + n3)); %reflection coefficient 23
t01 = ((2.*n0)./(n0 + n1)); %transmission coefficient 01
t12 = ((2.*n1)./(n1 + n2)); %transmission coefficient 12
t23 = ((2.*n2)./(n2 + n3)); %transmission coefficient 23
Q1 = [1 r01; r01 1]; %Matrix Q1
Q2 = [1 r12; r12 1]; %Matrix Q2
Q3 = [1 r23; r23 1]; %Matrix Q3
%%%%%%%%%%%% Graph of L vs R %%%%%%%%%%%
R = zeros(size(x));
for i = 1:length(x)
P = [exp(j.*x(i)) 0; 0 exp(-j.*x(i))]; %General Matrix P
T = ((1./(t01.*t12.*t23)).*(Q1*P*Q2*P*Q3)); %Transmission
T11 = T(1,1); %T11 value
T21 = T(2,1); %T21 value
R(i) = ((abs(T21./T11))^2).*100; %Percent reflectivity
end
plot(L1,R)
title('Percent Reflectance vs. wavelength for 2 Layers')
xlabel('Wavelength (m)')
ylabel('Reflectance (%)')
%%%%%%%%%%% Power Calculation %%%%%%%%%%
syms L; %General lamda
y = ((pi./2).*(L0./L)); %Layer phase thickness with variable Lamda
P1 = [exp(j.*y) 0; 0 exp(-j.*y)]; %Matrix P with variable Lambda
T1 = ((1./(t01.*t12.*t23)).*(Q1*P1*Q2*P1*Q3)); %Transmittivity matrix T1
I = ((6.16^(15))./((L.^(5)).*exp(2484./L) - 1)); %Blackbody Irradiance
Tf11 = T1(1,1); %New T11 section of matrix with variable Lambda
Tf2 = (((abs(1./Tf11))^2).*(n3./n0)); %final transmittivity
P1 = Tf2.*I; %Power before integration
L_initial = 200*10^(-9); %Initial wavelength
L_final = 2200*10^(-9); %Final wavelength
P2 = int(P1, L, L_initial, L_final) %Power production
I've refactored your code
to make it easier to read
to improve code reuse
to improve performance
to make it easier to understand
Why do you use so many unnecessary parentheses?!
Anyway, there's a few problems I saw in your code.
You used i as a loop variable, and j as the imaginary unit. It was OK for this one instance, but just barely so. In the future it's better to use 1i or 1j for the imaginary unit, and/or m or ii or something other than i or j as the loop index variable. You're helping yourself and your colleagues; it's just less confusing that way.
Towards the end, you used the variable name P1 twice in a row, and in two different ways. Although it works here, it's confusing! Took me a while to unravel why a matrix-producing function was producing scalars instead...
But by far the biggest problem in your code is the numerical problems with the blackbody irradiance computation. The term
L⁵ · exp(2484/L) - 1
for λ₀ = 200 · 10⁻⁹ m will require computing the quantity
exp(1.242 · 10¹⁰)
which, needless to say, is rather difficult for a computer :) Actually, the problem with your computation is two-fold. First, the exponentiation is definitely out of range of 64 bit IEEE-754 double precision, and will therefore result in ∞. Second, the parentheses are wrong; Planck's law should read
C/L⁵ · 1/(exp(D) - 1)
with C and D the constants (involving Planck's constant, speed of light, and Boltzmann constant), which you've presumably precomputed (I didn't check the values. I do know choice of units can mess these up, so better check).
So, aside from the silly parentheses error, I suspect the main problem is that you simply forgot to rescale λ to nm. Changing everything in the blackbody equation to nm and correcting those parentheses gives the code
I = 6.16^(15) / ( (L*1e+9)^5 * (exp(2484/(L*1e+9)) - 1) );
With this, I got a finite value for the integral of
P2 = 1.052916498836486e-010
But, again, you'd better double-check everything.
Note that I used quadgk(), because it's one of the better ones available on R2010a (which I'm stuck with), but you can just as easily replace this with integral() available on anything newer than R2012a.
Here's the code I ended up with:
function pwr = my_fcn()
% Parameters
n0 = 1; % air
n1 = 1.4; % layer 1
n2 = 2.62; % layer 2
n3 = 3.5; % silicon
L0 = 650e-9; % centre wavelength
% Reflection coefficients
r01 = (n0 - n1)/(n0 + n1);
r12 = (n1 - n2)/(n1 + n2);
r23 = (n2 - n3)/(n2 + n3);
% Transmission coefficients
t01 = (2*n0) / (n0 + n1);
t12 = (2*n1) / (n1 + n2);
t23 = (2*n2) / (n2 + n3);
% Quality factors
Q1 = [1 r01; r01 1];
Q2 = [1 r12; r12 1];
Q3 = [1 r23; r23 1];
% Initial & Final wavelengths
L_initial = 200e-9;
L_final = 2200e-9;
% plot reflectivity for selected lambda range
plot_reflectivity(L_initial, L_final, 1000);
% Compute power production
pwr = quadgk(#power_production, L_initial, L_final);
% Helper functions
% ========================================
% Graph of lambda vs reflectivity
function plot_reflectivity(L_initial, L_final, N)
L = linspace(L_initial, L_final, N);
R = zeros(size(L));
for ii = 1:numel(L)
% Transmission
T = transmittivity(L(ii));
% Percent reflectivity
R(ii) = 100 * abs(T(2,1)/T(1,1))^2 ;
end
plot(L, R)
title('Percent Reflectance vs. wavelength for 2 Layers')
xlabel('Wavelength (m)')
ylabel('Reflectance (%)')
end
% Compute transmittivity matrix for a single wavelength
function T = transmittivity(L)
% Layer phase thickness with variable Lamda
y = pi/2 * L0/L;
% Matrix P with variable Lambda
P1 = [exp(+1j*y) 0
0 exp(-1j*y)];
% Transmittivity matrix T1
T = 1/(t01*t12*t23) * Q1*P1*Q2*P1*Q3;
end
% Power for a specific wavelength. Note that this function
% accepts vector-valued wavelengths; needed for quadgk()
function pwr = power_production(L)
pwr = zeros(size(L));
for ii = 1:numel(L)
% Transmittivity matrix
T1 = transmittivity(L(ii));
% Blackbody Irradiance
I = 6.16^(15) / ( (L(ii)*1e+9)^5 * (exp(2484/(L(ii)*1e+9)) - 1) );
% final transmittivity
Tf2 = abs(1/T1(1))^2 * n3/n0;
% Power before integration
pwr(ii) = Tf2 * I;
end
end
end

The Fastest Method of Solving System of Non-linear Equations in MATLAB

Assume we have three equations:
eq1 = x1 + (x1 - x2) * t - X == 0;
eq2 = z1 + (z1 - z2) * t - Z == 0;
eq3 = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1 == 0;
while six of known variables are:
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
So we are looking for three unknown variables that are:
X , Z and t
I wrote two method to solve it. But, since I need to run these code for 5.7 million data, it become really slow.
Method one (using "solve"):
tic
S = solve( eq1 , eq2 , eq3 , X , Z , t ,...
'ReturnConditions', true, 'Real', true);
toc
X = double(S.X(1))
Z = double(S.Z(1))
t = double(S.t(1))
results of method one:
X = 316190;
Z = 234060;
t = -2.9280;
Elapsed time is 0.770429 seconds.
Method two (using "fsolve"):
coeffs = [a,b,x1,x2,z1,z2]; % Known parameters
x0 = [ x2 ; z2 ; 1 ].'; % Initial values for iterations
f_d = #(x0) myfunc(x0,coeffs); % f_d considers x0 as variables
options = optimoptions('fsolve','Display','none');
tic
M = fsolve(f_d,x0,options);
toc
results of method two:
X = 316190; % X = M(1)
Z = 234060; % Z = M(2)
t = -2.9280; % t = M(3)
Elapsed time is 0.014 seconds.
Although, the second method is faster, but it still needs to be improved. Please let me know if you have a better solution for that. Thanks
* extra information:
if you are interested to know what those 3 equations are, the first two are equations of a line in 2D and the third equation is an ellipse equation. I need to find the intersection of the line with the ellipse. Obviously, we have two points as result. But, let's forget about the second answer for simplicity.
My suggestion it's to use the second approce,which it's the recommended by matlab for nonlinear equation system.
Declare a M-function
function Y=mysistem(X)
%X(1) = X
%X(2) = t
%X(3) = Z
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
Y(1,1) = x1 + (x1 - x2) * X(2) - X(1);
Y(2,1) = z1 + (z1 - z2) * X(2) - X(3);
Y(3,1) = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1;
end
Then for solving use
x0 = [ x2 , z2 , 1 ];
M = fsolve(#mysistem,x0,options);
If you may want to reduce the default precision by changing StepTolerance (default 1e-6).
Also for more increare you may want to use the jacobian matrix for greater efficencies.
For more reference take a look in official documentation:
fsolve Nonlinear Equations with Analytic Jacobian
Basically giving the solver the Jacobian matrix of the system(and special options) you can increase method efficency.