Time Varying Transfer Function - matlab

I have a discrete transfer function whose numerator and denominator are coming from an input port. At every sample time these numerator and denominator vectors change.
E.g.
# t == 0
den == [1 0 -1]
# t == 1
den == [1 0 0 -1]
What do I have to do in order for the transfer function to work with this?
I have tried:
Having a variable length signal.
SIMULINK did not like this and refused to run, complaining that the discrete transfer function block could not handle variable sized input.
Padding the vector with many leading zeros
This led to periodic spikes in the signal. Additionally, Simulink does not let you do this if you enter the values by hand, rather than as an input, so I don't think this is the way to do it either.
Any help is much appreciated.

This is solved trivially with a single Simulink S-Function file sfuntvf.m, like this.
In there, a custom fixed vector state with y and us history is saved, and the time varying part is simply applied over the time history (depicted in cyan and yellow); here a FIR Filter with a random order (depicted in magenta).
Other build-in implementations shall consider the sucessive initial conditions between calls, and require the verification of the initial condition structure. The shown implementation is the easiest to deploy and understand.
The A and B vectors can be modified accordingly.
function [sys,x0,str,ts] = sfuntvf(t,x,u,flag)
N=20;
n=randi(N-2)+1;
A=[1;zeros(N-1,1)];
B=[1/n*ones(n,1);zeros(N-n,1)];
switch flag,
case 0, [sys,x0,str,ts] = mdlInitializeSizes(N);
case 2, sys = mdlUpdate(t,x,u,N,A,B);
case 3, sys = mdlOutputs(t,x,u,N,n);
case 9, sys = [];
otherwise DAStudio.error('Simulink:blocks:unhandledFlag',num2str(flag));
end
function [sys,x0,str,ts] = mdlInitializeSizes(N)
sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 2*N;
sizes.NumOutputs = 2;
sizes.NumInputs = 1;
sizes.DirFeedthrough = 0;
sizes.NumSampleTimes = 1;
sys = simsizes(sizes);
x0 = zeros(2*N,1);
str = [];
ts = [1 0];
function sys = mdlUpdate(t,x,u,N,A,B)
un=x(1:N,1);
yn=x(N+1:2*N,1);
y=-A(2:end)'*yn(2:end)+B'*un;
sys = [u;un(1:end-1);y;yn(1:end-1)];
function sys = mdlOutputs(t,x,u,N,n)
sys = [x(N+1);n];

Related

Setting up u vector when using lsim

I have a frustrating error when using Matlab where I'm trying to simulate a continuous time system in discrete time.
Ts = 0.01;
A=[-0.313 0 56.7;
0 56.7 0;
-0.0139 0 0.426];
B = [0.232; 0; 0.0203];
C = [0 1 0];
D = 0;
SYSC = ss(A,B,C,D);
SYSD = c2d(SYSC,Ts);
t = linspace(0,10,10/0.01)';
u = zeros(1000,3);
u(:) = 0.2;
lsim(SYSD,u,t);
I am getting the error:
When simulating the response to a specific input signal, the
input data U must be a matrix with as many rows as samples in
the time vector T, and as many columns as input channels
What is meant by input channels here? Overall I'm not sure how I can fix this error. I have a set time for which I want the simulation to run but I do not know how to set up my vector of inputs correctly. I am modeling three states.
If your input matrix is B = [0.232; 0; 0.0203] and is a 3-by-1 column vector, then the linear system given by A*x + B*u only has one control input.
So u should be:
u = zeros(1000,1);
u(:) = 0.2;
And you can simulate the discrete time system using
lsim(SYSD,u,[]);
Note that you don't need to define the time vector in lsim for the discrete simulation because u is sampled at the same rate as SYSD.
If the B matrix was 3-by-3, then you would need to have 3 control inputs.

lsim command with initial condition

while using the lsim command of matlab I found out that the initial condition in my program doesn't affect the simulation's output.
y = lsim(F,input,time,x0);
Where F is a transfer function, and x0 the initial condition that I calculate with the state-space model.
The value of x0 doesn't affect y, I even replaced it with different numbers and the simulation's output y is always the same.
I'm actually trying to get the parameters of the tf from a real measured output. So that's the main part of the code:
tsmpl = 1e-2;
Sizeof_y = length(y_real);
R = zeros(Sizeof_y,3);
R(1,:) = [y_real(1) input(1) 0];
for i=2:Sizeof_y
R(i,:)=[y_real(i-1) input(i) input(i-1)];
end
p = pinv(R)*y_real;
z = tf('z',tsmpl);
num = p(2)*z+p(3);
den = z-p(1);
F = num/den;
sys = ss(F);
x0 = (y_real(1) - (sys.d*sig(1)))*pinv(sys.c);
y = lsim(F,input,time,x0);
y_real is the measured output. It's a vector of complexe numbers.
time is the time vector that represents the duration of the process. (given by the measurment) time = 6:0.01:24
input represents the test signal which is a vector defined like this:
Size_input = length(time);
Size_sine = length(halftime) ; %halftime is the duration of the exitation also known from the measurment
input = zeros(Size_input,1);
input(1:Size_sine) = complex(30);
Vectors y_real, time, and input have the same length.
I would be thankful for any idea :))

