Poor fit using nlinfit and fminsearch in Matlab - matlab

I have some reference data against which I want to fit some model data. I have developed a 5-param model for this purpose. The job now is to optimize the model params using Matlab. However, I have very poor fit for ref vs model data (r^2 in the range 0.6 only). I tried using fminsearch and nlinfit algorithms.
One probable reason might be that my params are not of similar order of magnitude (while 1 param is of range e-09, another is ~e03). I am unsure whether to use scaling/normalization of params, and if so how to go about it. Can anyone help?
Here's my code for your perusal:
voltage = xlsread('co_content_29_07_avik.xlsx','A9:A99'); % voltage
current = xlsread('co_content_29_07_avik.xlsx','B9:B99'); % current
% Cell characteristics from manufacturer's datasheet
V_oc = 0.665; %V
I_sc = 5.75; %A
V_mp = 0.56; % V
I_mp = 5.35; % A
a = 1.2 % educated guess
% Calculate thermal voltage
k = 1.3806e-23; %Boltzmann constant - Joule/Kelvin
T = 298;
q = 1.602e-19; %electron charge - Coulomb
n_cell = 1; % no. of cells
V_t = n_cell*k*T/q;
% Calculate unoptimized cell parameters (R_s, R_sh, I_0, I_ph, n)
A = a*V_t/I_mp;
B = -(V_mp*(2*I_mp - I_sc)/(V_mp*I_sc + V_oc*(I_mp - I_sc)));
C = -((2*V_mp - V_oc)/a*V_t) + (V_mp*I_sc - V_oc*I_mp)/(V_mp*I_sc + V_oc*(I_mp - I_sc));
D = (V_mp-V_oc)/(a*V_t);
R_s = A*lambertw((B*exp(C) - (D+C)))
R_sh_num = (V_mp-I_mp*R_s)*(V_mp - R_s*(I_sc-I_mp) - a*V_t);
R_sh_den = (V_mp-I_mp*R_s)*(I_sc-I_mp) - a*V_t*I_mp;
R_sh = R_sh_num/R_sh_den
I_0 = (I_sc*(R_sh + R_s) - V_oc)/(R_sh*exp(V_oc/(a*V_t)))
I_ph = (R_sh+R_s)*I_sc/R_sh
len = length(voltage);
for i=1:1:len
non_exp1 = R_s*R_sh*I_0/(a*V_t*(R_s + R_sh));
lambexp1 = R_sh*(R_s*I_ph + R_s*I_0 + voltage(i,1))/(a*V_t*(R_s + R_sh));
lambarg1 = non_exp1*exp(lambexp1);
firstterm1 = -voltage(i,1)/(R_s + R_sh);
midterm1 = -(lambertw(lambarg1)*a*V_t/R_s);
third1 = R_sh*(I_0 + I_ph)/(R_s + R_sh);
I_1(i,1) = firstterm1 + midterm1 + third1;
end
% Optimize using fminsearch algo
fun = #(p) sum((current - (voltage/(p(1)+p(2)) - (lambertw((p(1)*p(2)*p(3))/(p(5)*V_t*(p(1)+p(2)))))*exp((p(2)*(p(1)*p(4)+p(1)*p(3)+voltage))/(p(5)*V_t*(p(1)+p(2))))*p(5)*V_t/p(1) + (p(2)*(p(3)+p(4))/(p(1)+p(2))))).^2);
% initial guess for param
pguess = [0.005,4.75,0.000000001,5.75,1.2];
%optimize
[x,fval,exitflag,output] = fminsearch(fun,pguess,optimset('MaxFunEvals',1000))

Related

Issues with maximum likelihood estimation of realGARCH(1,1) in matlab

