How to avoid tf() command using State-space models in Matlab - matlab

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().

Related

How to use dynamic function name in MATLAB?

I am trying to optimize the following program by using for loops
t = 0:0.1:100;
conc = rand(size(t));
syms x
equ_1(x) = 10*x.^2+1;
equ_2(x) = 5*x.^3+10*x.^2;
equ_3(x) = 5*x.^3+10*x.^2;
y_1 = equ_1(conc);
y_2 = equ_2(conc);
y_3 = equ_3(conc);
p_1 = polyfit(t,y_1,1);
p_2 = polyfit(t,y_2,1);
p_3 = polyfit(t,y_3,1);
yfit_1 = p_1(1)*conc+p_1(2);
yfit_2 = p_2(1)*conc+p_2(2);
yfit_3 = p_2(1)*conc+p_2(2);
rms_er_1 = double(sqrt((sum((yfit_1-y_1).^2)./length(yfit_1))));
rms_er_2 = double(sqrt((sum((yfit_2-y_2).^2)./length(yfit_2))));
rms_er_3 = double(sqrt((sum((yfit_3-y_3).^2)./length(yfit_3))));
rms = [rms_er_1 rms_er_2 rms_er_3]
In this program. I have many equations and I can write them manually like equ_1(x),equ_1(x),equ_1(x) etc. After writing equations, will it be possible to write remaining programs by using for loops?
Can anyone help?
Yes, it is possible. You can pack your functions in a cell array and give your values as parameters while looping over this cell array
t = (0:0.1:100)';
conc = rand(size(t));
% Packing your function handles in a cell array ( I do not have the
% symbolic math toolbox, so I used function handles here. In your case you
% have to pack your equations equ_n(x) in between the curly brackets{} )
allfuns = {#(x) 10*x.^2+1, ...
#(x) 5*x.^3+10*x.^2, ...
#(x) 5*x.^3+10*x.^2};
% Allocate memory
y = zeros(length(t), length(allfuns));
p = zeros(2,length(allfuns));
yfit = zeros(length(t), length(allfuns));
rms = zeros(1, length(allfuns));
% Loop over all functions the cell, applying your functional chain
for i=1:length(allfuns)
y(:,i) = allfuns{i}(t);
p(:,i) = polyfit(t,y(:,i),1);
yfit(:,i) = p(1,i)*conc+p(2,i);
rms(:,i) = double(sqrt((sum((yfit(:,i)-y(:,i)).^2)./ ...
length(yfit(:,i)))));
end
This leads to
>> rms
rms =
1.0e+06 *
0.0578 2.6999 2.6999
You can expand that to an arbitrary number of equations in allfuns.
Btw: You are fitting 1st order polynomials with polyfit to values calculated with 2nd and 3rd order functions. This leads of course to rough fits with high rms. I do not know how your complete problem looks like, but you could define an array poly_orders containing the polynomial order of each function in allfuns. If you give those values as parameter to the polyfit function in the loop, your fits will work way better.
You can try cellfun
Here is an example.
Define in a .m
function y = your_complex_operation(f,x, t)
y_1 = f(x);
p_1 = polyfit(t,y_1,1);
yfit_1 = p_1(1)*x+p_1(2);
y = double(sqrt((sum((yfit_1-y_1).^2)./length(yfit_1))));
end
Then use cellfunc
funs{1}=#(x) 10*x.^2+1;
funs{2}=#(x) 5*x.^3+10*x.^2;
funs{3}=#(x) 5*x.^3+10*x.^2;
%as many as you need
t = 0:0.1:100;
conc = rand(size(t));
funs_res = cellfun(#(c) your_complex_operation(c,conc,t),funs);

Trying to minimise a function wrt 2 variables for robust portfolio optimisation. How to do this with fmincon?

I am currently involved in a group project where we have to conduct portfolio selection and optimisation. The paper being referenced is given here: (specifically page 5 and 6, equations 7-10)
http://faculty.london.edu/avmiguel/DeMiguel-Nogales-OR.pdf
We are having trouble creating the optimisation problem using M-Portfolios, given below
min (wrt w,m) (1/T) * sum_(rho)*(w'*r_t - m) (Sorry I couldn't get the formatting to work)
s.t. w'e = 1 (just a condition saying that all weights add to 1)
So far, this is what we have attempted:
function optPortfolio = portfoliofminconM(returns,theta)
% Compute the inputs of the mean-variance model
mu = mean(returns)';
sigma = cov(returns);
% Inputs for the fmincon function
T = 120;
n = length(mu);
w = theta(1:n);
m = theta((n+1):(2*n));
c = 0.01*ones(1,n);
Aeq = ones(1,(2*n));
beq = 1;
lb = zeros(2,n);
ub = ones(2,n);
x0 = ones(n,2) / n; % Start with the equally-weighted portfolio
options = optimset('Algorithm', 'interior-point', ...
'MaxIter', 1E10, 'MaxFunEvals', 1E10);
% Nested function which is used as the objective function
function objValue = objfunction(w,m)
cRp = (w'*(returns - (ones(T,1)*m'))';
objValue = 0;
for i = 1:T
if abs(cRp(i)) <= c;
objValue = objValue + (((cRp(i))^2)/2);
else
objValue = objValue + (c*(abs(cRp(i))-(c/2)));
end
end
The problem starts at our definitions for theta being used as a vector of w and m. We don't know how to use fmincon with 2 variables in the objective function properly. In addition, the value of the objective function is conditional on another value (as shown in the paper) and this needs to be done over a rolling time window of 120 months for a total period of 264 months.(hence the for-loop and if-else)
If any more information is required, I will gladly provide it!
If you can additionally provide an example that deals with a similar problem, can you please link us to it.
Thank you in advance.
The way you minimize a function of two scalars with fmincon is to write your objective function as a function of a single, two-dimensional vector. For example, you would write f(x,y) = x.^2 + 2*x*y + y.^2 as f(x) = x(1)^2 + 2*x(1)*x(2) + x(2)^2.
More generally, you would write a function of two vectors as a function of a single, large vector. In your case, you could rewrite your objfunction or do a quick hack like:
objfunction_for_fmincon = #(x) objfunction(x(1:n), x(n+1:2*n));

Solving PDE with Matlab

`sol = pdepe(m,#ParticleDiffusionpde,#ParticleDiffusionic,#ParticleDiffusionbc,x,t);
% Extract the first solution component as u.
u = sol(:,:,:);
function [c,f,s] = ParticleDiffusionpde(x,t,u,DuDx)
global Ds
c = 1/Ds;
f = DuDx;
s = 0;
function u0 = ParticleDiffusionic(x)
global qo
u0 = qo;
function [pl,ql,pr,qr] = ParticleDiffusionbc(xl,ul,xr,ur,t,x)
global Ds K n
global Amo Gc kf rhop
global uavg
global dr R nr
sum = 0;
for i = 1:1:nr-1
r1 = (i-1)*dr; % radius at i
r2 = i * dr; % radius at i+1
r1 = double(r1); % convert to double precision
r2 = double(r2);
sum = sum + (dr / 2 * (r1*ul+ r2*ur));
end;
uavg = 3/R^3 * sum;
ql = 1;
pl = 0;
qr = 1;
pr = -((kf/(Ds.*rhop)).*(Amo - Gc.*uavg - ((double(ur/K)).^2).^(n/2) ));`
dq(r,t)/dt = Ds( d2q(r,t)/dr2 + (2/r)*dq(r,t)/dr )
q(r, t=0) = 0
dq(r=0, t)/dr = 0
dq(r=dp/2, t)/dr = (kf/Ds*rhop) [C(t) - Cp(at r = dp/2)]
q = solid phase concentration of trace compound in a particle with radius dp/2
C = bulk liquid concentration of trace compound
Cp = trace compound concentration at particle surface
I want to solve the above pde with initial and boundary conditions given. Tried Matlab's pdepe, but does not work satisfactorily. Maybe the boundary conditions is creating problem for me. I also used this isotherm equation for equilibrium: q = K*Cp^(1/n). This is convection-diffusion equation but i could not find any write ups that addresses solving this type of equation properly.
There are two problems with the current implementation.
Incorrect Source Term
The PDE you are attempting to solve has the form
which has the equivalent form
where the last term arises due to the factor of 2 in the original PDE.
The last term needs to be incorporated into pdepe via a source term.
Calculation of q average
The current implementation attempts to calculate the average value of q using the left and right values of q passed to the boundary condition function.
This is incorrect.
The average value of q needs to be calculated from a vector of up-to-date values of the quantity.
However, we have the complication that the only function to receive all mesh values is ParticleDiffusionpde; however, the mesh values passed to that function are not guaranteed to be from the mesh we provided.
Solution: use events (as described in the pdepe documentation).
This is a hack since the event function is meant to detect zero-crossings, but it has the advantage that the function is given all values of q on the mesh we provide.
So, the working example below (you'll notice I set all of the parameters to 1 since I didn't know better) uses the events function to update a variable qStore that can be accessed by the boundary condition function (see here for an explanation), and the boundary condition function performs a vectorized trapezoidal integration for the average calculation.
Working Example
function [] = ParticleDiffusion()
% Parameters
Ds = 1;
q0 = 0;
K = 1;
n = 1;
Amo = 1;
Gc = 1;
kf = 1;
rhop = 1;
% Space
rMesh = linspace(0,1,10);
rMesh = rMesh(:) ;
dr = rMesh(2) - rMesh(1) ;
% Time
tSpan = linspace(0,1,10);
% Vector to store current u-value
qStore = zeros(size(rMesh));
options.Events = #(m,t,x,y) events(m,t,x,y);
% Solve
[sol,~,~,~,~] = pdepe(1,#ParticleDiffusionpde,#ParticleDiffusionic,#ParticleDiffusionbc,rMesh,tSpan,options);
% Use the events function to update qStore
function [value,isterminal,direction] = events(m,~,~,y)
qStore = y; % Value of q on rMesh
value = m; % Since m is constant, it will never be zero (no event detection)
isterminal = 0; % Continue integration
direction = 0; % Detect all zero crossings (not important)
end
function [c,f,s] = ParticleDiffusionpde(r,~,~,DqDr)
% Define the capacity, flux, and source
c = 1/Ds;
f = DqDr;
s = DqDr./r;
end
function u0 = ParticleDiffusionic(~)
u0 = q0;
end
function [pl,ql,pr,qr] = ParticleDiffusionbc(~,~,R,ur,~)
% Calculate average value of current solution
qL = qStore(1:end-1);
qR = qStore(2: end );
total = sum((qL.*rMesh(1:end-1) + qR.*rMesh(2:end))) * dr/2;
qavg = 3/R^3 * total;
% Left boundary
pl = 0;
ql = 1;
% Right boundary
qr = 1;
pr = -(kf/(Ds.*rhop)).*(Amo - Gc.*qavg - (ur/K).^n);
end
end

Using Improved Euler Method in Matlab

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

use nested functions in matlab M-file

i have question,about which i am too much interested,suppose that i have two M-file in matlab, in the first one i have described following function for calculating peaks and peaks indeces
function [peaks,peak_indices] = find_peaks(row_vector)
A = [0 row_vector 0];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end
and in second M-file i have code for describing sinusoidal model for given data sample
function [ x ]=generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))';
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
end
my question is how to combine it together?one solution would be just create two M-file into folder,then call function from one M-file and made operation on given vector and get result,and then call second function from another M file on given result and finally get what we want,but i would like to build it in one big M-file,in c++,in java,we can create classes,but i am not sure if we can do same in matlab too,please help me to clarify everything and use find_peaks function into generate function
UPDATED:
ok now i would like to show simple change what i have made in my code
function [ x ] = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
[pks,locs] = findpeaks(x);
end
i used findpeaks built-in function in matlab,but i am getting following error
generate(1000,50,50)
Undefined function 'generate' for input arguments of type 'double'.
also i am interested what would be effective sampling rate to avoid alliasing?
You can simply put both in one file. The file must have the same name as the first function therein, and you will not be able to access subsequently defined functions from outside that file. See the MATLAB documentation on functions http://www.mathworks.co.uk/help/matlab/ref/function.html (particularly the examples section).
Also note that MATLAB has a built-in function findpeaks().
(By the way, you're still sampling at too low a frequency and will most certainly get aliasing - see http://en.wikipedia.org/wiki/Aliasing#Sampling_sinusoidal_functions )
Edit: As you requested it, here is some more information on the sampling theorem. A good and simple introduction to these basics is http://www.dspguide.com/ch3/2.htm and for further reading you should search for the Shannon/Nyquist sampling theorem.
Try with this, within a single MATLAB script
function test()
clc, clear all, close all
x = generate(1000,50,50);
[p,i] = find_peaks(x)
end
function x = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
end
function [peaks,peak_indices] = find_peaks(row_vector)
A = [0;row_vector;0];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end