Setting up a matrix of time and space for a function

I'm writing a program in matlab to observe how a function evolves in time. I'd like to set up a matrix that fills its first row with the initial function, and progressively fills more rows based off of a time derivative (that's dependent on the spatial derivative). The function is arbitrary, the program just needs to 'evolve' it. This is what I have so far:
xleft = -10;
xright = 10;
xsampling = 1000;
tmax = 1000;
tsampling = 1000;
dt = tmax/tsampling;
x = linspace(xleft,xright,xsampling);
t = linspace(0,tmax,tsampling);
funset = [exp(-(x.^2)/100);cos(x)]; %Test functions.
funsetvel = zeros(size(funset)); %The functions velocities.
spacetimevalue1 = zeros(length(x), length(t));
spacetimevalue2 = zeros(length(x), length(t));
% Loop that fills the first functions spacetime matrix.
for j=1:length(t)
funsetvel(1,j) = diff(funset(1,:),x,2);
spacetimevalue1(:,j) = funsetvel(1,j)*dt + funset(1,j);
end
This outputs the error, Difference order N must be a positive integer scalar. I'm unsure what this means. I'm fairly new to Matlab. I will exchange the Euler-method for another algorithm once I can actually get some output along the proper expectation. Aside from the error associated with taking the spatial derivative, do you all have any suggestions on how to evaluate this sort of process? Thank you.

Solving differential equation for a single time in loop with matlab

I have a Mechanical system with following equation:
xdot = Ax+ Bu
I want to solve this equation in a loop because in every step I need to update u but solvers like ode45 or lsim solving the differential equation for a time interval.
for i = 1:10001
if x(i,:)>= Sin1 & x(i,:)<=Sout2
U(i,:) = Ueq - (K*(S/Alpha))
else
U(i,:) = Ueq - (K*S)
end
% [y(i,:),t,x(i+1,:)]=lsim(sys,U(i,:),(time=i/1000),x(i,:));
or %[t,x] = ode45(#(t,x)furuta(t,x,A,B,U),(time=i/1000),x)
end
Do I have another ways to solve this equation in a loop for a single time(Not single time step).
There are a number of methods for updating and storing data across function calls.
For the ODE suite, I've come to like what is called "closures" for doing that.
A closure is basically a nested function accessing or modifying a variable from its parent function.
The code below makes use of this feature by wrapping the right-hand side function passed to ode45 and the 'OutputFcn' in a parent function called odeClosure().
You'll notice that I am using logical-indexing instead of an if-statement.
Vectors in if-statements will only be true if all elements are true and vice-versa for false.
Therefore, I create a logical array and use it to make the denominator either 1 or Alpha depending on the signal value for each row of x/U.
The 'OutputFcn' storeU() is called after a successful time step by ode45.
The function grows the U storage array and updates it appropriately.
The array U will have the same number of columns as the number of solution points requested by tspan (12 in this made-up example).
If a successful full step leaps over any requested points, the function is called with intermediate all requested times and their associated solution values (so x may be rectangular and not just a vector); this is why I used bsxfun in storeU and not in rhs.
Example function:
function [sol,U] = odeClosure()
% Initilize
% N = 10 ;
A = [ 0,0,1.0000,0; 0,0,0,1.0000;0,1.3975,-3.7330,-0.0010;0,21.0605,-6.4748,-0.0149];
B = [0;0;0.6199;1.0752 ] ;
x0 = [11;11;0;0];
K = 100;
S = [-0.2930;4.5262;-0.5085;1.2232];
Alpha = 0.2 ;
Ueq = [0;-25.0509;6.3149;-4.5085];
U = Ueq;
Sin1 = [-0.0172;-4.0974;-0.0517;-0.2993];
Sout2 = [0.0172 ; 4.0974; 0.0517; 0.2993];
% Solve
options = odeset('OutputFcn', #(t,x,flag) storeU(t,x,flag));
sol = ode45(#(t,x) rhs(t,x),[0,0.01:0.01:0.10,5],x0,options);
function xdot = rhs(~,x)
between = (x >= Sin1) & (x <= Sout2);
uwork = Ueq - K*S./(1 + (Alpha-1).*between);
xdot = A*x + B.*uwork;
end
function status = storeU(t,x,flag)
if isempty(flag)
% grow array
nAdd = length(t) ;
iCol = size(U,2) + (1:nAdd);
U(:,iCol) = 0 ;
% update U
between = bsxfun(#ge,x,Sin1) & bsxfun(#le,x,Sout2);
U(:,iCol) = Ueq(:,ones(1,nAdd)) - K*S./(1 + (Alpha-1).*between);
end
status = 0;
end
end

Matlab ode solvers: changing state and specified time

I am solving a set of ODEs (dy/dt) at t=0, all initial conditions t=0 y_0=(0,0,0). Can I add some number to the y values at different times (e.g., at t=10, y1 should be added to that number; at t=20, y2 should be added to that number, etc.) and solve the equations?
Inserting large discontinuities in your ODE in the way you suggest (and the way illustrated by #macduff) can lead to less precision and longer computation times (especially with ode45 - ode15s might be a better option or at least make sure that your absolute and relative tolerances are suitable). You've effectively produced a very stiff system. If you want to add some number to the ODEs starting at a specific time keep in mind that the solver only evaluates these equations at specific points in time of its own choosing. (Don't be mislead by the fact that you can obtain fixed step-size outputs by specifying tspan as more than two elements – all of Matlab's solvers are variable step-size solvers and choose their true steps based on error criteria.)
A better option is to integrate the system piecewise and append the resultant outputs from each run together:
% t = 0 to t = 10, pass parameter a = 0 to add to ODEs
a = 0;
tspan = [0 10];
[T,Y] = ode45(#(t,y)myfun(t,y,a),tspan,y_0);
% t = 10 to t = 20, pass parameter a = 10 to add to ODEs
a = 10;
[t,y] = ode45(#(t,y)myfun(t,y,a),tspan+T(end),Y(end,:));
T = [T;t(2:end)];
Y = [Y;y(2:end,:)];
% t = 20 to t = 30, pass parameter a = 20 to add to ODEs
a = 20;
[t,y] = ode45(#(t,y)myfun(t,y,a),tspan+T(end),Y(end,:));
T = [T;t(2:end)];
Y = [Y;y(2:end,:)];
The Matlab editor may complain about the array T and Y not being preallocated and/or growing, but it's fine in this case as they're growing in large chunks only a few times. Alternatively, if you want fixed output step-sizes, you can do this:
dt = 0.01;
T = 0:dt:30;
Y = zeros(length(T),length(y_0));
% t = 0 to t = 10, pass parameter a = 0 to add to ODEs
a = 0;
[~,Y(1:10/dt+1,:)] = ode45(#(t,y)myfun(t,y,a),T(1:10/dt+1),y_0);
% t = 10 to t = 20, pass parameter a = 10 to add to ODEs
a = 10;
[~,Y(10/dt+1:20/dt+1,:)] = ode45(#(t,y)myfun(t,y,a),T(10/dt+1:20/dt+1),Y(10/dt+1,:));
% t = 20 to t = 30, pass parameter a = 20 to add to ODEs
a = 20;
[~,Y(20/dt+1:end,:)] = ode45(#(t,y)myfun(t,y,a),T(20/dt+1:end),Y(20/dt+1,:));
One could easily convert both of the above blocks of code to more compact for loops if desired.
In both cases your ODE function myfun incorporates the parameter a this way:
function ydot = myfun(t,y,a)
y(1) = ... % add a however you like
...
Ok, like Simon McKenzie says we really need more info on your urgent issue, but I think I can help. From what you've given us, I'll assume you have a function myfun that you pass to something like ode45
y_0 = [0,0,0];
% here Tfinal is the time in seconds that you want to simulate to
% and specify the tspan so that you will get a solution at each whole
% number of seconds, I believe
[t,y] = ode45(#myfun,[0:0.1:Tfinal],y_0);
Somewhere you have defined your function, here I'll call it myfun
function dy = myfun(t,y)
% here let's check to see if it's time to add your offsets
% still, you may want to put a little fudge factor for the time, but
% you'll have to experiment, I'll set it up though
EPS = 1e-12;
if( t < 10 + EPS || t > 10 - EPS )
y(1) = y(1) + 10;
.
.
.
.
% this only makes sense if you then use y(1) in the compuatation
Otherwise, just add the offset to the returned solution vector, i.e.
idx10 = find( t == 10 ); % should be there since it's in the tspan
y(idx10:end) = y(idx10:end) + 10; % I guess you add it from that point on?