I am having some trouble estimating the parameter for the log-linear realized Garch(1,1) model. The parameter values which I get from the optimisation are different from those derived in the paper and I'm not sure where I am going wrong. Any help would be great. The specification of the model from (Hansen et al. (2012)) is:
Realized GARCH specification
And the likelihood function is given by:
Log Likelihood
I am using the same data as used by Hansen and co-authors which can retrieved from the rugarch package with the command data(spyreal).
My matlab code is
function output = loglikRV(param, data)
r = data.SPY_OC;
RV = data.SPY_RK;
logRV = log(RV);
T = numel(RV); % time sample size
alpha0 = param(1);
alpha1 = param(2);
alpha2 = param(3);
omega0 = param(4);
omega1 = param(5);
omega2 = param(6);
omega3 = param(7);
sigmamu2 = param(8);
z = zeros(T,1);
logh = zeros(T,1);
u = zeros(T,1);
llhs = zeros(T,1);
logh(1) = 8.8296e-05;
u(1) = 0.005;
z(1) = 0.005;
llhs(1) = 0.005;
for i = 2:T
logh(i) = alpha0 + alpha1*logh(i-1) + alpha2*logRV(i-1);
z(i) = r(i) / sqrt(exp(logh(i)));
u(i) = logRV(i) - omega0 - omega1*logh(i) - omega2*z(i) - omega3*(z(i)^2 - 1);
llhs(i) = -(1/2)*(log(2*pi) + logh(i) + z(i)^2) - (1/2)*(log(2*pi) + log(sigmamu2) + u(1)^2 / sigmamu2);
end
output = sum(llhs(2:T-1));
return
And I am optimising this using the Matlab fmincon function with the code as shown below:
clear;close all;
RVfinal = readtable('spyreal.xlsx');
objfun = #(param)(-loglikRV(param,RVfinal)); % negative of the log-likelihood function
param0 = [0.07048753,0.43272574,0.52944743,-0.19368728,1.02540217,-0.06100213, 0.07437231, 0.38];
% constraints in the optimization
A = []; b = []; % no inequality constraints
Aeq=[]; beq=[]; % no equality constraints
% -- MLE Optimization using "fmincon" --
optim_options = optimset('Display','off','TolX',1e-4,'TolFun',1e-4);
[mymle,fval] = fmincon(objfun,param0,A,b,Aeq,beq,[],[],[],optim_options);
mymle
Thank You!

MATLAB - Adaptive Step Size Runge-Kutta

