I am currently implementing a second order low-pass filter employing Tustin discretization as embedded function within a Simulink model. The function has currently deployed as follows:
function y = SecondOrderLowpassFilterTustin(u,fn,dn,Ts)
persistent xs
if isempty(xs)
xs = [u 0]';
end
% Convert frequency from Hz to rad/s
wn = fn*2*pi;
% Construct state-space matrices in continuous time
A = [0 1 ; -wn^2 -2*dn*wn];
B = [0 ; wn^2];
C = [1 0];
D = 0;
% Construct equivalent state-space matrices in discrete time
I = eye(size(A));
K1 = (I + 0.5*A*Ts);
K2 = (I - 0.5*A*Ts)^-1;
Ad = K1*K2;
Bd = K2*B*Ts;
Cd = C*K2;
Dd = (0.5*Ts*C*K2*B) + D;
% Calculate output
xs = Ad*xs + Bd*u;
y = Cd*xs + Dd*u;
end
I am then calling such function from within another function which looks like this:
function u1 = fcn(u,fn,dn,Ts)
u1 = SecondOrderLowpassFilterTustin(u(1),fn,dn,Ts);
In all those cases when I call the function a single time, as in the case
y1 = SecondOrderLowpassFilterTustin(u1,fn,dn,Ts);
the results are ok
However, as soon as I would like to filter multiple signals concurrently, as in the following case
function [u1,u2,u3] = fcn(u,fn,dn,Ts)
u1 = SecondOrderLowpassFilterTustin(u(1),fn,dn,Ts);
u2 = SecondOrderLowpassFilterTustin(u(2),fn,dn,Ts);
u3 = SecondOrderLowpassFilterTustin(u(3),fn,dn,Ts);
the results are poor as in Figure 2.
I believe that it has to do with the persistent state variable xs, which should undergo a reset or initialization as soon as the SecondOrderLowpassFilterTustin(u,fn,dn,Ts) is being called.
I have tried different things out, unfortunately with little success. Therefore, your suggestions are highly appreciated.
Indeed, the persistent variable is not reset when calling the filter function the second and third time, and thus the initial xs is not set correctly. Since you want to use the function for multiple signals, the persistent variable cannot be inside SecondOrderLowpassFilterTustin.
You can however let this function output xs and take xs as input argument, and keep this persistent in fcn.
function [y, xs] = SecondOrderLowpassFilterTustin(u,fn,dn,Ts,xs)
if isempty(xs)
xs = [u 0].';
end
% Convert frequency from Hz to rad/s
wn = fn*2*pi;
% continue with the rest...
end
And fcn would look like:
function [u1,u2,u3] = fcn(u,fn,dn,Ts)
persistent x1 x2 x3
% x1, x2 and x3 will be [] on first iteration, thus xs will be set to [u 0].'
[u1,x1] = SecondOrderLowpassFilterTustin(u(1),fn,dn,Ts,x1);
[u2,x2] = SecondOrderLowpassFilterTustin(u(2),fn,dn,Ts,x2);
[u3,x3] = SecondOrderLowpassFilterTustin(u(3),fn,dn,Ts,x3);
end
BTW, don't think you expect any complex output, but just in case ' is not transpose, .' is.
Related
Hi i've been asked to solve SIR model using fsolve command in MATLAB, and Euler 3 point backward. I'm really confused on how to proceed, please help. This is what i have so far. I created a function for 3BDF scheme but i'm not sure how to proceed with fsolve and solve the system of nonlinear ODEs. The SIR model is shown as and 3BDF scheme is formulated as
clc
clear all
gamma=1/7;
beta=1/3;
ode1= #(R,S,I) -(beta*I*S)/(S+I+R);
ode2= #(R,S,I) (beta*I*S)/(S+I+R)-I*gamma;
ode3= #(I) gamma*I;
f(t,[S,I,R]) = [-(beta*I*S)/(S+I+R); (beta*I*S)/(S+I+R)-I*gamma; gamma*I];
R0=0;
I0=10;
S0=8e6;
odes={ode1;ode2;ode3}
fun = #root2d;
x0 = [0,0];
x = fsolve(fun,x0)
function [xs,yb] = ThreePointBDF(f,x0, xmax, h, y0)
% This function should return the numerical solution of y at x = xmax.
% (It should not return the entire time history of y.)
% TO BE COMPLETED
xs=x0:h:xmax;
y=zeros(1,length(xs));
y(1)=y0;
yb(1)=y0+f(x0,y0)*h;
for i=1:length(xs)-1
R =R0;
y1(i+1,:) = fsolve(#(u) u-2*h/3*f(t(i+1),u) - R, y1(i-1,:)+2*h*F(i,:))
S = S0;
y2(i+1,:) = fsolve(#(u) u-2*h/3*f(t(i+1),u) - S, y2(i-1,:)+2*h*F(i,:))
I= I0;
y3(i+1,:) = fsolve(#(u) u-2*h/3*f(t(i+1),u) - I, y3(i-1,:)+2*h*F(i,:))
end
end
You have an implicit equation
y(i+1) - 2*h/3*f(t(i+1),y(i+1)) = G = (4*y(i) - y(i-1))/3
where the right-side term G is constant in the call to fsolve, that is, during the solution of the implicit step equation.
Note that this is for the vector valued system y'(t)=f(t,y(t)) where
f(t,[S,I,R]) = [-(beta*I*S)/(S+I+R); (beta*I*S)/(S+I+R)-I*gamma; gamma*I];
To solve this write
G = (4*y(i,:) - y(i-1,:))/3
y(i+1,:) = fsolve(#(u) u-2*h/3*f(t(i+1),u) - G, y(i-1,:)+2*h*F(i,:))
where a midpoint step is used to get an order 2 approximation as initial guess, F(i,:)=f(t(i),y(i,:)). Add solver options for error tolerances as necessary, you want the error in the implicit equation smaller than the truncation error O(h^3) of the step. One can also keep only a short array of function values, then one has to be careful for the correspondence of the position in the short array to the time index.
Using all that and a reference solution by a higher order standard solver produces the following error graphs for the components
where one can see that the first order error of the constant first step results in a first order global error, while with a second order error in the first step using the Euler method results in a clear second order global error.
Implement the method in general terms
from scipy.optimize import fsolve
def BDF2(f,t,y0,y1):
N, h = len(t)-1, t[1]-t[0];
y = (N+1)*[np.asarray(y0)];
y[1] = y1;
for i in range(1,N):
t1, G = t[i+1], (4*y[i]-y[i-1])/3
y[i+1] = fsolve(lambda u: u-2*h/3*f(t1,u)-G, y[i-1]+2*h*f(t[i],y[i]), xtol=1e-3*h**3)
return np.vstack(y)
Set up the model to be solved
gamma=1/7;
beta=1/3;
print beta, gamma
y0 = np.array([8e6, 10, 0])
P = sum(y0); y0 = y0/P
def f(t,y): S,I,R = y; trns = beta*S*I/(S+I+R); recv=gamma*I; return np.array([-trns, trns-recv, recv])
Compute a reference solution and method solutions for the two initialization variants
from scipy.integrate import odeint
tg = np.linspace(0,120,25*128)
yg = odeint(f,y0,tg,atol=1e-12, rtol=1e-14, tfirst=True)
M = 16; # 8,4
t = tg[::M];
h = t[1]-t[0];
y1 = BDF2(f,t,y0,y0)
e1 = y1-yg[::M]
y2 = BDF2(f,t,y0,y0+h*f(0,y0))
e2 = y2-yg[::M]
Plot the errors, computation as above, but embedded in the plot commands, could be separated in principle by first computing a list of solutions
fig,ax = plt.subplots(3,2,figsize=(12,6))
for M in [16, 8, 4]:
t = tg[::M];
h = t[1]-t[0];
y = BDF2(f,t,y0,y0)
e = (y-yg[::M])
for k in range(3): ax[k,0].plot(t,e[:,k],'-o', ms=1, lw=0.5, label = "h=%.3f"%h)
y = BDF2(f,t,y0,y0+h*f(0,y0))
e = (y-yg[::M])
for k in range(3): ax[k,1].plot(t,e[:,k],'-o', ms=1, lw=0.5, label = "h=%.3f"%h)
for k in range(3):
for j in range(2): ax[k,j].set_ylabel(["$e_S$","$e_I$","$e_R$"][k]); ax[k,j].legend(); ax[k,j].grid()
ax[0,0].set_title("Errors: first step constant");
ax[0,1].set_title("Errors: first step Euler")
I've noticed some weird facts about integral2. These are probably due to my limitations in understanding how it works. I have some difficulties in integrating out variables when I have particular functions. For instance, look at the following Code:
function Output = prova(p,Y)
x = p(1);
y = p(2);
w = p(3);
z = p(4);
F1 = #(Data,eta_1,eta_2,x,y,w,z) F2(eta_1,eta_2,Data) .* normpdf(eta_1,x,y) .* normpdf(eta_2,w,z);
Output = integral2(#(eta_1,eta_2)F1(Y,eta_1,eta_2,0,1,10,2),-5,5,-5,5);
end
function O = F2(pp1,pp2,D)
O = pp1 + pp2 + sum(D);
end
In this case the are no problems in evaluating the integral. But if I change the code in this way I obtain some errors, although the output of F2 is exactly the same:
function Output = prova(p,Y)
x = p(1);
y = p(2);
w = p(3);
z = p(4);
F1 = #(Data,eta_1,eta_2,x,y,w,z) F2(eta_1,eta_2,Data) .* normpdf(eta_1,x,y) .* normpdf(eta_2,w,z);
Output = integral2(#(eta_1,eta_2)F1(Y,eta_1,eta_2,0,1,10,2),-5,5,-5,5);
end
function O = F2(pp1,pp2,D)
o = sum([pp1 pp2]);
O = o + sum(D);
end
The problems increase if F2 for example have some matrix multiplication in which "eta_1" and "eta_2", which I want to integrate out, are involved. This problems makes practically impossible to solve computations in which, for instance, we have to integrate out a variable X which is inside a Likelihood Function (whose calculation could require some internal Loop, or Sum, or Prod involving our variable X). What is the solution?
I have a dataset with 1125 rows and 64 columns. Where first 554 rows belong to one class and the remaining rows belong to the other class. The objective function
is to be minimized in terms of R_1 and R_2 where both are are row vectors(1 x 64). x_i and x_l are the rows from the data matrix. I am trying to minimize this objective function using the optimization toolbox, but I am struggling to get the objective function in the desired form and running into errors. This is how I have coded so far
data = xlsread('data.xlsx');
dat1 = data(1:554,:);
dat2 = data(555:1125,:);
f1 = #(x) 0;
f2 = #(x) 0;
%% for digits labeled 0
for i = 1:554
f1 = #(x) f1 + (dat1(i,:) - x(1)).^2;
end
%% for digits labeled 1
for j = 1:571
f2 = #(x) f2 + (dat2(j,:) - x(2)).^2;
end
%% final objective function
f = #(x) 1/554*f1 + 1/571*f2;
%%
x = fminunc(f);
Please guide me on how to correctly form this type of objective function in Matlab
None of your code makes sense. A few issues
f1 = #(x) 0; and f2 = #(x) 0 define anonymous functions which always return zero. What is the purpose of this?
Every further definition of f1,f2,f is attempting to do arithmetic operations on an anonymous function. It's not clear what you expect this to accomplish.
x = fminunc(f); is missing an argument, it needs an initial guess as well. This isn't just to initialize the algorithm but also so that fminunc knows the dimensions that the input to f should have.
For your case f should be defined so half the values passed to it refer to R1 and the other half refer to R2. For example define
l2_sq = #(x) sum(x.^2,2); % return norm(x,2)^2 for each row of x
f1 = #(R1) sum(l2_sq(bsxfun(#minus, dat1, R1)));
f2 = #(R2) sum(l2_sq(bsxfun(#minus, dat2, R2)));
f3 = #(R1,R2) -10 * norm(R1-R2,1);
f = #(R) f1(R(1:64)) + f2(R(65:128)) + f3(R(1:64), R(65:128));
Since the combined R vector has 128 elements, we need to generate an initial guess that contains 128 elements. In this case we could just use random Gaussian noise
R0 = randn(1,128);
Finally, call fminunc as
Rhat = fminunc(f, R0);
R1 = Rhat(1:64);
R2 = Rhat(65:128);
where R1 and R2 are the optimal values.
Note In MATLAB 2016b and newer, implicit expansion allows you to replace bsxfun(#minus, dat1, R1) with the more efficient dat1 - R1. Similarly for bsxfun(#minus, dat2, R2).
The MATLAB program below is a function that references specific input values for S, E, r, sigma, and tau.
function [C, Cdelta, P, Pdelta] = ch08(S,E,r,sigma,tau)
% Input arguments: S = asset price at time t
% E = Exercise price
% r = interest rate
% sigma = volatility
% tau = time to expiry (T-t)
%
% Output arguments: C = call value, Cdelta = delta value of call
% P = Put value, Pdelta = delta value of put
%
% function [C, Cdelta, P, Pdelta] = ch08(S,E,r,sigma,tau)
if tau > 0
d1 = (log(S/E) + (r + 0.5*sigma^2)*(tau))/(sigma*sqrt(tau));
d2 = d1 - sigma*sqrt(tau);
N1 = 0.5*(1+erf(d1/sqrt(2)));
N2 = 0.5*(1+erf(d2/sqrt(2)));
C = S*N1-E*exp(-r*(tau))*N2;
Cdelta = N1;
P = C + E*exp(-r*tau) - S;
Pdelta = Cdelta - 1;
title('Graph of Call Value vs. Time to Expiry')
xlabel('Time to expiry')
ylabel('Call Value')
plot (tau,C)
else
C = max(S-E,0);
Cdelta = 0.5*(sign(S-E) + 1);
P = max(E-S,0);
Pdelta = Cdelta - 1;
title('Graph of Call Value vs. Time to Expiry')
xlabel('Time to expiry')
ylabel('Call Value')
plot (tau,C)
end
After running
ch08(3,2.5,0.03,0.25,1)
The following output is produced
After running the function again,
ch08(3,2.5,0.03,0.25,1)
hold on
ch08(3,2.5,0.03,0.25,0.9)
Two data points are produced
After manually typing decreasing tau values,
ch08(3,2.5,0.03,0.25,1)
hold on
ch08(3,2.5,0.03,0.25,0.9)
hold on
ch08(3,2.5,0.03,0.25,0.8)
hold on
ch08(3,2.5,0.03,0.25,0.7)
hold on
ch08(3,2.5,0.03,0.25,0.6)
hold on
ch08(3,2.5,0.03,0.25,0.5)
hold on
ch08(3,2.5,0.03,0.25,0.4)
hold on
ch08(3,2.5,0.03,0.25,0.3)
hold on
ch08(3,2.5,0.03,0.25,0.2)
hold on
ch08(3,2.5,0.03,0.25,0.1)
The graph will produce a bunch of data points,
Is there a way to automate the tau values entered in ch08(S,E,r,sigma,tau) so that the user doesn't have to type all of the input in?
As I suggested in comments, you need to use a for loop. You can create an array with values of tau that you want to use, and call your function with a different element from that array in each loop iteration:
figure, hold on
tau = 10.^(0:-1:-6);
for ii = 1:length(tau)
ch08(3,2.5,0.03,0.25,tau(ii))
end
However, a better solution would be to not plot within your ch08 function, and return the value C as you did in your first version of your question. Then you can do this:
tau = 10.^(0:-1:-6);
C = zeros(size(tau));
for ii = 1:length(tau)
C(ii) = ch08(3,2.5,0.03,0.25,tau(ii));
end
plot(tau,C,'.');
This would allow you to change your plot as you please, for example drawing a line through your points.
PS: Note that you only need to give hold on once. It sets a flag in the figure window that is not cleared until you do hold off or clf.
I am trying to compute the value of this integral using Matlab
Here the other parameters have been defined or computed in the earlier part of the program as follows
N = 2;
sigma = [0.01 0.1];
l = [15];
meu = 4*pi*10^(-7);
f = logspace ( 1, 6, 500);
w=2*pi.*f;
for j = 1 : length(f)
q2(j)= sqrt(sqrt(-1)*2*pi*f(j)*meu*sigma(2));
q1(j)= sqrt(sqrt(-1)*2*pi*f(j)*meu*sigma(1));
C2(j)= 1/(q2(j));
C1(j)= (q1(j)*C2(j) + tanh(q1(j)*l))/(q1(j)*(1+q1(j)*C2(j)*tanh(q1(j)*l)));
Z(j) = sqrt(-1)*2*pi*f(j)*C1(j);
Apprho(j) = meu*(1/(2*pi*f(j))*(abs(Z(j))^2));
Phi(j) = atan(imag(Z(j))/real(Z(j)));
end
%integration part
c1=w./(2*pi);
rho0=1;
fun = #(x) log(Apprho(x)/rho0)/(x.^2-w^2);
c2= integral(fun,0,Inf);
phin=pi/4-c1.*c2;
I am getting an error like this
could anyone help and tell me where i am going wrong.thanks in advance
Define Apprho in a separate *.m function file, instead of storing it in an array:
function [ result ] = Apprho(x)
%
% Calculate f and Z based on input argument x
%
% ...
%
meu = 4*pi*10^(-7);
result = meu*(1/(2*pi*f)*(abs(Z)^2));
end
How you calculate f and Z is up to you.
MATLAB's integral works by calling the function (in this case, Apprho) repeatedly at many different x values. The x values called by integral don't necessarily correspond to the 1: length(f) values used in your original code, which is why you received errors.