The problem is to find the optimum(maximum) value of x3 in range of (-8e-4 to 2e-4) by varying kst,x1,x5 and xo)
x5=5 %Input 2 (Input 2 is a state variable and could vary in range of 4 to 15 while performing
optimization)
kst=1 %Input 3 (Input 3 is in terms of rate constant, it could vary from 0.1 to 2)
xo=4 %Input 4 (Input 4 is a state variable and could vary in range of 4 to 10)
x1=1e-7 %Input 1 could vary from 1e-9 to 1e-6
Script file
function rest = Scrpt1(t,X)
x2 = X(1);
x3 = X(2);
%Parameters
if t<15
x1 = 1e-7; %Input 1 could vary from 1e-9 to 1e-6
else x1 = 0;
end
x5=5 %Input 2 (Input 2 is a state variable and could vary in range of 4 to 15 while performing optimization)
kst=1 %Input 3 (Input 3 is in terms of rate constant, it could vary from 0.1 to 2)
xo=4 %Input 4 (Input 4 is a state variable and could vary in range of 4 to 10)
k1 = 6e7;
km1 = 0.20;
km4 = 0.003;
k3 = 2500.00;
k4 = km4/9;
km3 = km1;
LAP=1.5
% Differential equations
dx2dt = km1*x3 + km3*LAP - k1*x1*x2 + km4*x3 - k4*x2;
dx3dt = k1*x1*x2 - km1*(x3+x5+xo) - k3*x3*kst;
rest = [dx2dt; dx3dt];
end
Function file for ODE solution
options = odeset('InitialStep',0.0001,'RelTol',1e-09);
[T,Y]=ode15s(#Scrpt1,[0 60],[9e-13,0],options);
X3= Y(:,2);
plot(T,X3)
How to use fmincon or any other optimization solver for this to solve the mentioned optimization problem of finding maximum value of x3. For which values of x5,kst,xo,x1 we get maximum x3?
First you must add the values you want wo optimie as parameters of your coupled diffrential equations:
function rest = Scrpt1(t,X,X_opt)
x5=X_opt(1);
kst=X_opt(2);
xo=X_opt(3);
x1=X_opt(4);
x2 = X(1);
x3 = X(2);
%Parameters
if t>=15
x1 = 0;
end
k1 = 6e7;
km1 = 0.20;
km4 = 0.003;
k3 = 2500.00;
k4 = km4/9;
km3 = km1;
LAP=1.5;
% Differential equations
dx2dt = km1*x3 + km3*LAP - k1*x1*x2 + km4*x3 - k4*x2;
dx3dt = k1*x1*x2 - km1*(x3+x5+xo) - k3*x3*kst;
rest = [dx2dt; dx3dt];
end
then you have to wirte a wrapper function you want to minimize. Because you want to maxmize x3 you have to add an minus to your objective value.
function max_X3=fun(X_opt)
tspan=[0 60];
y0=[9e-13,0];
options = odeset('InitialStep',0.0001,'RelTol',1e-09);
[~,y] = ode15s(#(t,y) Scrpt1(t,y,X_opt), tspan, y0,options);
max_X3=-max(y(:,2));
end
Finally you can use fmincon like this:
% x5, kst, xo, x1
initial_search_point=[5, 1, 4, 1e-7]
lower_bounds=[4, 0.1, 4, 1e-9]
upper_bounds=[15, 2, 10, 1e-6]
fmincon(#fun,initial_search_point,[],[],[],[], lower_bounds,upper_bounds)
Below is a solution in Gekko that can run in Python or with a Python interface to MATLAB.
import numpy as np
from gekko import GEKKO
n = 121; t = np.linspace(0,60,n)
m = GEKKO(remote=False)
m.time = t
k1 = 6e7; km1 = 0.20; km4 = 0.003;
k3 = 2500.00; k4 = km4/9;
km3 = km1; LAP=1.5
x5 = m.FV(value=5,lb=4,ub=15); x5.STATUS = 1
kst = m.FV(value=1,lb=0.1,ub=2); kst.STATUS = 1
xo = m.FV(value=4,lb=4,ub=10); xo.STATUS = 1
x1 = m.FV(value=[1e-17 if t[i]<15 else 0 for i in range(n)],\
lb=1e-9,ub=1e-6)
x2,x3 = m.Array(m.Var,2)
x3.value = -0.00032
x3.lower = -8e-4
x3.upper = 2e-4
m.Equations([x2.dt()==km1*x3+km3*LAP-k1*x1*x2+km4*x3-k4*x2,
x3.dt()==k1*x1*x2-km1*(x3+x5+xo)-k3*x3*kst])
m.Maximize(x3)
m.options.SOLVER = 1
m.options.IMODE = 6
m.solve()
import matplotlib.pyplot as plt
plt.plot(m.time,x3)
plt.show()
The initial condition for x2 and x3 are not defined.
Number of state variables: 483
Number of total equations: - 480
Number of slack variables: - 0
---------------------------------------
Degrees of freedom : 3
----------------------------------------------
Dynamic Control with APOPT Solver
----------------------------------------------
Iter Objective Convergence
0 4.99217E+02 2.99935E-01
1 6.07645E-02 4.31439E-05
2 3.25294E-02 3.04712E-05
3 3.41027E-02 8.96081E-05
4 3.31615E-02 2.48287E-06
5 3.31615E-02 2.22045E-16
6 3.31615E-02 2.22045E-16
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 2.189999999245629E-002 sec
Objective : 3.316154172805905E-002
Successful solution
---------------------------------------------------
Related
I am using Matlab fminsearch to minimize a equation with two variables sum((interval-5).^2, 2)*factor
The interval is a vector contains 5 values. They can be only picked sequentially from value 1 to 30 with step size is 1. The factor is a value from 0.1 to 0.9.
The code is below. I think the interval values are correct but factor value is wrong.
Interval value: [3 4 5 6 7]
factor value: 0.6
Final Output: 6
I think the factor value should be 0.1 and final output should be 1 as global minimum.
%% initialization of problem parameters
minval = 1;
maxval = 30;
step = 1;
count = 5;
minFactor = 0.1;
maxFactor = 0.9;
%% the objective function
fun = #(interval, factor) sum((interval-5).^2, 2)*factor;
%% a function that generates an interval from its initial value
getinterval = #(start) floor(start) + (0:(count-1)) * step;
getfactor =#(start2) floor(start2 * 10)/10;
%% a modified objective function that handles constraints
objective = #(start, start2) f(start, fun, getinterval, minval, maxval, getfactor, minFactor, maxFactor);
%% finding the interval that minimizes the objective function
start = [(minval+maxval)/2 (minFactor+maxFactor)/2];
y = fminsearch(objective, start);
bestvals = getinterval(y(1));
bestfactor = getfactor(y(2));
eval = fun(bestvals,bestfactor);
disp(bestvals)
disp(bestfactor)
disp(eval)
The code uses the following function f.
function y = f(start, fun, getinterval, minval, maxval, getfactor, minFactor, maxFactor)
interval = getinterval(start(1));
factor = getfactor(start(2));
if (min(interval) < minval) || (max(interval) > maxval) || (factor<minFactor) || (factor>maxFactor)
y = Inf;
else
y = fun(interval, factor);
end
end
I tried the GA function as Adam suggested. I changed it to two different sets given the fact that my variables are from different ranges and steps. Here are my changes.
step1 = 1;
set1 = 1:step1:30;
step2 = 0.1;
set2 = 0.1:step2:0.9;
% upper bound depends on how many integer used for mapping
ub = zeros(1, nvar);
ub(1) = length(set1);
ub(2) = length(set2);
Then, I changed the objective function
% objective function
function y = f(x,set1, set2)
% mapping
xmap1 = set1(x(1));
xmap2 = set2(x(2));
y = (40 - xmap1)^xmap2;
end
After I run the code, I think I get the answer I want.
Illustration of ga() optimizing over a set
objective function
f = xmap(1) -2*xmap(2)^2 + 3*xmap(3)^3 - 4*xmap(4)^4 + 5*xmap(5)^5;
set
set = {1, 5, 10, 15, 20, 25, 30}
The set contains 7 elements:
index 1 is equivalent to 1 set(1)
index 2 to 5...
index 7 to 30 set(7)
The input to ga will be in the range 1 to 7.
The lower bound is 1, and the upper bound is 7.
ga optimization is done by computing the fitness function: evaluate f over the input variable.
The tips here will be using integer as input and later while evaluating f use the mapping discussed above.
The code is as follows
% settting option for ga
opts = optimoptions(#ga, ...
'PopulationSize', 150, ...
'MaxGenerations', 200, ...
'EliteCount', 10, ...
'FunctionTolerance', 1e-8, ...
'PlotFcn', #gaplotbestf);
% number of variable
nvar = 5;
% lower bound is 1
lb = ones(1, nvar);
step = 2.3;
set = 1:step:30;
limit = length(set);
% upper bound depends on how many integers are used for mapping
ub = limit.*lb;
% maximization used the opposite of f as ga only does minimization
% asking ga to minimize -f is equivalent to maximizing f
fitness = #(x)-1*f(x, step, set);
[xbest, fbest, exitflag] = ga(fitness,nvar, [], [], [], [], lb, ub, [], 1:nvar, opts);
% get the discrete integer value and find their corresponding value in the set
mapx = set(xbest)
% objective function
function y = f(x, step, set)
l = length(x);
% mapping
xmap = zeros(1, l);
for i = 1:l
xmap(i) = set(x(i));
end
y = xmap(1) -2*xmap(2)^2 + 3*xmap(3)^3 - 4*xmap(4)^4 + 5*xmap(5)^5;
end
I am having a system of 6 ode.
What i am trying to manage, is to solve it, for several different values of one of its parameters, parameter 'p', using a for loop at the integration.
I have managed to do it using ode45, however,
using a non-built-in integrator, it seems i am making a mistake and I don't get back the same values, or graphs.
I would appreciate any feedback on my code on what went wrong
Using ODE45
p = -100:+1:350;
time = 0:.05:3;
initial = [0 0 0 0 0 0];
x = NaN(length(time),length(initial),length(p));
for i=1:length(p)
[t,x(:,:,i)] = ode45(#ode,time,initial,[],p(i));
end
figure(1)
plot3(squeeze(x(:,1,:)),squeeze(x(:,2,:)),squeeze(x(:,3,:)))
function dx = ode(~,x,p)
bla bla
end
Using the non-built-in integrator
figure
hold all
for p = -100:+1:350
inicond = [0 0 0 0 0 0];
dt = 0.01;
time = 0:dt:10;
[y] = integrator(#ode,inicond,time,dt,p);
x1 = y(:,1);
x2 = y(:,2);
x3 = y(:,3);
figure(1)
plot3(x1,x2,x3)
axis equal
legend('-DynamicLegend')
end
function [y] = integrator(ode,inicond,time,dt,p)
y = NaN(length(time),length(inicond));
y(1,:) = inicond;
for j=2:length(time)
k1 = dt*ode(y(j-1,:),p);
k2 = dt*ode(y(j-1,:)+k1/2,p);
k3 = dt*ode(y(j-1,:)+k2/2,p);
k4 = dt*ode(y(j-1,:)+k3,p);
y(j,:) = y(j-1,:) + k1/6+k2/3+k3/3+k4/6;
end
end
function [dydt] = ode(y,p)
bla bla
end
Using the non-built-in function to solve Van der Pol for multiple 'epsilon'values: This works., while for the previous it doesnt..
figure
hold all
for epsilon = 0:.2:5
inicond = [0.2 0.8];
dt = 0.1;%timestep for integration
time = 0:dt:100;
[x] = integrator(#VanDerPol,inicond,time,dt,epsilon);
xdot = x(:,2);
x = x(:,1);
figure(1)
plot(x,xdot,'DisplayName',sprintf('epsilon = %1.0f',epsilon))
figure(2)
plot3(time, x,xdot)
axis equal
legend('-DynamicLegend')
end
function [x] = integrator(VanDerPol,inicond,time,dt,epsilon)
x = NaN(length(time),length(inicond));
x(1,:) = inicond;
%%% ACTUAL CALL OF INTEGRATOR %%%%%%%%%%%%%%
for j=2:length(time)
k1 = dt*feval(VanDerPol,x(j-1,:),epsilon);
k2 = dt*feval(VanDerPol,x(j-1,:)+k1/2,epsilon);
k3 = dt*feval(VanDerPol,x(j-1,:)+k2/2,epsilon);
k4 = dt*feval(VanDerPol,x(j-1,:)+k3,epsilon);
x(j,:) = x(j-1,:) + k1/6+k2/3+k3/3+k4/6;
end
end
function [dxdt] = VanDerPol(x,epsilon)
dxdt=NaN(1,2);
dxdt(1,1) = x(:,2);
dxdt(1,2) = epsilon*(1 - x(:,1)^2)*x(:,2) - x(:,1);
end
I am afraid that with the second way, the values of all the repetitions might not be stored correctly and for this reason the values of the occurring matrices after integration, hardly vary one from another
Assume we have three equations:
eq1 = x1 + (x1 - x2) * t - X == 0;
eq2 = z1 + (z1 - z2) * t - Z == 0;
eq3 = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1 == 0;
while six of known variables are:
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
So we are looking for three unknown variables that are:
X , Z and t
I wrote two method to solve it. But, since I need to run these code for 5.7 million data, it become really slow.
Method one (using "solve"):
tic
S = solve( eq1 , eq2 , eq3 , X , Z , t ,...
'ReturnConditions', true, 'Real', true);
toc
X = double(S.X(1))
Z = double(S.Z(1))
t = double(S.t(1))
results of method one:
X = 316190;
Z = 234060;
t = -2.9280;
Elapsed time is 0.770429 seconds.
Method two (using "fsolve"):
coeffs = [a,b,x1,x2,z1,z2]; % Known parameters
x0 = [ x2 ; z2 ; 1 ].'; % Initial values for iterations
f_d = #(x0) myfunc(x0,coeffs); % f_d considers x0 as variables
options = optimoptions('fsolve','Display','none');
tic
M = fsolve(f_d,x0,options);
toc
results of method two:
X = 316190; % X = M(1)
Z = 234060; % Z = M(2)
t = -2.9280; % t = M(3)
Elapsed time is 0.014 seconds.
Although, the second method is faster, but it still needs to be improved. Please let me know if you have a better solution for that. Thanks
* extra information:
if you are interested to know what those 3 equations are, the first two are equations of a line in 2D and the third equation is an ellipse equation. I need to find the intersection of the line with the ellipse. Obviously, we have two points as result. But, let's forget about the second answer for simplicity.
My suggestion it's to use the second approce,which it's the recommended by matlab for nonlinear equation system.
Declare a M-function
function Y=mysistem(X)
%X(1) = X
%X(2) = t
%X(3) = Z
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
Y(1,1) = x1 + (x1 - x2) * X(2) - X(1);
Y(2,1) = z1 + (z1 - z2) * X(2) - X(3);
Y(3,1) = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1;
end
Then for solving use
x0 = [ x2 , z2 , 1 ];
M = fsolve(#mysistem,x0,options);
If you may want to reduce the default precision by changing StepTolerance (default 1e-6).
Also for more increare you may want to use the jacobian matrix for greater efficencies.
For more reference take a look in official documentation:
fsolve Nonlinear Equations with Analytic Jacobian
Basically giving the solver the Jacobian matrix of the system(and special options) you can increase method efficency.
A filter g is called separable if it can be expressed as the multiplication of two vectors grow and gcol . Employing one dimensional filters decreases the two dimensional filter's computational complexity from O(M^2 N^2) to O(2M N^2) where M and N are the width (and height) of the filter mask and the image respectively.
In this stackoverflow link, I wrote the equation of a Gabor filter in the spatial domain, then I wrote a matlab code which serves to create 64 gabor features.
According to the definition of separable filters, the Gabor filters are parallel to the image axes - theta = k*pi/2 where k=0,1,2,etc.. So if theta=pi/2 ==> the equation in this stackoverflow link can be rewritten as:
The equation above is extracted from this article.
Note: theta can be extented to be equal k*pi/4. By comparing to the equation in this stackoverflow link, we can consider that f= 1 / lambda.
By changing my previous code in this stackoverflow link, I wrote a matlab code to make the Gabor filters separable by using the equation above, but I am sure that my code below is not correct especially when I initialized the gbp and glp equations. That is why I need your help. I will appreciate your help very much.
Let's show now my code:
function [fSiz,filters1,filters2,c1OL,numSimpleFilters] = init_gabor(rot, RF_siz)
image=imread('xxx.jpg');
image_gray=rgb2gray(image);
image_gray=imresize(image_gray, [100 100]);
image_double=double(image_gray);
rot = [0 45 90 135]; % we have four orientations
RF_siz = [7:2:37]; %we get 16 scales (7x7 to 37x37 in steps of two pixels)
minFS = 7; % the minimum receptive field
maxFS = 37; % the maximum receptive field
sigma = 0.0036*RF_siz.^2 + 0.35*RF_siz + 0.18; %define the equation of effective width
lambda = sigma/0.8; % it the equation of wavelength (lambda)
G = 0.3; % spatial aspect ratio: 0.23 < gamma < 0.92
numFilterSizes = length(RF_siz); % we get 16
numSimpleFilters = length(rot); % we get 4
numFilters = numFilterSizes*numSimpleFilters; % we get 16x4 = 64 filters
fSiz = zeros(numFilters,1); % It is a vector of size numFilters where each cell contains the size of the filter (7,7,7,7,9,9,9,9,11,11,11,11,......,37,37,37,37)
filters1 = zeros(max(RF_siz),numFilters);
filters2 = zeros(numFilters,max(RF_siz));
for k = 1:numFilterSizes
for r = 1:numSimpleFilters
theta = rot(r)*pi/180;
filtSize = RF_siz(k);
center = ceil(filtSize/2);
filtSizeL = center-1;
filtSizeR = filtSize-filtSizeL-1;
sigmaq = sigma(k)^2;
for x = -filtSizeL:filtSizeR
fx = exp(-(x^2)/(2*sigmaq))*cos(2*pi*x/lambda(k));
f1(x+center,1) = fx;
end
for y = -filtSizeL:filtSizeR
gy = exp(-(y^2)/(2*sigmaq));
f2(1,y+center) = gy;
end
f1 = f1 - mean(mean(f1));
f1 = f1 ./ sqrt(sum(sum(f1.^2)));
f2 = f2 - mean(mean(f2));
f2 = f2 ./ sqrt(sum(sum(f2.^2)));
p = numSimpleFilters*(k-1) + r;
filters1(1:filtSize,p)=f1;
filters2(p,1:filtSize)=f2;
convv1=imfilter(image_double, filters1(1:filtSize,p),'conv');
convv2=imfilter(double(convv1), filters2(p,1:filtSize),'conv');
figure
imagesc(convv2);
colormap(gray);
end
end
I think the code is correct provided your previous version of Gabor filter code is correct too. The only thing is that if theta = k * pi/4;, your formula here should be separated to:
fx = exp(-(x^2)/(2*sigmaq))*cos(2*pi*x/lambda(k));
gy = exp(-(G^2 * y^2)/(2*sigmaq));
To be consistent, you may use
f1(1,x+center) = fx;
f2(y+center,1) = gy;
or keep f1 and f2 as it is but transpose your filters1 and filters2 thereafter.
Everything else looks good to me.
EDIT
My answer above works for theta = k * pi/4;, with other angles, based on your paper,
x = i*cos(theta) - j*sin(theta);
y = i*sin(theta) + j*cos(theta);
fx = exp(-(x^2)/(2*sigmaq))*exp(sqrt(-1)*x*cos(theta));
gy = exp(-(G^2 * y^2)/(2*sigmaq))*exp(sqrt(-1)*y*sin(theta));
The final code will be:
function [fSiz,filters1,filters2,c1OL,numSimpleFilters] = init_gabor(rot, RF_siz)
image=imread('xxx.jpg');
image_gray=rgb2gray(image);
image_gray=imresize(image_gray, [100 100]);
image_double=double(image_gray);
rot = [0 45 90 135];
RF_siz = [7:2:37];
minFS = 7;
maxFS = 37;
sigma = 0.0036*RF_siz.^2 + 0.35*RF_siz + 0.18;
lambda = sigma/0.8;
G = 0.3;
numFilterSizes = length(RF_siz);
numSimpleFilters = length(rot);
numFilters = numFilterSizes*numSimpleFilters;
fSiz = zeros(numFilters,1);
filters1 = zeros(max(RF_siz),numFilters);
filters2 = zeros(numFilters,max(RF_siz));
for k = 1:numFilterSizes
for r = 1:numSimpleFilters
theta = rot(r)*pi/180;
filtSize = RF_siz(k);
center = ceil(filtSize/2);
filtSizeL = center-1;
filtSizeR = filtSize-filtSizeL-1;
sigmaq = sigma(k)^2;
for x = -filtSizeL:filtSizeR
fx = exp(-(x^2)/(2*sigmaq))*exp(sqrt(-1)*x*cos(theta));
f1(1, x+center) = fx;
end
for y = -filtSizeL:filtSizeR
gy=exp(-(y^2)/(2*sigmaq))*exp(sqrt(-1)*y*sin(theta));
f2(y+center,1) = gy;
end
f1 = f1 - mean(mean(f1));
f1 = f1 ./ sqrt(sum(sum(f1.^2)));
f2 = f2 - mean(mean(f2));
f2 = f2 ./ sqrt(sum(sum(f2.^2)));
p = numSimpleFilters*(k-1) + r;
filters1(1:filtSize,p)=f1;
filters2(p,1:filtSize)=f2;
convv1=imfilter(image_double, filters1(1:filtSize,p),'conv');
convv2=imfilter(double(convv1), filters2(p,1:filtSize),'conv');
figure
imagesc(imag(convv2));
colormap(gray);
end
end
I wrote a python function to get the parameters of the following cosine function:
param = Parameters()
param.add( 'amp', value = amp_guess, min = 0.1 * amp_guess, max = amp_guess )
param.add( 'off', value = off_guess, min = -10, max = 10 )
param.add( 'shift', value = shift_guess[0], min = 0, max = 2 * np.pi, )
fit_values = minimize( self.residual, param, args = ( azi_unique, los_unique ) )
def residual( self, param, azi, data ):
"""
Parameters
----------
Returns
-------
"""
amp = param['amp'].value
off = param['off'].value
shift = param['shift'].value
model = off + amp * np.cos( azi - shift )
return model - data
In Matlab how can get the amplitude, offset and shift of the cosine function?
My experience tells me that it's always good to depend as little as possible on toolboxes. For your particular case, the model is simple and doing it manually is pretty straightforward.
Assuming that you have the following model:
y = B + A*cos(w*x + phi)
and that your data is equally-spaced, then:
%// Create some bogus data
A = 8;
B = -4;
w = 0.2;
phi = 1.8;
x = 0 : 0.1 : 8.4*pi;
y = B + A*cos(w*x + phi) + 0.5*randn(size(x));
%// Find kick-ass initial estimates
L = length(y);
N = 2^nextpow2(L);
B0 = (max(y(:))+min(y(:)))/2;
Y = fft(y-B0, N)/L;
f = 5/(x(2)-x(1)) * linspace(0,1,N/2+1);
[A0,I] = max( 2*abs(Y(1:N/2+1)) );
w0 = f(I);
phi0 = 2*imag(Y(I));
%// Refine the fit
sol = fminsearch(#(t) sum( (y(:)-t(1)-t(2)*cos(t(3)*x(:)+t(4))).^2 ), [B0 A0 w0 phi0])
Results:
sol = %// B was -4 A was 8 w was 0.2 phi was 1.8
-4.0097e+000 7.9913e+000 1.9998e-001 1.7961e+000
MATLAB has a function called lsqcurvefit in the optimisation toolbox:
lsqcurvefit(fun,X0,xdata,ydata,lbound,ubound);
where fun is the function to fit, x0 is the initial parameter guess, xdata and ydata are self-explanatory, and lbound and ubound are the lower and upper bounds to the parameters. So, for instance, you might have a function:
% x(1) = amp
% x(2) = shift
% x(3) = offset
% note cosd instead of cos, because your data appears to be in degrees
cosfit = #(x,xdata) x(1) .* cosd(xdata - x(2)) + x(3);
You would then call the lsqcurvefit function as follows:
guess = [7,150,0.5];
lbound = [-10,0,-10]
ubound = [10,360,10]
fit_values = lsqcurvefit(cosfit,guess,azi_unique,los_unique,lbound,ubound);