I've programmed in MATLAB an adaptive step size RK4 to solve a system of ODEs. The code runs without error, however it does not produce the desired curve when I try to plot x against y. Instead of being a toroidal shape, I simply get a flat line. This is evident from the fact that r is outputting a constant value. After checking the outputs of each line, they are not outputting constants or errors or inf or NaN, rather they are outputting both a real and imaginary component (complex numbers). I have no idea as to why this is occurring and I believe it to be the source of my trouble.
function AdaptRK4()
parsec = 3.08*10^18;
r_1 = 8.5*1000.0*parsec; % in cm
theta_1 = 0.0;
a = 0.5*r_1;
gam = 1;
grav = 6.6720*10^-8;
amsun = 1.989*10^33;
amg = 1.5d11*amsun;
gm = grav*amg;
u_1 = 20.0*10^5;
v = sqrt(gm/r_1);
time = 0.0;
epsilon = 0.00001;
m1 = 0.5;
m2 = 0.5;
m3 = 0.5;
i = 1;
nsteps = 50000;
deltat = 5.0*10^12;
angmom = r_1*v;
angmom2 = angmom^2.0;
e = -2*10^5.0*gm/r_1+u_1*u_1/2.0+angmom2/(2.0*r_1*r_1);
for i=1:nsteps
deltat = min(deltat,nsteps-time);
fk3_1 = deltat*u_1;
fk4_1 = deltat*(-gm*r_1*r_1^(-gam)/(a+r_1)^(3- gam)+angmom2/(r_1^3.0));
fk5_1 = deltat*(angmom/(r_1^2.0));
r_2 = r_1+fk3_1/4.0;
u_2 = u_1+fk4_1/4.0;
theta_2 = theta_1+fk5_1/4.0;
fk3_2 = deltat*u_2;
fk4_2 = deltat*(-gm*r_2*r_2^(-gam)/(a+r_2)^(3-gam)+angmom2/(r_2^3.0));
fk5_2 = deltat*(angmom/(r_2^2.0));
r_3 = r_1+(3/32)*fk3_1 + (9/32)*fk3_2;
u_3 = u_1+(3/32)*fk4_1 + (9/32)*fk4_2;
theta_3 = theta_1+(3/32)*fk5_1 + (9/32)*fk5_2;
fk3_3 = deltat*u_3;
fk4_3 = deltat*(-gm*r_3*r_3^(-gam)/(a+r_3)^(3-gam)+angmom2/(r_3^3.0));
fk5_3 = deltat*(angmom/(r_3^2.0));
r_4 = r_1+(1932/2197)*fk3_1 - (7200/2197)*fk3_2 + (7296/2197)*fk3_3;
u_4 = u_1+(1932/2197)*fk4_1 - (7200/2197)*fk4_2 + (7296/2197)*fk4_3;
theta_4 = theta_1+(1932/2197)*fk5_1 - (7200/2197)*fk5_2 + (7296/2197)*fk5_3;
fk3_4 = deltat*u_4;
fk4_4 = deltat*(-gm*r_4*r_4^(-gam)/(a+r_4)^(3-gam)+angmom2/(r_4^3.0));
fk5_4 = deltat*(angmom/(r_4^2.0));
r_5 = r_1+(439/216)*fk3_1 - 8*fk3_2 + (3680/513)*fk3_3 - (845/4104)*fk3_4;
u_5 = u_1+(439/216)*fk4_1 - 8*fk4_2 + (3680/513)*fk4_3 - (845/4104)*fk4_4;
theta_5 = theta_1+(439/216)*fk5_1 - 8*fk5_2 + (3680/513)*fk5_3 - (845/4104)*fk5_4;
fk3_5 = deltat*u_5;
fk4_5 = deltat*(-gm*r_5*r_5^(-gam)/(a+r_5)^(3-gam)+angmom2/(r_5^3.0));
fk5_5 = deltat*(angmom/(r_5^2.0));
r_6 = r_1-(8/27)*fk3_1 - 2*fk3_2 - (3544/2565)*fk3_3 + (1859/4104)*fk3_4-(11/40)*fk3_5;
u_6 = u_1-(8/27)*fk4_1 - 2*fk4_2 - (3544/2565)*fk4_3 + (1859/4104)*fk4_4-(11/40)*fk4_5;
theta_6 = theta_1-(8/27)*fk5_1 - 2*fk5_2 - (3544/2565)*fk5_3 + (1859/4104)*fk5_4-(11/40)*fk5_5;
fk3_6 = deltat*u_6;
fk4_6 = deltat*(-gm*r_6*r_6^(-gam)/(a+r_6)^(3-gam)+angmom2/(r_6^3.0));
fk5_6 = deltat*(angmom/(r_6^2.0));
fm3_1 = m1 + 25*fk3_1/216+1408*fk3_3/2565+2197*fk3_4/4104-fk3_5/5;
fm4_1 = m2 + 25*fk4_1/216+1408*fk4_3/2565+2197*fk4_4/4104-fk4_5/5;
fm5_1 = m3 + 25*fk5_1/216+1408*fk5_3/2565+2197*fk5_4/4104-fk5_5/5;
fm3_2 = m1 + 16*fk3_1/135+6656*fk3_3/12825+28561*fk3_4/56430-9*fk3_5/50+2*fk3_6/55;
fm4_2 = m2 + 16*fk4_1/135+6656*fk4_3/12825+28561*fk4_4/56430-9*fk4_5/50+2*fk4_6/55;
fm5_2 = m3 + 16*fk5_1/135+6656*fk5_3/12825+28561*fk5_4/56430-9*fk5_5/50+2*fk5_6/55;
R3 = abs(fm3_1-fm3_2)/deltat;
R4 = abs(fm4_1-fm4_2)/deltat;
R5 = abs(fm5_1-fm5_2)/deltat;
err3 = 0.84*(epsilon/R3)^(1/4);
err4 = 0.84*(epsilon/R4)^(1/4);
err5 = 0.84*(epsilon/R5)^(1/4);
if R3<= epsilon
time = time+deltat;
fm3 = fm3_1;
i = i+1;
deltat = err3*deltat;
end
if R4<= epsilon
time = time+deltat;
fm4 = fm4_1;
i = i+1;
deltat = err4*deltat;
end
if R5<= epsilon
time = time+deltat;
fm5 = fm5_1;
i = i+1;
deltat = err5*deltat;
end
e=2*gm^2.0/(2*angmom2);
ecc=(1.0+(2.0*e*angmom2)/(gm^2.0))^0.5;
x(i)=r_1*cos(theta_1)/(1000.0*parsec);
y(i)=r_1*sin(theta_1)/(1000.0*parsec);
time=time+deltat;
r(i)=r_1;
time1(i)=time;
end
figure()
plot(x,y, '-k');
TeXString = title('Plot of Orbit in Gamma Potential Obtained Using RK4')
xlabel('x')
ylabel('y')
You are getting complex values because at some point npts - time < 0. You may want to print out the values of deltat to check the error.
Also, your code doesn't seem to take into account the case when the error estimate is larger than your tolerance. When your error estimate is greater than your tolerance you have to:
Shift back the time AND solution
calculate a new step-size based on a formula, and
recalculate your solution and error estimate.
The fact that you don't know how many iterations you will have to go through makes the use of a for-loop for adaptive runge Kutta a bit awkward. I suggest using a while loop instead.
You are using "i" in your code. "i" returns the basic imaginary unit. "i" is equivalent to sqrt(-1). Try to use another identifier in your loops and only use "i" or "j" in calculations where complex numbers are involved.

