I know this question is really too basic, but I am stuck since I am new to MATLAB. The problem is I do not know how to use for-loop to show three output of V in one run for different initial points.
I would like to have an output like the following:
V1 (first initial point)-----V2(second initial point)-----V3(third initial point)
This is my code:
%variables
ENG1=0.52;
ENG2 = [0.00139;0.00149;0.00122;0.00130;0.000866;0.000731;0.001002;0.001285];
ENG3 = zeros(8,1);
%6.2.2) minimization term
fun = #(V) abs(ENG1 - V'*ENG2);
%6.2.3) constrains:
Aeq = [ENG3';ones(1,8)];
beq = [0;1];
lb = zeros(8,1); %lower bound
ub = ones(8,1); %upper bound
V0 = rand(8,1);V0 = V0/sum(V0); %initial guess
options = optimset('Display', 'off'); %supressing extra unnecessary outputs.
for i=1:3
V(i) = fmincon(fun,V0,[],[],Aeq,beq,lb,ub,[],options)
end
If you store your different initial conditions as columns of a matrix you can do it in the following way:
V0 = rand(8,3); %3 columns of initial guesses
V0 = bsxfun(#rdivide, V0, sum(V0));
% V0 = V0./sum(V0); % similar to previous line, but only supported from R2016b
V = zeros(size(V0)); % preallocate memory for efficiency
for i=1:3
V(:, i) = fmincon(fun,V0(:, i),[],[],Aeq,beq,lb,ub,[],options);
end
Note the use of the elementwise division (./) to normalise your initial guesses.
Note that V(:, i) selects all elements of column i.
See this post, for more information about the compatibility issue.
Related
I have written a script to compute and solve a simple inverted pendalum system.Now suppose that I want to solve the nonlinear dynamic equation of the system with ODE45 function with different values of initial conditions.How could I use a for loop to solve for state vector of X for different values of initial conditions?I wrote a for loop to do that but I could not get the answer I wanted.Help me please.Here are my function and mfile as follows:
function xDot = of(x,g,L,u)
xDot = zeros(2,1);
xDot(1) = x(2);
xDot(2) = ((g./L)*sin(x(1)))+u;
end
And this is my main code:
clc;
clear;close all;
%% Solve The Nonlinear Equation
L = 1;
g = 9.81;
h = 0.25;
t = [0:h:5];
A = [0 1;(g/L) 0];
B =[0 1]';
Ics = [pi,0;pi/2 0;pi/5 0;0.001 0;pi 0.5;pi/2 0.5;pi/5 0.5;0.001 0.5];
[Poles,~] = eig(A); %Poles Of Closed LOop System
R = 0.01;
Q = eye(2);
K = lqr(A,B,Q,R);
u = #(x)-K*(x);
for i=1:size(Ics,1)
[~,X] = ode45(#(t,x)of(x,g,L,u(x)),t,Ics(i,:));
end
Also note that I want the first column of X vector which is the angular displacements of the pendulum in each iteration because the second column of X vector in ODE45 is always the Derivative of the main state vector.
You can store all the integration outputs for the different initial conditions in a 3D array.
The number of rows of Xout will equal the number of time steps at which you want to evaluate your solution, so numel(t). The number of columns is the number of states, and then the third dimension will be the number of initial conditions you want to test.
Xout = zeros(numel(t), size(Ics, 2), size(Ics, 1)); % initialize the 3D array
for k = 1:size(Ics, 1)
[~, Xout(:, :, k)] = ode45(#(t, x)of(x, g, L, u(x)), t, Ics(k, :));
end
The following is my code. I try to model PFR in Matlab using ode23s. It works well with one component irreversible reaction. But when extending more dependent variables, 'Matrix dimensions must agree' problem shows. Have no idea how to fix it. Is possible to use other software to solve similar problems?
Thank you.
function PFR_MA_length
clear all; clc; close all;
function dCdt = df(t,C)
dCdt = zeros(N,2);
dCddt = [0; -vo*diff(C(:,1))./diff(V)-(-kM*C(2:end,1).*C(2:end,2)-kS*C(2:end,1))];
dCmdt = [0; -vo*diff(C(:,2))./diff(V)-(-kM*C(2:end,1).*C(2:end,2))];
dCdt(:,1) = dCddt;
dCdt(:,2) = dCmdt;
end
kM = 1;
kS = 0.5; % assumptions of the rate constants
C0 = [2, 2]; % assumptions of the entering concentration
vo = 2; % volumetric flow rate
volume = 20; % total volume of reactor, spacetime = 10
N = 100; % number of points to discretize the reactor volume on
init = zeros(N,2); % Concentration in reactor at t = 0
init(1,:) = C0; % concentration at entrance
V = linspace(0,volume,N)'; % discretized volume elements, in column form
tspan = [0 20];
[t,C] = ode23s(#(t,C) df(t,C),tspan,init);
end
'''
You can put a break point on the line that computes dCddt and observe that the size of the matrices C and V are different.
>> size(C)
ans =
200 1
>> size(V)
ans =
100 1
The element-wise divide operation, ./, between these two variables would then result in the error that you mentioned.
Per ode23s's help, the output of the call to dCdt = df(t,C) needs to be a vector. However, you are returning a matrix of size 100x2. In the next call to the same function, ode32s converts it to a vector when computing the value of C, hence the size 200x1.
In the GNU octave interpretation of Matlab behavior, one has to explicitly make sure that the solver only sees flat one-dimensional state vectors. These have to be translated forward and back in the application of the model.
Explicitly reading the object A as flat array A(:) forgets the matrix dimension information, these can be added back with the reshape(A,m,n) command.
function dCdt = df(t,C)
C = reshape(C,N,2);
...
dCdt = dCdt(:);
end
...
[t,C] = ode45(#(t,C) df(t,C), tspan, init(:));
The equations can be found here. As you can see it is set of 8 scalar equations closed to 3 matrix ones. In order to let Matlab know that equations are matrix - wise, I declare variable time dependent vector functions as:
syms t p1(t) p2(t) p3(t)
p(t) = symfun([p1(t);p2(t);p3(t)], t);
p = formula(p(t)); % allows indexing for vector p
% same goes for w(t) and m(t)...
Known matrices are declared as follows:
A = sym('A%d%d',[3 3]);
Fq = sym('Fq%d%d',[2 3]);
Im = diag(sym('Im%d%d',[1 3]));
The system is now ready to be modeled according to guide:
eqs = [diff(p) == A*w + Fq'*m,...
diff(w) == -Im*p,...
Fq*w == 0];
vars = [p; w; m];
At this point, when I try to reduce index (since it equals 2), I receive following error:
[DAEs,DAEvars] = reduceDAEIndex(eqs,vars);
Error using sym/reduceDAEIndex (line 95)
Expecting as many equations as variables.
The error would not arise if we had declared all variables as scalars:
syms A Im Fq real p(t) w(t) m(t)
Quoting symfun documentation (tips section):
Symbolic functions are always scalars, therefore, you cannot index into a function.
However it is hard for me to believe that it's not possible to solve these equations matrix - wise. Obviously, one can expand it to 8 scalar equations, but the multi body system concerned here is very simple and the aim is to be able to solve complex ones - hence the question: is it possible to solve matrix DAE in Matlab, and if so - what has to be fixed in order for this to work?
Ps. I have another issue with Matlab DAE solver: input variables (known coefficient functions) for my model are time variant. As far as example is concerned, they are constant in all domain, however for my problem they change in time. This problem has been brought out here. I would be grateful if you referred to it, should you have any solution.
Finally, I managed to find correct syntax for this problem. I made a mistake of treating matrix variables (such as A, Fq) as a single entity. Below I present code that utilizes matrix approach and solves this particular DAE:
% Define symbolic variables.
q = sym('q%d',[3 1]); % state variables
a = sym('a'); k = sym('k'); % constant parameters
t = sym('t','real'); % independent variable
% Define system variables and group them in vectors:
p1(t) = sym('p1(t)'); p2(t) = sym('p2(t)'); p3(t) = sym('p3(t)');
w1(t) = sym('w1(t)'); w2(t) = sym('w2(t)'); w3(t) = sym('w3(t)');
m1(t) = sym('m1(t)'); m2(t) = sym('m2(t)');
pvect = [p1(t); p2(t); p3(t)];
wvect = [w1(t); w2(t); w3(t)];
mvect = [m1(t); m2(t)];
% Define matrices:
mass = diag(sym('ms%d',[1 3]));
Fq = [0 -1 a;
0 0 1];
A = [1 0 0;
0 1 a;
0 a -q(1)*a] * k;
% Define sets of equations and aggregate them into one set:
set1 = diff(pvect,t) == A*wvect + Fq'*mvect;
set2 = mass*diff(wvect,t) == -pvect;
set3 = Fq*wvect == 0;
eqs = [set1; set2; set3];
% Close all system variables in one vector:
vars = [pvect; wvect; mvect];
% Reduce index of the system and remove redundnat equations:
[DAEs,DAEvars] = reduceDAEIndex(eqs,vars);
[DAEs,DAEvars] = reduceRedundancies(DAEs,DAEvars);
[M,F] = massMatrixForm(DAEs,DAEvars);
We receive very simple 2x2 ODE for two variables p1(t) and w1(t). Keep in mind that after reducing redundancies we got rid of all elements from state vector q. This means that all left variables (k and mass(1,1)) are not time dependent. If there had been time dependency of some variables within the system, the case would have been much harder to solve.
% Replace symbolic variables with numeric ones:
M = odeFunction(M, DAEvars,mass(1,1));
F = odeFunction(F, DAEvars, k);
k = 2000; numericMass = 4;
F = #(t, Y) F(t, Y, k);
M = #(t, Y) M(t, Y, numericMass);
% set the solver:
opt = odeset('Mass', M); % Mass matrix of the system
TIME = [1; 0]; % Time boundaries of the simulation (backwards in time)
y0 = [1 0]'; % Initial conditions for left variables p1(t) and w1(t)
% Call the solver
[T, solution] = ode15s(F, TIME, y0, opt);
% Plot results
plot(T,solution(:,1),T,solution(:,2))
I'm writing a function of the Gauss Seidel method of solving a linear system of equations of the form Ax=b, x being the unknown we are looking for.
I am having a problem with the while loop in my function, it seems that it runs infinitely. I can't seem to figure out why.
This is my function for creating the coefficient matrix A and the column vectors x and b, all with the same number of rows of course. No problem with this one.
function [A, b, x0] = test_system(n)
u = ones(n, 1);
A = spdiags([u 4*u u], [-1 0 1], n, n);
b = zeros(n, 1);
b(1) = 3;
b(2 : 2 : end-2) = -2;
b(3 : 2 : end-1) = 2;
b(end) = -3;
x0 = ones(n, 1);
This is my function for solving the system. I have included all of it just in case, but I believe the real problem is within the while loop at the very end which runs infinitely when I execute the function. The counter doesn't break away from it either. I can't really see what its problem is. Any clues?
Be gentle, I'm new at Matlab :)
function [x] = GaussSeidel(A,b,x0,tol)
% implementation of the GaussSeidel iterative method
% for solving a linear system of equations Ax = b
%INPUTS:
% A: coefficient matrix
% b: column vector of constants
% x0: setup for the unknown vector (using vector of ones)
% tol: result must be within 'tol' of correct answer.
%OUTPUTS:
% x: unknown
%check that A is a matrix
if ~(ismatrix(A))
error('A is not a matrix');
end
%check that A is square
[m,n] = size(A);
if m ~= n
error('Matrix A is not square');
end
%check that b is a column vector
if ~(iscolumn(b))
error('b is not a column vector');
end
%check that x0 is a column vector
if ~(iscolumn(x0))
error('x0 is not a column vector');
end
%check that A, b and x0 agree in size
[rowA,colA] = size(A);
[rowb,colb] = size(b);
[rowx0,colx0] = size(x0);
if ~isequal(colA,rowb)||~isequal(rowb,rowx0)
error('matrix dimensions of A, b and xo do not agree');
end
%check that A and b have real entries
if ~isreal(A) || ~isreal(b)
error('matrix A or vector b do not have real entries');
end
%check that the provided tolerance is positive
if tol <= 0
error('tolerance must be positive');
end
%check that A is strictly diagonally dominant
absoluteA = abs(A);
row_sum=sum(absoluteA,2);
diagonal=diag(absoluteA);
if ~all(2*diagonal > row_sum)
warning('matrix A is not strictly diagonally dominant');
end
L = tril(A,-1);
U = triu(A,+1);
D = diag(diag(A));
x = x0;
M1 = inv(D).*L;
M2 = inv(D).*U;
M3 = D\b;
k = 0; %iterations counter
disp(size(M1));
disp(size(M2));
disp(size(M3));
disp(size(x));
while (norm(A*x - b) > tol)
for i=1:n
x(i) = - M1(i,:).*x - M2(i,:).*x + M3(i,:);
end
k=k+1;
if(k >= 10e4)
error('too many iterations carried out');
end
end
end %end function
Coding Discussion
The source of the coding error is the use of element-wise operations instead of matrix-matrix and matrix-vector operations.
These operations produce zero-matrices, so no progress is made.
The M matrices should be defined by
M1 = inv(D)*L; % Note that D\L is more efficient
M2 = inv(D)*U; % Note that D\U is more efficient
M3 = D\b;
and the iterator performing the update should be
x(i) = - M1(i,:)*x - M2(i,:)*x + M3(i,:);
Method Discussion
I also think it is worth mentioning that the code is currently implementing the Jacobi Method since the updater has the form
while a Gauss-Seidel update has the form
.
I don’t have 50 reputation so I can not comment this.
The line if(k >= 10e4), I think this does not make what you think it would. 10e4 is 100,000 and 1e4 is 10,000. This will be the reason why you think your counter does not work. Matlab ist still running because it’s running further than you think it will. Also I run in the same Problem knedlsepp already pointed out.
How can I use matlab to solve the following Ordinary Differential Equations?
x''/y = y''/x = -( x''y + 2x'y' + xy'')
with two known points, such as t=0: x(0)= x0, y(0) = y0; t=1: x(1) = x1, y(1) = y1 ?
It doesn't need to be a complete formula if it is difficult. A numerical solution is ok, which means, given a specific t, I can get the value of x(t) and y(t).
If matlab is hard to do this, mathematica is also OK. But as I am not familiar with mathematica, so I would prefer matlab if possible.
Looking forward to help, thanks!
I asked the same question on stackexchange, but haven't get good answer yet.
https://math.stackexchange.com/questions/812985/matlab-or-mathematica-solve-ordinary-differential-equations
Hope I can get problem solved here!
What I have tried is:
---------MATLAB
syms t
>> [x, y] = dsolve('(D2x)/y = -(y*D2x + 2Dx*Dy + x*D2y)', '(D2y)/x = -(y*D2x + 2Dx*Dy + x*D2y)','t')
Error using sym>convertExpression (line 2246)
Conversion to 'sym' returned the MuPAD error: Error: Unexpected 'identifier'.
[line 1, col 31]
Error in sym>convertChar (line 2157)
s = convertExpression(x);
Error in sym>convertCharWithOption (line 2140)
s = convertChar(x);
Error in sym>tomupad (line 1871)
S = convertCharWithOption(x,a);
Error in sym (line 104)
S.s = tomupad(x,'');
Error in dsolve>mupadDsolve (line 324)
sys = [sys_sym sym(sys_str)];
Error in dsolve (line 186)
sol = mupadDsolve(args, options);
--------MATLAB
Also, I tried to add conditions, such as x(0) = 2, y(0)=8, x(1) = 7, y(1) = 18, and the errors are still similar. So what I think is that this cannot be solve by dsolve function.
So, again, the key problem is, given two known points, such as when t=0: x(0)= x0, y(0) = y0; t=1: x(1) = x1, y(1) = y1 , how I get the value of x(t) and y(t)?
Update:
I tried ode45 functions. First, in order to turn the 2-order equations into 1-order, I set x1 = x, x2=y, x3=x', x4=y'. After some calculation, the equation becomes:
x(1)' = x(3) (1)
x(2)' = x(4) (2)
x(3)' = x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)) (3)
x(4)' = -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2) (4)
So the matlab code I wrote is:
myOdes.m
function xdot = myOdes(t,x)
xdot = [x(3); x(4); x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)); -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)]
end
main.m
t0 = 0;
tf = 1;
x0 = [2 3 5 7]';
[t,x] = ode45('myOdes',[t0,tf],x0);
plot(t,x)
It can work. However, actually this is not right. Because, what I know is that when t=0, the value of x and y, which is x(1) and x(2); and when t=1, the value of x and y. But the ode functions need the initial value: x0, I just wrote the condition x0 = [2 3 5 7]' randomly to help this code work. So how to solve this problem?
UPDATE:
I tried to use the function bvp4c after I realized that it is a boundary value problem and the following is my code (Suppose the two boundry value conditions are: when t=0: x=1, y=3; when t=1, x=6, y=9. x is x(1), y is x(2) ):
1. bc.m
function res = bc(ya,yb)
res = [ ya(1)-1; ya(2)-3; yb(1) - 6; yb(2)-9];
end
2. ode.m
function dydx = ode(t,x)
dydx = [x(3); x(4); x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)); -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)];
end
3. mainBVP.m
solinit = bvpinit(linspace(0,6,10),[1 0 -1 0]);
sol = bvp4c(#ode,#bc,solinit);
t = linspace(0,6);
x = deval(sol,t);
plot(t,x(1,:));
hold on
plot(t,x(2,:));
plot(t,x(3,:));
plot(t,x(4,:));
x(1,:)
x(2,:)
It can work, but I don't know whether it is right. I will check it again to make sure it is the right code.
As mentioned, this isn't a math site, so try to give code or something showing some effort.
However, the first step you need to do is turn the DE into normal form (i.e., no 2nd derivatives). You do this by making a separate variable equal to the derivative. Then, you use
syms x y % or any variable instead of x or y
to define variables as symbolic. Use matlabfunction to create a symbolic function based on these variables. Finally, you can use the ode45 function to solve the symbolic function while passing variable values. I recommend you look up the full documentation in matlab in order to understand it better, but here is a very basic syntax:
MyFun= matlabFunction(eq,'vars',{x,y});
[xout,yout]=ode45(#(x,Y) MyFun(variables),[variable values],Options);
Hopefully this puts you in the right direction, so try messing around with it and provide code if you need more help.
EDIT:
This is how I would solve the problem. Note: I don't really like the matlabFunction creator but this is simply a personal preference for various reasons I won't go into.
% Seperate function of the first order state equations
function dz = firstOrderEqns(t,z)
dz(4,1) = 0;
dz(1) = -2.*z(3).*z(1).*z(4)./(1 + z(4).^2 + z(2).^2);
dz(2) = z(1);
dz(3) = -2.*z(2).*z(3).*z(1)./(1 + z(4).^2 + z(2).^2);
dz(4) = z(3);
end
% runfirstOrderEqns
%% Initial conditions i.e. # t=0
z1 = 5; % dy/dt = 5 (you didn't specify these initial conditions,
% these will depend on the system which you didn't really specify
z2 = 0; % y = 0
z3 = 5; % dx/dt = 5 (The same as for z1)
z4 = 0; % x = 0
IC = [z1, z2, z3, z4];
%% Run simulation
% Time vector: i.e closed interval [0,20]
t = [0,20]; % This is where you have to know about your system
% i.e what is it's time domain.
% Note: when a system has unstable poles at
% certain places the solver can crash you need
% to understand these.
% using default settings (See documentation ode45 for 'options')
[T,Y] = ode45(#firstOrderEqns,t,IC);
%% Plot function
plot(T,Y(:,1),'-',T,Y(:,2),'-.',T,Y(:,3),':',T,Y(:,4),'.');
legend('dy/dt','y','dx/dt','x')
As in my comments I have made a lot of assumtions that you need to fix for example, you didn't specify what the initial conditions for the first derivatives of the states are i.e. (z1, z3) which is important for the response of the system. Also you didn't specify the time interval your interested for the simulation etc.
Note: The second m file can be used with any state function in the correct format
The following is the answer we finally get #Chriso: use matlab bvp4c function to solve this boundary value problem (Suppose the two boundry value conditions are: when t=0: x=1, y=3; when t=1, x=6, y=9. x is x(1), y is x(2) ):
1. bc.m
function res = bc(ya,yb)
res = [ ya(1)-1; ya(2)-3; yb(1) - 6; yb(2)-9];
end
2. ode.m
function dydx = ode(t,x)
dydx = [x(3); x(4); x(2)/x(1)*(-2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)); -2*x(1)*x(3)*x(4)/(1+x(1)^2+x(2)^2)];
end
3. mainBVP.m
solinit = bvpinit(linspace(0,6,10),[1 0 -1 0]);
sol = bvp4c(#ode,#bc,solinit);
t = linspace(0,6);
x = deval(sol,t);
plot(t,x(1,:));
hold on
plot(t,x(2,:));
plot(t,x(3,:));
plot(t,x(4,:));
x(1,:)
x(2,:)