I have a MATLAB code that solves a large scale ODE system of following type
function [F] = myfun(t,C,u)
u here is a time dependent vector used as a input in the function myfun. My current code reads as:-
u = zeros(4,1);
u(1) = 0.1;
u(2) = 0.1;
u(3) = 5.01/36;
u(4) = 0.1;
C0 = zeros(15*4*20+12,1);
options = odeset('Mass',Mf,'RelTol',1e-5,'AbsTol',1e-5);
[T,C] = ode15s(#OCFDonecolumnA, [0,5000] ,C0,options,u);
I would like to have the entire time domain split into 5 different sections and have the elements of u take different values at different times(something like a multiple step function). what would be the best way to code it considering that I later want to solve a optimization problem to determine values of u for each time interval in the domain [0,5000].
Thanks
ode15s expects your model function to accept a parameter t for time and a vector x (or C as you named it) of differential state variables. Since ode15s will not let us pass in another vector u of control inputs, I usually wrap the ODE function ffcn inside a model function:
function [t, x] = model(x0, t_seg, u)
idx_seg = 0;
function y = ffcn(t, x)
% simple example of exponential growth
y(1) = u(idx_seg) * x(1)
end
...
end
In the above, the parameters of model are the initial state values x0, the vector of switching times t_seg, and the vector u of control input values in different segments. You can see that idx_seg is visible from within ffcn. This allows us to integrate the model over all segments (replace ... in the above with the following):
t_start = 0;
t = t_start;
x = x0;
while idx_seg < length(t_seg)
idx_seg = idx_seg + 1;
t_end = t_seg(idx_seg);
[t_sol, x_sol] = ode15s(#ffcn, [t_start, t_end], x(end, :));
t = [t; t_sol(2 : end)];
x = [x; x_sol(2 : end, :)];
t_start = t_end;
end
In the first iteration of the loop, t_start is 0 and t_end is the first switching point. We use ode15s now to only integrate over this interval, and our ffcn evaluates the ODE with u(1). The solution y_sol and the corresponding time points t_sol are appended to our overall solution (t, x).
For the next iteration, we set t_start to the end of the current segment and set the new t_end to the next switching point. You can also see that the last element of t_seg must be the time at which the simulation ends. Importantly, we pass to ode15s the current tail y(end, :) of the simulated trajectory as the initial state vector of the next segment.
In summary, the function model will use ode15s to simulate the model segment by segment and return the overall trajectory y and its time points t. You could convince yourself with an example like
[t, x] = model1(1, [4, 6, 12], [0.4, -0.7, 0.3]);
plot(t, x);
which for my exponential growth example should yield
For your optimization runs, you will need to write an objective function. This objective function can pass u to model, and then calculate the merit associated with u by looking at x.
Related
I am simulating a dynamic system using the ode15s(..) MATLAB solver:
tspan = 0:0.01:8;
[t,theta] = ode15s(#ode_simulation, tspan, theta)
Inside the ode_simulation(..) function I am computing a signal u which does an exact job. Some lines of this function are these:
function d_theta = ode_simulation(t,theta)
...
...
u = (K*g*s_q)/e;
d_theta = [theta(2) ; ... ];
end
The code executes well but I would like to obtain the values of variable u at the specific time instants defined by tspan. So, the simulation return a 801x4 matrix for the theta solution and I also want a 801x1 vector containing the corresponding u values. I tried storing them as the simulation runs but obviously all the values the ODE-Solver obtains throughout all its steps are being stored, resulting in an much bigger vector. How can I store and plot the values of u variable at the specific time steps defined by tspan ? Here are the links for my code:
main_code
ode_simulation
function h = uniform_hysteretic_quantizer(u,last,D)
if (u >= last + D)
h = last + D;
elseif (u <= last - D)
h = last - D;
else
h = last;
end
end
I'm trying to verify if my implementation of Logistic Regression in Matlab is good. I'm doing so by comparing the results I get via my implementation with the results given by the built-in function mnrfit.
The dataset D,Y that I have is such that each row of D is an observation in R^2 and the labels in Y are either 0 or 1. Thus, D is a matrix of size (n,2), and Y is a vector of size (n,1)
Here's how I do my implementation:
I first normalize my data and augment it to include the offset :
d = 2; %dimension of data
M = mean(D) ;
centered = D-repmat(M,n,1) ;
devs = sqrt(sum(centered.^2)) ;
normalized = centered./repmat(devs,n,1) ;
X = [normalized,ones(n,1)];
I will be doing my calculations on X.
Second, I define the gradient and hessian of the likelihood of Y|X:
function grad = gradient(w)
grad = zeros(1,d+1) ;
for i=1:n
grad = grad + (Y(i)-sigma(w'*X(i,:)'))*X(i,:) ;
end
end
function hess = hessian(w)
hess = zeros(d+1,d+1) ;
for i=1:n
hess = hess - sigma(w'*X(i,:)')*sigma(-w'*X(i,:)')*X(i,:)'*X(i,:) ;
end
end
with sigma being a Matlab function encoding the sigmoid function z-->1/(1+exp(-z)).
Third, I run the Newton algorithm on gradient to find the roots of the gradient of the likelihood. I implemented it myself. It behaves as expected as the norm of the difference between the iterates goes to 0. I wrote it based on this script.
I verified that the gradient at the wOPT returned by my Newton implementation is null:
gradient(wOP)
ans =
1.0e-15 *
0.0139 -0.0021 0.2290
and that the hessian has strictly negative eigenvalues
eig(hessian(wOPT))
ans =
-7.5459
-0.0027
-0.0194
Here's the wOPT I get with my implementation:
wOPT =
-110.8873
28.9114
1.3706
the offset being the last element. In order to plot the decision line, I should convert the slope wOPT(1:2) using M and devs. So I set :
my_offset = wOPT(end);
my_slope = wOPT(1:d)'.*devs + M ;
and I get:
my_slope =
1.0e+03 *
-7.2109 0.8166
my_offset =
1.3706
Now, when I run B=mnrfit(D,Y+1), I get
B =
-1.3496
1.7052
-1.0238
The offset is stored in B(1).
I get very different values. I would like to know what I am doing wrong. I have some doubt about the normalization and 'un-normalization' process. But I'm not sure, may be I'm doing something else wrong.
Additional Info
When I tape :
B=mnrfit(normalized,Y+1)
I get
-1.3706
110.8873
-28.9114
which is a rearranged version of the opposite of my wOPT. It contains exactly the same elements.
It seems likely that my scaling back of the learnt parameters is wrong. Otherwise, it would have given the same as B=mnrfit(D,Y+1)
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.
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
Is is it possible to use an ODE solver, such as ode45, and still be able to 'change' values for the parameters within the called function?
For example, if I were to use the following function:
function y = thisode(t, Ic)
% example derivative function
% parameters
a = .05;
b = .005;
c = .0005;
d = .00005;
% state variables
R = Ic(1);
T = Ic(2);
y = [(R*a)-(T/b)+d; (d*R)-(c*T)];
with this script:
clear all
% Initial conditions
It = [0.06 0.010];
% time steps
time = 0:.5:10;
% ODE solver
[t,Ic1] = ode45(#thisode, time, It);
everything works as I would expect. However, I would like a way to easily change the parameter values, but still run multiple iterations of the ODE solver with just one function and one script. However, it does not seem like I can just add more terms to the ODE solver, for example:
function y = thisode(t, Ic, P)
% parameters
a = P(1);
b = P(2);
c = P(3);
d = P(4);
% state variables
R = Ic(1);
T = Ic(2);
y = [(R*a)-(T/b)+d; (d*R)-(c*T)];
with this script:
clear all
% Initial conditions
It = [0.06 0.010];
P1 = [.05 .005 .0005 .00005]
% time steps
time = 0:.5:10;
% ODE solver
[t,Ic1] = ode45(#thisode, time, It, [], P1);
does not work. I guess I know this shouldn't work, but I have been unable to come up with a solution. I was also considering an if statement within the function and then hard coding several sets of parameters based to be used (e.g use set 1 when P == 1, set 2 when P == 2, etc) but this also did not work as I don't where to call the set to be used with an ODE. Any tips or suggestion on how to use one function and one script with an ODE solver while being able to change parameter values would be much appreciated.
Thank you,
Mike
You'll have to call the function differently:
[t,Ic1] = ode45(#(t,y) thisode(t,y,P1), time, It);
The function ode45 assumes all functions passed to it accept only an t and a y. The above call is a standard trick to get Matlab to pass P1, while ode45 will pass it t and y on every call.