Index exceeds matrix dimensions error in Runge-Kutta method: Matlab

I'm trying to make a time stepping code using the 4th order Runge-Kutta method but am running into issues indexing one of my values properly. My code is:
clc;
clear all;
L = 32; M = 32; N = 32; % No. of elements
Lx = 2; Ly = 2; Lz = 2; % Size of each element
dx = Lx/L; dy = Ly/M; dz = Lz/N; % Step size
Tt = 1;
t0 = 0; % Initial condition
T = 50; % Final time
dt = (Tt-t0)/T; % Determining time step interval
% Wave characteristics
H = 2; % Wave height
a = H/2; % Amplitude
Te = 6; % Period
omega = 2*pi/Te; % Wave rotational frequency
d = 25; % Water depth
x = 0; % Location of cylinder axis
u0(1:L,1:M,1:N,1) = 0; % Setting up solution space matrix (u values)
v0(1:L,1:M,1:N,1) = 0; % Setting up solution space matrix (v values)
w0(1:L,1:M,1:N,1) = 0; % Setting up solution space matrix (w values)
[k,L] = disp(d,omega); % Solving for k and wavelength using Newton-Raphson function
%u = zeros(1,50);
%v = zeros(1,50);
%w = zeros(1,50);
time = 1:1:50;
for t = 1:T
for i = 1:L
for j = 1:M
for k = 1:N
eta(i,j,k,t) = a*cos(omega*time(1,t);
u(i,j,k,1) = u0(i,j,k,1);
v(i,j,k,1) = v0(i,j,k,1);
w(i,j,k,1) = w0(i,j,k,1);
umag(i,j,k,t) = a*omega*(cosh(k*(d+eta(i,j,k,t))))/sinh(k*d);
vmag(i,j,k,t) = 0;
wmag(i,j,k,t) = -a*omega*(sinh(k*(d+eta(i,j,k,t))))/sinh(k*d);
uRHS(i,j,k,t) = umag(i,j,k,t)*cos(k*x-omega*t);
vRHS(i,j,k,t) = vmag(i,j,k,t)*sin(k*x-omega*t);
wRHS(i,j,k,t) = wmag(i,j,k,t)*sin(k*x-omega*t);
k1x(i,j,k,t) = dt*uRHS(i,j,k,t);
k2x(i,j,k,t) = dt*(0.5*k1x(i,j,k,t) + dt*uRHS(i,j,k,t));
k3x(i,j,k,t) = dt*(0.5*k2x(i,j,k,t) + dt*uRHS(i,j,k,t));
k4x(i,j,k,t) = dt*(k3x(i,j,k,t) + dt*uRHS(i,j,k,t));
u(i,j,k,t+1) = u(i,j,k,t) + (1/6)*(k1x(i,j,k,t) + 2*k2x(i,j,k,t) + 2*k3x(i,j,k,t) + k4x(i,j,k,t));
k1y(i,j,k,t) = dt*vRHS(i,j,k,t);
k2y(i,j,k,t) = dt*(0.5*k1y(i,j,k,t) + dt*vRHS(i,j,k,t));
k3y(i,j,k,t) = dt*(0.5*k2y(i,j,k,t) + dt*vRHS(i,j,k,t));
k4y(i,j,k,t) = dt*(k3y(i,j,k,t) + dt*vRHS(i,j,k,t));
v(i,j,k,t+1) = v(i,j,k,t) + (1/6)*(k1y(i,j,k,t) + 2*k2y(i,j,k,t) + 2*k3y(i,j,k,t) + k4y(i,j,k,t));
k1z(i,j,k,t) = dt*wRHS(i,j,k,t);
k2z(i,j,k,t) = dt*(0.5*k1z(i,j,k,t) + dt*wRHS(i,j,k,t));
k3z(i,j,k,t) = dt*(0.5*k2z(i,j,k,t) + dt*wRHS(i,j,k,t));
k4z(i,j,k,t) = dt*(k3z(i,j,k,t) + dt*wRHS(i,j,k,t));
w(i,j,k,t+1) = w(i,j,k,t) + (1/6)*(k1z(i,j,k,t) + 2*k2z(i,j,k,t) + 2*k3z(i,j,k,t) + k4z(i,j,k,t));
a(i,j,k,t+1) = ((u(i,j,k,t+1))^2 + (v(i,j,k,t+1))^2 + (w(i,j,k,t+1))^2)^0.5;
end
end
end
end
At the moment, the values seem to be fine for the first iteration but then I have the error Index exceeds matrix dimension in the line calculating eta. I understand that I am not correctly indexing the eta value but am not sure how to correct this.
My goal is to update the value of eta for each loop of t and then use that new eta value for the rest of the calculations.
I'm still quite new to programming and am trying to understand indexing, especially in 3 or 4 dimensional matrices and would really appreciate any advice in correctly calculating this value.
Thanks in advance for any advice!
You declare
time = 1:1:50;
which is just a row vector but access it here
eta(i,j,k,t) = a*cos(omega*time(i,j,k,t));
as if it were an array with 4 dimensions.
To correctly access element x of time you need to use syntax
time(1,x);
(as it is a 1 x 50 array)

Matlab Genetic Algorithm for a non-genetic case

I've never used optimization tools, but I think I have to use now, so I'm a bit lost. After using the answer given by #A. Donda, I have noticed that maybe that is not the best solution because every time I run the function it gives a different matrix 'pares' and in the majority of times it says that I need more evaluations. So I was thinking that maybe the answer to my problem are Genetic Algorithms optimization, but once again I do not know how to work with them.
My first problem is described below and the answer by #A. Donda is in the only post of a answer. I really need this optimization done and I don't know how to proceed for this case with GA tools.
Thank you so much in advance again, and thank you #A. Donda for your answer.
As asked, I tried to put here the code that I was trying to explain, I hope it will result:
function opt_pares
clear all; clc; close all;
h = randi(24,8760,1);
nd = randi(365,8760,1);
veic = randi(333,8760,1);
max_veic = max(veic);
veicN = veic./max_veic;
Gh = randi(500,8760,1);
Dh = randi(500,8760,1);
Ih = Gh-Dh;
A = randi([300 800], 27,1);
max_Gh = max(Gh);
max_Dh = max(Dh);
max_Ih = max(Ih);
lat = 70;
HRA =15.*(h-12);
decl = 23.27*sind(360*(284+nd)/365);
Ii = zeros(8760,27);
Di = zeros(8760,27);
Gi = zeros(8760,27);
pares = randi([0,90],27,2);
inclin = pares(:,1);
azim = pares(:,2);
% for MATRIZC
for n=1:27
Ii(:,n) = Ih.*(sind(decl).*sind(lat).*cosd(inclin(n))-sind(decl).*cosd(lat).*sind(inclin(n)).*cosd(azim(n))+cosd(decl).*cosd(lat).*cosd(inclin(n)).*cosd(HRA)+cosd(decl).*sind(lat).*sind(inclin(n)).*cosd(azim(n)).*cosd(HRA)+cosd(decl).*sind(inclin(n)).*sind(azim(n)).*sind(HRA));
Di(:,n) = 0.5*Dh.*(1+cosd(inclin(n)));
Gi(:,n) = (Ii(:,n)+Di(:,n))*A(n,1);
end
Gparque = sum(Gi,2);
max_Gparque = max(Gparque);
GparqueN = Gparque./max_Gparque;
RMSE = sqrt(mean((GparqueN-veicN).^2));
% end
end
I don't know if it is possible, maybe this time I can be more assertive.
My main goal is to achieve the best 'RMSE' possible, to do so I have to create a matrix ('pares') where each line contains a pair of values (one value from each column).
These values have to be within a certain range(0-90). With each of this 27 pairs I have to calculate 'Ii'/'Gi'/'Di', giving me a matrix with a size like 8760*27.
Then I make a sum of 'Gi' to have 'Gparque'(vector 8760*1) and finally I I calculate 'RMSE'. When I have RMSE calculated, I have to modify the matrix 'pares' to other values that can result in a better RMSE. Once there are many combinations of 27 values that can be within the 0-90 range, I have to get a solution that can optimize this search for the minimum RMSE.
The parts that are in comments in the code (a for loop with 'pares') is the thing that I have no idea how to do, because I have to change the values of 'pares' but with some optimization criteria that can approximate the minimum of RMSE.
I hope this time I have explain this doubt better.
Thank you very much!
OK, so here is an attempt at a question. I'm not sure how useful the results will be in the end, because I don't understand the underlying problem and I don't have real data to test it with.
You were right that you need an optimization algorithm, your problem appears to be more complex than simple linear algebra. For optimization I use the function fminsearch from the Optmization Toolbox.
First the function whose value is to be optimized (the objective function) needs to be defined. Based on your code, this is
function RMSE = fun(pares)
inclin = pares(:,1);
azim = pares(:,2);
Ii = zeros(8760,27);
Di = zeros(8760,27);
Gi = zeros(8760,27);
for n=1:27
Ii(:,n) = Ih.*(sind(decl).*sind(lat).*cosd(inclin(n))-sind(decl).*cosd(lat).*sind(inclin(n)).*cosd(azim(n))+cosd(decl).*cosd(lat).*cosd(inclin(n)).*cosd(HRA)+cosd(decl).*sind(lat).*sind(inclin(n)).*cosd(azim(n)).*cosd(HRA)+cosd(decl).*sind(inclin(n)).*sind(azim(n)).*sind(HRA));
Di(:,n) = 0.5*Dh.*(1+cosd(inclin(n)));
Gi(:,n) = (Ii(:,n)+Di(:,n))*A(n,1);
end
Gparque = sum(Gi,2);
max_Gparque = max(Gparque);
GparqueN = Gparque./max_Gparque;
RMSE = sqrt(mean((GparqueN-veicN).^2));
end
Now we can call
pares_opt = fminsearch(#fun, randi([0,90],27,2))
using random initialization. The optimization takes quite a while because the objective function is not very efficiently implemented. Here's a vectorized version that does the same:
% precompute
cHRA = cosd(HRA);
sHRA = sind(HRA);
sdecl = sind(decl);
cdecl = cosd(decl);
slat = sind(lat);
clat = cosd(lat);
function RMSE = fun(pares)
% precompute
cinclin = cosd(pares(:,1))';
sinclin = sind(pares(:,1))';
cazim = cosd(pares(:,2))';
sazim = sind(pares(:,2))';
Ii = bsxfun(#times, Ih, ...
sdecl * (slat * cinclin - clat * sinclin .* cazim) ...
+ (cdecl .* cHRA) * (clat * cinclin + slat * sinclin .* cazim) ...
+ (cdecl .* sHRA) * (sinclin .* sazim));
Di = 0.5 * Dh * (1 + cinclin);
Gi = (Ii + Di) * diag(A);
Gparque = sum(Gi,2);
max_Gparque = max(Gparque);
GparqueN = Gparque./max_Gparque;
RMSE = sqrt(mean((GparqueN-veicN).^2));
end
We have not yet implemented the constraint for pares to lie within [0, 90]. A crude way to do this is to insert these lines:
if any(pares(:) < 0) || any(pares(:) > 90)
RMSE = inf;
return
end
at the beginning of the objective function.
Putting it all together:
function Raquel
h = randi(24,8760,1);
nd = randi(365,8760,1);
veic = randi(333,8760,1);
max_veic = max(veic);
veicN = veic./max_veic;
Gh = randi(500,8760,1);
Dh = randi(500,8760,1);
Ih = Gh-Dh;
A = randi([300 800], 27,1);
lat = 70;
HRA =15.*(h-12);
decl = 23.27*sind(360*(284+nd)/365);
% precompute
cHRA = cosd(HRA);
sHRA = sind(HRA);
sdecl = sind(decl);
cdecl = cosd(decl);
slat = sind(lat);
clat = cosd(lat);
pares_opt = fminsearch(#fun, randi([0,90],27,2))
function RMSE = fun(pares)
if any(pares(:) < 0) || any(pares(:) > 90)
RMSE = inf;
return
end
% precompute
cinclin = cosd(pares(:,1))';
sinclin = sind(pares(:,1))';
cazim = cosd(pares(:,2))';
sazim = sind(pares(:,2))';
Ii = bsxfun(#times, Ih, ...
sdecl * (slat * cinclin - clat * sinclin .* cazim) ...
+ (cdecl .* cHRA) * (clat * cinclin + slat * sinclin .* cazim) ...
+ (cdecl .* sHRA) * (sinclin .* sazim));
Di = 0.5 * Dh * (1 + cinclin);
Gi = (Ii + Di) * diag(A);
Gparque = sum(Gi,2);
max_Gparque = max(Gparque);
GparqueN = Gparque./max_Gparque;
RMSE = sqrt(mean((GparqueN-veicN).^2));
end
end
With simulated data, if I run the optimization twice on the same randomized data but different initial values I get different solutions. This is an indication that there is more than one local minimum of the objective function. Hopefully, this will not be the case with real data.

no oscillation after put in pid controller

I have a problem regarding putting a PID controller in my simulink file.
In my simulink file, i used pid controller to control my process. I used s-function as my process block diagram.
According Ziegler-Nichols method, for the first step we set k equal to the smallest value (0.5) so I put 0.5 in my proportional value . but there is no different between the result with controller and without controller.Even i increase or decrease proportional value.
Why this problem occur? hope someone can help me.Thank you.
my block diagram is look like below picture.refer to this picture
http://s1009.photobucket.com/albums/af218/syarinazulkifeli/?action=view&current=Untitled-1.png
Here is my s-function file:
function [sys,x0,str,ts]= reactor_sfcn(t,x,u,flag)
switch flag
case 0
[sys,x0,str,ts]=mdlInitializeSizes;
case 1,
sys = mdlDerivatives(t,x,u);
case 3,
sys = mdlOutputs(t,x,u);
case 9
sys =[];
end
function [sys,x0,str,ts] = mdlInitializeSizes()
s = simsizes;
s.NumContStates = 11;
s.NumDiscStates = 0;
s.NumOutputs = 11;
s.NumInputs = 1;
s.DirFeedthrough = 0;
s.NumSampleTimes = 1;
sys = simsizes(s) ;
x0 = [0.0258,0,0,0,0,0,0,0,8.83,303.15,303.15];
str=[] ;
ts = [0 0];
function sys = mdlDerivatives (t,x,u)
Tjo = u;
sys = reactor(t,x,Tjo);
function sys = mdlOutputs(t,x,u)
% sys(1)=x(1);
% sys(2)=x(2);
% sys(3)=x(3);
% sys(4)=x(4);
% sys(5)=x(5);
% sys(6)=x(6);
% sys(7)=x(7);
% sys(8)=x(8);
% sys(9)=x(9);
% sys(10)=x(10);
% sys(11)=x(11);
sys = x;
Link of s-function file
function DXDT = reactor(t,x,Tjo)
% -------------------------------------------- %
% Parameters definition
% -------------------------------------------- %
I = x(1); X = x(2); P0 = x(3);
P1 = x(4); P2 = x(5); Q0 = x(6);
Q1 = x(7); Q2 = x(8); M = x(9);
Tjo = x(10); T = x(11);
% ---------------------------------------
% Constants
% =======================================
%constant
M0 = 8.83;
I0 = 0.0258;
Qh = 60.44;
MMWm = 100.3;
U0 = 55.1;
% Densities
dp = 1200;
dm = 968-1.225*(T-273.15);
Rhoc = 998;
% volume expansion factor
Fev = (dm - dp)./dp ;
% volume fraction
Fvm = (1 - X)./(1 + Fev*X);
Fvp = X*(1-Fev)./(1+Fev*X);
% Total reactant mixture density
Rho = dm*Fvm + dp*Fvp;
% Reactor and jacket volume
Vc = 2;
V = 2;
% Reactor dimension
At =3.1416*0.15*0.113;
% coolant flow rate
Mc = 0.41/18;
%
Cpc = 77.22;
Cp = 199.13;
% Average coolant temperature
Tji = 303.15;
Tj =(Tji+Tjo)/2;
% Overall heat transfer coeff
alpha = 0.4;
U = U0-alpha*X;
delHp = 57800;
% ---------------------------------------
% Rates of reaction
% =======================================
% Fujita-Doolittle equation
Tgp = 114 +273.25 ;
A = 0.168-8.21e-6*(T-Tgp)^2;
B = 0.03;
g = exp(2.303*Fvm/(A + B*Fvm));
% Dissociation rate
F = 0.58;
Kd = (6.32e16*exp(-15.43e3/T));
% Propagation rate
Tep = 5.4814e-16*exp(13982/T);
Kp0 = 2.952e7*exp(-4353/(1.987*T));
Kp = (Kp0*g)./(g + (Tep*P0.*Kp0));
% Termination rate
Tet = (1.1353e-22*exp(17420/T))./I0;
Kt0 = 5.88e9*exp(-701/(1.987*T));
Kt = (Kt0*g)./(g + (Tet*P0.*Kt0));
Ktc = 0;
Ktd = Kt ;
% -------------------------------------------- %
% ODE's
% -------------------------------------------- %
dIdt = -Kd*I - ((Fev*I.*P0.*(1 - X)*Kp)./(1 + Fev*X));
dXdt = Kp*(1 - X).*P0;
dP0dt = (-Fev*P0.*P0.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P0;
dP1dt = (-Fev*P0.*P1.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P1 + (Kp*M0*(1 - X)./(1 + Fev*X)).*P0;
dP2dt = (-Fev*P0.*P2.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P2 + (Kp*M0*(1 - X)./(1 + Fev*X)).*(2*P1 + P0);
dQ0dt = (-Fev*P0.*Q0.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P0 + 0.5*Ktc*P0.*P0;
dQ1dt = (-Fev*P0.*Q1.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P1 + Ktc*P0.*P1;
dQ2dt = (-Fev*P0.*Q2.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P2 + Ktc*(P1.*P0 + P1.^2);
dMdt = (-Kp*P0*M0*(1 - X)./(1 + Fev*X)).*((Fev*(1 - X)./(1 + Fev*X)) + 1);
Rm = (-delHp)*dMdt;
dTjodt = (Mc*Cpc*(Tji-Tjo)+ U*At*(T-Tj))/(Vc*Rhoc*Cpc/18);
dTdt = (Qh+(Rm*V*MMWm)-(U*At*(T-Tj)))/(V*Rho*Cp);
DXDT =[dIdt;dXdt;dP0dt;dP1dt;dP2dt;dQ0dt;dQ1dt;dQ2dt;dMdt;dTjodt;dTdt];
First I woult check if the s-function for the process is working as expected. Disconnect the PID controller and connect a step, ramp or a sin block. This could give you a hint if the block for the process is OK and how large the static coefficient is.
A second hint: the Ziegler-Nichols method says one should increase the Kp until the system gets marginaly stable. Have you tested only one value for the proportional gain? Depending on the plant 0.5 can be really small value and way under the levels you need to control the system.
You change the Kp term but there is no change...did you give the system a step command? Is the actual and desired signal error being fed back to the PID controller? If these are satisfied and the system is still insensitive to Kp you may need to go through your model block by block to find the issue. Also, why are you modelling your plant with an S function? Implementing these can be tricky. I would much rather see the plant model in diagram form, or at least in embedded m.
For the step input I would recommend this link or google it. You need to set the Kp fairly high and then give it a step command input to destabilize the system and then vary Kp until it's stable and measure the period of oscillation.
I put together a toy model for you to test, I am inclined as well to beleive your s-function is at fault here. If you want to post/send the sfunction, I'd be glad to look at it. However, if you want to learn Ziegler-Nichols, start with a very simple model and follow the steps in the Ziegler-Nichols process. Here's the output for some of my data with a Kp = 200 and a plant of 1/(s+1):
So you can see the oscillation above. Kp = 200 is way too high, you'd have to reduce it quite a bit for Ziegler-Nichols, but I just wanted to give you an example.
EDIT I downloaded your readtor_sfcn and reactor function into two files named
reactor_sfcn.m and reactor.m Right away, I can tell why you never see any
change in the input. In the reactor_sfcn mdlDerivatives, you pass the input
to the system u as the third parameter to the reactor function. In the
reactor function I can see that the third parameter, Tjo is never read,
but overwritten with x(10). So, if Tjo is supposed to be the input parameter
it shouldn't also be a state. That will be up to you to solve that problem,
it is specific to your implementation of the plant. I've got a test model
I've used to look at your files, I'll try to put it somewhere you can get
access to it soon, but it likely won't be as useful as you analyzing what
the plant is supposed to be doing. Hope this helps!
Thanks!