I am learning OCTAVE, and I am trying to use LSODE ODE solver to integrate a version of FitzHugh–Nagumo model. My attempt looks like this:
time = linspace(0,200,1000);
u0 = rand(32,32);
v0 = rand(32,32);
vec_u0 = reshape(u0,[1,size(u0)(1)*size(u0)(2)]);
vec_v0 = reshape(v0,[1,size(v0)(1)*size(v0)(2)]);
vec_FHN0 = horzcat(vec_u0,vec_v0);
FHN = lsode("FHN_eq_vec", vec_FHN0, time);
FHN(end)
where all of the functions I have defined are in the repository I have set in GitHub - link. I have created a function that transform the two 2D fields of the FHN model into a row vector (as I understand from the examples here the LSODE integrator use row vector as input). I got this error message:
>> fhn_integrate_lsode
warning: non-integer range used as index
warning: called from
FHN_eq_vec at line 3 column 7
fhn_integrate_lsode at line 9 column 5
error: reshape: can't reshape 0x1 array to 1x1 array
error: called from
FHN_eq_vec at line 4 column 3
fhn_integrate_lsode at line 9 column 5
error: lsode: evaluation of user-supplied function failed
error: called from
fhn_integrate_lsode at line 9 column 5
error: lsode: inconsistent sizes for state and derivative vectors
error: called from
fhn_integrate_lsode at line 9 column 5
>>
Someone knows what could be the problem?
This has been answered at http://octave.1599824.n4.nabble.com/Using-Hindmarsh-s-ODE-solver-LSODE-in-OCTAVE-td4674210.html
However, looking quickly at your code, the system that you want to
solve is probably an ordinary differential equation stemming from a
pde space discretization, i.e.,
$dx(t)/dt = f(x,t) := -K x(t) + r(t)$
with K being a square matrix (Laplacian?!) and f a time-dependent
function of matching dimension. I expect that your system is stiff
(due to the negative Laplacian on the right-hand side) and that you
are happy with errors in the order of 10^(-4). Thus you should adapt
the options of lsode:
lsode_options("integration method","stiff");
lsode_options("absolute tolerance",1e-4);
lsode_options("relative tolerance",1e-4);
Then
T = 0:1e-2:1; % time vector
K = sprandsym(32,1)+eye(32); % symmetric stiffness matrix
x0 = rand(32,1); % initial values
r = #(t) rand(32,1)*sin(t); % excitation vector
f = #(x,t) (-K*x+r(t)); % right-hand-side function
x=lsode (f, x0, T); % get solution from lsode
You should exploit any knowledge on the Jacobian df/dx since this will
speed up computations. It's trivial in the case of linear ODE:
f = {#(x,t) -K*x+r(t), #(x,t) -K}; % right-hand-side function.
On the other hand, if the system has an additional mass matrix
$M dx(t)/dt = -K x(t) + r(t)$
things might become more complicated. You probably want to use another
time stepper. Only if M has full rank then you could do
f = #(x,t) ( M\(-K*x+r(t)) ); % right-hand-side function
which is typically not very efficient.
Bye Sebastian
Related
How do I solve the following system of equations on MATLAB when one of the elements of the variable vector is a constant? Please do give the code if possible.
More generally, if the solution is to use symbolic math, how will I go about generating large number of variables, say 12 (rather than just two) even before solving them?
For example, create a number of symbolic variables using syms, and then make the system of equations like below.
syms a1 a2
A = [matrix]
x = [1;a1;a2];
y = [1;0;0];
eqs = A*x == y
sol = solve(eqs,[a1, a2])
sol.a1
sol.a2
In case you have a system with many variables, you could define all the symbols using syms, and solve it like above.
You could also perform a parameter optimization with fminsearch. First you have to define a cost function, in a separate function file, in this example called cost_fcn.m.
function J = cost_fcn(p)
% make sure p is a vector
p = reshape(p, [length(p) 1]);
% system of equations, can be linear or nonlinear
A = magic(12); % your system, I took some arbitrary matrix
sol = A*p;
% the goal of the system of equations to reach, can be zero, or some other
% vector
goal = zeros(12,1);
% calculate the error
error = goal - sol;
% Use a cost criterion, e.g. sum of squares
J = sum(error.^2);
end
This cost function will contain your system of equations, and goal solution. This can be any kind of system. The vector p will contain the parameters that are being estimated, which will be optimized, starting from some initial guess. To do the optimization, you will have to create a script:
% initial guess, can be zeros, or some other starting point
p0 = zeros(12,1);
% do the parameter optimization
p = fminsearch(#cost_fcn, p0);
In this case p0 is the initial guess, which you provide to fminsearch. Then the values of this initial guess will be incremented, until a minimum to the cost function is found. When the parameter optimization is finished, p will contain the parameters that will result in the lowest error for your system of equations. It is however possible that this is a local minimum, if there is no exact solution to the problem.
Your system is over-constrained, meaning you have more equations than unknown, so you can't solve it. What you can do is find a least square solution, using mldivide. First re-arrange your equations so that you have all the constant terms on the right side of the equal sign, then use mldivide:
>> A = [0.0297 -1.7796; 2.2749 0.0297; 0.0297 2.2749]
A =
0.029700 -1.779600
2.274900 0.029700
0.029700 2.274900
>> b = [1-2.2749; -0.0297; 1.7796]
b =
-1.274900
-0.029700
1.779600
>> A\b
ans =
-0.022191
0.757299
I intend to compute the determinant of a transfer matrix and then subject to a nyquist analysis by making the nyquist plot but the problem is that the determinant command doesn't recognizes the transfer matrix. The code is shown below
clc
clear all;
close all;
g11 = tf(12.8,[16.7 1],'InputDelay',1)
g12 = tf(-18.9,[21 1],'InputDelay',3)
g21 = tf(6.6,[10.9 1],'InputDelay',7)
g22 = tf(-19.4,[14.4 1],'InputDelay',3)
G=[g11 g12 ; g21 g22]
[re,im,w] = nyquist(G)
F=2.55;
s=tf('s');
%syms s;
ggc11 = g11*(0.96*(1+3.25*F*s)/(3.25*F^2*s))
ggc12 = g12*(0.534*(1+3.31*F*s)/(3.31*F^2*s))
ggc21 = g21*(0.96*(1+3.25*F*s)/(3.25*F^2*s))
ggc22 = g22*(0.534*(1+3.31*F*s)/(3.31*F^2*s))
GGc=[ggc11 ggc12 ; ggc21 ggc22];
L=eye(2)+ GGc;
W= -1 + det(L)
nyquist(W)
The error that appears is as follows
Undefined function 'det' for input arguments of type 'ss'.
Error in BLT_code (line 30)
W= -1 + det(L)
I would like to avoid the 'syms' command as I would not be able to do the nyquist plot then. Is there any alternative way of computing the nyquist plot of the same ?
I am stuck in the same boat, trying to calculate the determinant of transfer function matrices for the purpose of checking the MIMO Nyquist stability criteria, see MIMO Stability ETH Zurich Lecture slides (pg 10). Unfortunately there does not seem to be a simple MATLAB command for this. I figured it can be evaluated manually.
If you have a TF matrix G(s) of the following form:
G = [g_11 g_12; g_21 g_22];
you can obtain the determinant by evaluating it as per its original definition as
det_G = g_11*g_22 - g_12*g_21;
This will result in a 1x1 TF variable. Of course, this method gets much too complicated for anything above a 2x2 system.
Doing homework and there's a question that's giving me trouble. The questions is:
a)create a function M-file called nmoles that requires two vector inputs—
the mass and molecular weight—and returns the corresponding number
of moles. Because you are providing vector input, it will be necessary
to use the meshgrid function in your calculations.
b) Test your function for the compounds shown in the following table, for
masses from 1 to 10 g:
In my function file, i've got:
function [ n ] = nmoles(m, MW)
%% Finds number of moles
m = (1:10); %% mass range
MW = [78.115 46.07 102.3]; %% Values from the table
n=m/MW; %%formula provided by the textbook
My main file only has:
nmoles(m,MW)
I'm getting an error: "Error using / Matrix dimensions must agree"
Also: Error in nmoles (line 10) n=m/MW;
I'm inexperienced with MATLAB and still learning syntax but I assume that my formula is incorrect and i'm using the wrong symbol to divide, though i'm not sure how to correct this. Also, how would i incorporate the meshgrid function into my anwser?
Here is how your function should probably look like:
function [ n ] = nmoles(m, MW)
% Finds number of moles
[mv,MWv] = meshgrid(m, MW); % extends m and MW to match all combinations.
n = mv./MWv; %formula provided by the textbook
end
And then your main script should be:
m = 1:10; % mass range
MW = [78.115 46.07 102.3]; % Values from the table
nmoles(m, MW)
You had 3 mistakes:
If you get m and MW as input to the function, your not suppose to define them within it.
Because you want the number of moles for each combination of mass and molar weight, you use meshgrid.
When you want to perform an elementwise division or multiplication on 2 arrays, put a . before the / or *. In MATLAB everything is a matrix by default, and so this operations are interpreted as matrix multiplication and division by default. If you want to do a regular division or multiplication you use .* and ./. This is true also for power (^ and .^).
I have equation F(f)=a*f^3+b*f+c. I have known vectors of the data, p, independent variable, 'f'. I need to find values of a, b, c.
What I tried:
function [ val ] = myfunc(par_fit,f,p)
% This gives me a,b,c
% p= af^3 +bf +c
val = norm(p - (par_fit(1)*(f.^3))+ (par_fit(2)*f) + (par_fit(3)));
end
my_par = fminsearch(#(par_fit) myfunc(par_fit,f,p),rand(1,3));
This gives me my_par = [1.9808 -2.2170 -24.8039], or a=1.9808, b=-2.2170, and c=-24.8039, but I require that b should be larger than 5, and c should be larger than zero.
I think your problem might be because your objective function is incorrect:
val = norm(p - (par_fit(1)*(f.^3))+ (par_fit(2)*f) + (par_fit(3)));
should probably be:
val = norm(p-(par_fit(1)*f.^3+par_fit(2)*f+par_fit(3)));
But you can constrain the values of variables when you do minimisation by using fmincon rather than fminsearch. By setting the lb input to [-Inf -Inf 0], the first two coefficients are allowed to be any real number, but the third coefficient must be greater than or equal to zero. For example: (I've also shown how to solve the problem (without the non-negativity constraint) using a matrix method)
% Sample data
f=(0:.1:1).';
p=2*f.^3+3*f+1+randn(size(f))
% Create Van der Monde matrix
M=[f.^3 f f.^0];
C=M\p; % Solve the matrix problem in a least squares sense if size(f)>size(F)
my_par=fmincon(#(c) norm(p-(c(1)*f.^3+c(2)*f+c(3))),rand(1,3),[],[],[],[],[-Inf 5 0],[])
C.'
plot(f,p,'o',f,M*C,f,my_par(1)*f.^3+my_par(2)*f+my_par(3))
I have the following ODE:
x_dot = 3*x.^0.5-2*x.^1.5 % (Equation 1)
I am using ode45 to solve it. My solution is given as a vector of dim(k x 1) (usually k = 41, which is given by the tspan).
On the other hand, I have made a model that approximates the model from (1), but in order to compare how accurate this second model is, I want to solve it (solve the second ODE) by means of ode45. My problem is that this second ode is given discrete:
x_dot = f(x) % (Equation 2)
f is discrete and not a continuous function like in (1). The values I have for f are:
0.5644
0.6473
0.7258
0.7999
0.8697
0.9353
0.9967
1.0540
1.1072
1.1564
1.2016
1.2429
1.2803
1.3138
1.3435
1.3695
1.3917
1.4102
1.4250
1.4362
1.4438
1.4477
1.4482
1.4450
1.4384
1.4283
1.4147
1.3977
1.3773
1.3535
1.3263
1.2957
1.2618
1.2246
1.1841
1.1403
1.0932
1.0429
0.9893
0.9325
0.8725
What I want now is to solve this second ode using ode45. Hopefully I will get a solution very similar that the one from (1). How can I solve a discrete ode applying ode45? Is it possible to use ode45? Otherwise I can use Runge-Kutta but I want to be fair comparing the two methods, which means that I have to solve them by the same way.
You can use interp1 to create an interpolated lookup table function:
fx = [0.5644 0.6473 0.7258 0.7999 0.8697 0.9353 0.9967 1.0540 1.1072 1.1564 ...
1.2016 1.2429 1.2803 1.3138 1.3435 1.3695 1.3917 1.4102 1.4250 1.4362 ...
1.4438 1.4477 1.4482 1.4450 1.4384 1.4283 1.4147 1.3977 1.3773 1.3535 ...
1.3263 1.2957 1.2618 1.2246 1.1841 1.1403 1.0932 1.0429 0.9893 0.9325 0.8725];
x = 0:0.25:10
f = #(xq)interp1(x,fx,xq);
Then you should be able to use ode45 as normal:
tspan = [0 1];
x0 = 2;
xout = ode45(#(t,x)f(x),tspan,x0);
Note that you did not specify what values of of x your function (fx here) is evaluated over so I chose zero to ten. You'll also not want to use the copy-and-pasted values from the command window of course because they only have four decimal places of accuracy. Also, note that because ode45 required the inputs t and then x, I created a separate anonymous function using f, but f can created with an unused t input if desired.