I want to plot the step response. I know that I can use step function with state space equations, but I try to get same results using plot function. Here is my sample of code:
for i=1:201
u(i) = 1;
x1(i+1) = (-(b/J)*x1(i) + (K/J)*x2(i));
x2(i+1) = (-(K/L)*x1(i) - (R/L)*x2(i) + (1/L)*u(i));
y(i) = x1(i);
end
and this is the state space equations:
A = [-b/J K/J
-K/L -R/L];
B = [0
1/L];
C = [1 0];
D = 0;
If i do:
t = 0:1:200;
plot(t, y)
it is not working and I want to have the same results like the step function below:
sys = ss(A,B,C,D);
step(sys)
You can find my state space equation here.
The reason for the mismatch is that sys is a continuous time model, whereas the computation of y treats it as a discrete-time system.
The following is a way of estimating the step-response of a continuous-time system in the discrete-time domain:
% Given from the problem statement
A = [-b/J K/J
-K/L -R/L];
B = [0
1/L];
C = [1 0];
D = 0;
% this is your continuous-time model
sys = ss(A,B,C,D);
% define the sample rate of the equivalent discrete-time model
Ts = 1/10;
% this needs to be something smaller than the time-constants in your model,
% so that you have enough resolution to represent the continuous-time
% signal.
% convert the system to the equivalent discrete-time model
sysd = c2d(sys,Ts);
% define how long a step response you'd like to compute
T = 7;
% this should be long enough to cover the length of the step response
t = 0:Ts:T; % time-grid for the plot
nSmp = length(t); % total number of samples to be computed
% initializations
y = NaN(1, nSmp); % output vector
u = ones(1, nSmp); % unit step input
X = [0; 0]; % state vector, initialized to 0
% compute the samples of the step-response
% (i prefer to use vectorized form to keep the code concise)
for i=1:nSmp
y(i) = sysd.C * X + sysd.D * u(i);
X = sysd.A * X + sysd.B * u(i);
end
% plot continous-time step response
figure;
step(sys);
% plot simulated discrete-time step response
figure;
plot(t, y, 'r')
xlabel('Time (s)');
ylabel('Amplitude');
title('Simulated Step Response');
Related
I've spent quite some time trying to simulate a simple SISO system using two approaches:
1) Using lsim() in MATLAB
2) By writing down the difference equations myself and iterate over them in a loop.
I was never able to get the same simulation results from both approaches, and I have no idea what I am doing wrong.
I stacked my code in a single m-file so it's easier to follow. Here is the code:
function main()
clear all
clc
simulateUsing_lsim()
simulateUsing_loop()
end
%%%%%% Simulating using lsim %%%%%%%
function simulateUsing_lsim()
% Define the continuous-time closed-loop system
P = getContPlant();
[Kp,Ki,Kd] = get_PIDgains();
C = pid(Kp,Ki,Kd);
clSys_cont = feedback(C*P,1);
% Define the discrete-time closed-loop system
hk = get_sampling_time();
clSys_disc = c2d(clSys_cont,hk);
% Generate the reference signal and the time vector
[r,t] = getReference(hk);
%% Simulate and plot using lsim
figure
lsim(clSys_disc,r,t)
%% Finding and plotting the error
y = lsim(clSys_disc,r);
e = r - y;
figure
p = plot(t,e,'b--');
set(p,'linewidth',2)
legend('error')
xlabel('Time (seconds)')
ylabel('error')
% xlim([-.1 10.1])
end
%%%%%% Simulating using loop iteration (difference equations) %%%%%%%
function simulateUsing_loop()
% Get the cont-time ol-sys
P = getContPlant();
% Get the sampling time
hk = get_sampling_time();
% Get the disc-time ol-sys in SS representation
P_disc = ss(c2d(P,hk));
Ad = P_disc.A;
Bd = P_disc.B;
Cd = P_disc.C;
% Get the PID gains
[Kp,Ki,Kd] = get_PIDgains();
% Generate the reference signal and the time vector
[r,t] = getReference(hk);
%% Perform the system simulation
x = [0 0]'; % Set initial states
e = 0; % Set initial errors
integral_sum = 0; % Set initial integral part value
for i=2:1:length(t)
% Calculate the output signal "y"
y(:,i) = Cd*x;
% Calculate the error "e"
e(:,i) = y(:,i) - r(i);
% Calculate the control signal vector "u"
integral_sum = integral_sum + Ki*hk*e(i);
u(:,i) = Kp*e(i) + integral_sum + (1/hk)*Kd*(e(:,i)-e(:,i-1));
% Saturation. Limit the value of u withing the range [-tol tol]
% tol = 100;
% if abs(u(:,i)) > tol
% u(:,i) = tol * abs(u(:,i))/u(:,i);
% else
% end
% Calculate the state vector "x"
x = Ad*x + Bd*u(:,i); % State transitions to time n
end
%% Subplots
figure
plot(t,y,'b',t,r,'g--')
%% Plotting the error
figure
p = plot(t,e,'r');
set(p,'linewidth',2)
legend('error')
xlabel('Time (seconds)')
ylabel('error')
end
function P = getContPlant()
s = tf('s');
P = 1/(s^2 + 10*s + 20);
end
function [Kp,Ki,Kd] = get_PIDgains()
Kp = 350;
Ki = 300;
Kd = 50;
end
function hk = get_sampling_time()
hk = 0.01;
end
function [r,t] = getReference(hk)
[r,t] = gensig('square',4,10,hk);
end
I got the plant model P and its PID controller from this page (see equation 10), where the system is simulated against a step reference and the result looks pretty much exactly like the lsim() result (just for a single step peak).
However, the result of simulating the system using lsim() is this:
whereas, using the for loop, I got this performance:
I would highly appreciate any help or clarification why I am getting different results.
I'm trying to plot the following equation (let's call it "Equation 1"):
This is the code I'm testing:
clear all;
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
x = xl : dx : xr; % generate the grid point
u_ex = zeros(J+1,Nt);
for n = 1:Nt
t = n*dt; % current time
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(100 , 1);
for k= 1:100
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) = suma(k) * exp(-((2*k-1)^2) *pi*pi*t) * cos(2*k-1)*pi*xj;
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
tt = dt : dt : Nt*dt;
figure(1)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
The problem is that all I get is a flat surface:
Equation 1 is suppossed to be the solution of the following parabolic partial differential equation with boundary values:
And after getting the numerical solution, it should look like this:
This plot gets the right values at the boundaries x = 0 and x = 1. The plot of Equation 1 doesn't have those values at the boundaries.
My complete .m code (that plots both the numerical solution and Equation 1) is:
clear all; % clear all variables in memory
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
mu = dt/(dx)^2;
if mu > 0.5 % make sure dt satisy stability condition
error('mu should < 0.5!')
end
% Evaluate the initial conditions
x = xl : dx : xr; % generate the grid point
% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);
% Find the approximate solution at each time step
for n = 1:Nt
t = n*dt; % current time
% boundary condition at left side
gl = 0;
% boundary condition at right side
gr = 0;
for j=2:J
if n==1 % first time step
u(j,n) = j;
else % interior nodes
u(j,n)=u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
end
end
u(1,n) = gl; % the left-end point
u(J+1,n) = gr; % the right-end point
% calculate the analytic solution
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(100 , 1);
for k= 1:100
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) = suma(k) * exp(-((2*k-1)^2) *pi*pi*t) * cos(2*k-1)*pi*xj;
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(gray); % draw gray figure
surf(x,tt, u'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')
figure(2)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')
maxerr=max(max(abs(u-u_ex))),
The code is taken from the book "Computational Partial Differential Equations Using MATLAB" by Yi-Tung Chen, Jichun Li, chapter 2, exercise 3.
In short: I'm not asking about the differential equation or the boundary problem, I want to know is: Why am I getting a flat surface when plotting Equation 1? Am I missing a parenthesis?
I do not want to use the symsum function because it never stop the script execution and I want to learn how to plot Equation 1 with no using symsum.
I've tested this code with Matlab R2008b and Octave 4.2.1. I got the same results (even with sums of 1000, 10000 and 50000 terms in the for loop with the k variable).
Edit!
Thanks, Steve!
I was missing a couple of parenthesis near the cosine, the right code is:
clear all; % clear all variables in memory
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
mu = dt/(dx)^2;
if mu > 0.5 % make sure dt satisy stability condition
error('mu should < 0.5!')
end
% Evaluate the initial conditions
x = xl : dx : xr; % generate the grid point
% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);
% Find the approximate solution at each time step
for n = 1:Nt
t = n*dt; % current time
% boundary condition at left side
gl = 0;
% boundary condition at right side
gr = 0;
for j=2:J
if n==1 % first time step
u(j,n) = j;
else % interior nodes
u(j,n)=u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
end
end
u(1,n) = gl; % the left-end point
u(J+1,n) = gr; % the right-end point
% calculate the analytic solution
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(1000 , 1);
for k= 1:1000
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) *= exp(-((2*k-1)^2) *pi*pi*t) * cos((2*k-1)*pi*xj);
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(gray); % draw gray figure
surf(x,tt, u'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')
figure(2)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')
Now my Equation 1 looks much better:
Also Steve was right when pointing out that my numerical solution may be wrong. I didn't notice that the boundary values are for the derivatives of my function, not the actual values of the function. I'll ask my teacher about this.
Edit2!
Ok, I got it. To calculate the derivatives at the boundaries you have to use hint 2.21 in the same book:
% hint 2.21 given by the book
% it is better to calculate the boundary values after calculating the inner points inside the for j = 1:m loop because you will need them:
u(1, n) = u(2, n) - dx * gl; % the left-end point
u(J+1,n) = u(J, n) + dx * gr; % the right-end point
Now my numerical solution looks like my analytic solution :D
Matlab R2008b can't recognize the *= operator that Octave does. I'm not tested this operator in other versions of Matlab because I'm too poor.
Yvon: I think the analytical solution formula comes from the real part of a Fourier expansion, but authors don't tell how they got it.
I am coding a Gaussian Process regression algorithm. Here is the code:
% Data generating function
fh = #(x)(2*cos(2*pi*x/10).*x);
% range
x = -5:0.01:5;
N = length(x);
% Sampled data points from the generating function
M = 50;
selection = boolean(zeros(N,1));
j = randsample(N, M);
% mark them
selection(j) = 1;
Xa = x(j);
% compute the function and extract mean
f = fh(Xa) - mean(fh(Xa));
sigma2 = 1;
% computing the interpolation using all x's
% It is expected that for points used to build the GP cov. matrix, the
% uncertainty is reduced...
K = squareform(pdist(x'));
K = exp(-(0.5*K.^2)/sigma2);
% upper left corner of K
Kaa = K(selection,selection);
% lower right corner of K
Kbb = K(~selection,~selection);
% upper right corner of K
Kab = K(selection,~selection);
% mean of posterior
m = Kab'*inv(Kaa+0.001*eye(M))*f';
% cov. matrix of posterior
D = Kbb - Kab'*inv(Kaa + 0.001*eye(M))*Kab;
% sampling M functions from from GP
[A,B,C] = svd(Kaa);
F0 = A*sqrt(B)*randn(M,M);
% mean from GP using sampled points
F0m = mean(F0,2);
F0d = std(F0,0,2);
%%
% put together data and estimation
F = zeros(N,1);
S = zeros(N,1);
F(selection) = f' + F0m;
S(selection) = F0d;
% sampling M function from posterior
[A,B,C] = svd(D);
a = A*sqrt(B)*randn(N-M,M);
% mean from posterior GPs
Fm = m + mean(a,2);
Fmd = std(a,0,2);
F(~selection) = Fm;
S(~selection) = Fmd;
%%
figure;
% show what we got...
plot(x, F, ':r', x, F-2*S, ':b', x, F+2*S, ':b'), grid on;
hold on;
% show points we got
plot(Xa, f, 'Ok');
% show the whole curve
plot(x, fh(x)-mean(fh(x)), 'k');
grid on;
I expect to get some nice figure where the uncertainty of unknown data points would be big and around sampled data points small. I got an odd figure and even odder is that the uncertainty around sampled data points is bigger than on the rest. Can someone explain to me what I am doing wrong? Thanks!!
There are a few things wrong with your code. Here are the most important points:
The major mistake that makes everything go wrong is the indexing of f. You are defining Xa = x(j), but you should actually do Xa = x(selection), so that the indexing is consistent with the indexing you use on the kernel matrix K.
Subtracting the sample mean f = fh(Xa) - mean(fh(Xa)) does not serve any purpose, and makes the circles in your plot be off from the actual function. (If you choose to subtract something, it should be a fixed number or function, and not depend on the randomly sampled observations.)
You should compute the posterior mean and variance directly from m and D; no need to sample from the posterior and then obtain sample estimates for those.
Here is a modified version of the script with the above points fixed.
%% Init
% Data generating function
fh = #(x)(2*cos(2*pi*x/10).*x);
% range
x = -5:0.01:5;
N = length(x);
% Sampled data points from the generating function
M = 5;
selection = boolean(zeros(N,1));
j = randsample(N, M);
% mark them
selection(j) = 1;
Xa = x(selection);
%% GP computations
% compute the function and extract mean
f = fh(Xa);
sigma2 = 2;
sigma_noise = 0.01;
var_kernel = 10;
% computing the interpolation using all x's
% It is expected that for points used to build the GP cov. matrix, the
% uncertainty is reduced...
K = squareform(pdist(x'));
K = var_kernel*exp(-(0.5*K.^2)/sigma2);
% upper left corner of K
Kaa = K(selection,selection);
% lower right corner of K
Kbb = K(~selection,~selection);
% upper right corner of K
Kab = K(selection,~selection);
% mean of posterior
m = Kab'/(Kaa + sigma_noise*eye(M))*f';
% cov. matrix of posterior
D = Kbb - Kab'/(Kaa + sigma_noise*eye(M))*Kab;
%% Plot
figure;
grid on;
hold on;
% GP estimates
plot(x(~selection), m);
plot(x(~selection), m + 2*sqrt(diag(D)), 'g-');
plot(x(~selection), m - 2*sqrt(diag(D)), 'g-');
% Observations
plot(Xa, f, 'Ok');
% True function
plot(x, fh(x), 'k');
A resulting plot from this with 5 randomly chosen observations, where the true function is shown in black, the posterior mean in blue, and confidence intervals in green.
I am trying to implement the finite difference method in matlab. I did some calculations and I got that y(i) is a function of y(i-1) and y(i+1), when I know y(1) and y(n+1). However, I don't know how I can implement this so the values of y are updated the right way. I tried using 2 fors, but it's not going to work that way.
EDIT
This is the script and the result isn't right
n = 10;
m = n+1;
h = 1/m;
x = 0:h:1;
y = zeros(m+1,1);
y(1) = 4;
y(m+1) = 6;
s = y;
for i=2:m
y(i) = y(i-1)*(-1+(-2)*h)+h*h*x(i)*exp(2*x(i));
end
for i=m:-1:2
y(i) = (y(i) + (y(i+1)*(2*h-1)))/(3*h*h-2);
end
The equation is:
y''(x) - 4y'(x) + 3y(x) = x * e ^ (2x),
y(0) = 4,
y(1) = 6
Thanks.
Consider the following code. The central differential quotient is discretized.
% Second order diff. equ.
% y'' - 4*y' + 3*y = x*exp(2*x)
% (y(i+1)-2*y(i)+y(i-1))/h^2-4*(y(i+1)-y(i-1))/(2*h) + 3*y(i) = x(i)*exp(2*x(i));
The solution region is specified.
x = (0:0.01:1)'; % Solution region
h = min(diff(x)); % distance
As said in my comment, using this method, all points have to be solved simultaneously. Therefore, above numerical approximation of the equation is transformed in a linear system of euqations.
% System of equations
% Matrix of coefficients
A = zeros(length(x));
A(1,1) = 1; % known solu for first point
A(end,end) = 1; % known solu for last point
% y(i) y'' y
A(2:end-1,2:end-1) = A(2:end-1,2:end-1)+diag(repmat(-2/h^2+3,[length(x)-2 1]));
% y(i-1) y'' -4*y'
A(1:end-1,1:end-1) = A(1:end-1,1:end-1)+diag(repmat(1/h^2+4/(2*h),[length(x)-2 1]),-1);
% y(i+1) y'' -4*y'
A(2:end,2:end) = A(2:end,2:end)+diag(repmat(1/h^2-4/(2*h),[length(x)-2 1]),+1);
With the rhs of the differential equation. Note that the known values are calculated by 1 in the matrix and the actual value in the solution vector.
Y = x.*exp(2*x);
Y(1) = 4; % known solu for first point
Y(end) = 6; % known solu for last point
y = A\Y;
Having an equation to approximate the first order derivative (see above) you can verify the solution. (note, ddx2 is an own function)
f1 = ddx2(x,y); % first derivative (own function)
f2 = ddx2(x,f1); % second derivative (own function)
figure;
plot(x,y);
saveas(gcf,'solu1','png');
figure;
plot(x,f2-4*f1+3*y,x,x.*exp(2*x),'ko');
ylim([0 10]);
legend('lhs','rhs','Location','nw');
saveas(gcf,'solu2','png');
I hope the solution shown below is correct.
Lets say I have a simple logistic equation
dx/dt = 2ax(1 - x/N)
where N is the carrying capacity, a is some growth rate, and both a and N are parameters I'd like to vary.
So what I want to do is to plot a 3D graph of my fixed point and the two parameters.
I understand how to find a fixed point of a single parameter.
Here is my sample code
function xprime = MyLogisticFunction(t,X) %% The ODE
% Parameters
N = 10 % Carrying Capacity
a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
Next my solver
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
[t,x]=ode45(#MyLogisticFunction,tspan,x0);
clf
x(end,1) % This gives me the fixed point for the parameters above.
So my real question is, how do I put a for loop across two functions, that allows me to vary a and N, so that I can plot out a 3D graph of a and N and my fixed point x*.
I've tried combining both functions into one .m file but it does not seem to work
You need to pass the parameters to your function:
function xprime = MyLogisticFunction(t,X,a,N) %% The ODE
% Parameters (passed as function arguments)
% N = 10 % Carrying Capacity
% a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
and then when you call the ode solver:
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
a = 0.1:0.1:1; % or whatever
N = 1:10; % or whatever
x_end = zeros(length(a),length(N));
for ii = 1:length(a)
for jj = 1:length(N)
[t,x]=ode45(#(t,X)MyLogisticFunction(t,X,a(ii),N(jj)),tspan,x0);
x_end(ii,jj) = x(end,1);
end
end