Question

I'm new in Matlab, so sorry for asking a banal and probably already answered question, but I wasn't able to solve it.

I have this ODE to solve

g''(x)+f(x)g'(x)

with g(0)=0 and g'(0)=0.5

f(x) is a known vector, so I tried

xspan = linspace(0,10,100);
y0 = [0,0.5];
%f=f(xspan), known function, for example f=1./xspan;
[x,y] = ode45('odefun',xspan,y0);

and for odefun

function dy=odefun(x,y)

global f  

dy(1) = y(2);
dy(2) = -f.*y(2);

dy    = dy(:);
end

Of course it doesn't work. How can I pass the values of vector f to the solver?

EDIT

Thanks for help, but this is not working for me. Maybe I have an old Matlab version (7.11.0 (R2010B))? I tried to do as you told, but this is what I get in command window

???  In an assignment  A(I) = B, the number of elements in B and
 I must be the same.

Error in ==> odefun at 3
dy(2) = -f.*y(2);

Error in ==> @(x,y)odefun(x,y,f)


Error in ==> odearguments at 109
f0 = feval(ode,t0,y0,args{:});   % ODE15I sets args{1} to yp0.

Error in ==> ode45 at 173
[neq, tspan, ntspan, next, t0, tfinal, tdir, y0, f0, odeArgs, odeFcn, ...

Error in ==> trying at 7
[x,y] = ode45(fun,xspan,y0);

This is the code trying.m

xspan=linspace(0,10,100);
y0=[0 0.5];
f=1./xspan;
[x,y] = ode45(@(x,y)odefun(x,y,f),xspan,y0);

and the odefun

function dy=odefun(x,y,f)
dy(1) = y(2);
dy(2) = -f.*y(2);
dy    = dy(:);
end
Was it helpful?

Solution

It looks like you're using global variables incorrectly (f needs to be declared global in your main function as well), but you shouldn't be using globals to begin with. You should rarely, if ever, use globals. You should also specify your integration function, odefun, as an anonymous function rather than a string in modern Matlab. Here is how you can modify your code to fix these issues:

...
f = ...
[x,y] = ode45(@(x,y)odefun(x,y,f),xspan,y0);

And your integration function, which can be a sub-function or in a separate file, just needs to take an extra argument for the parameter f:

function dy=odefun(x,y,f)
dy(1) = y(2);
dy(2) = -f.*y(2);
dy    = dy(:);

The methods should also be faster than using strings and globals. The code @(x,y)odefun(x,y,f) creates an anonymous function of x and y (ode45 expects a function that takes exactly two inputs) that captures the value of f from the current scope. This is also referred to as a closure in computer science. You can equivalently create a function handle and pass that in:

...
f = ...
fun = @(x,y)odefun(x,y,f)
[x,y] = ode45(fun,xspan,y0);

See also this article on parametrizing functions from The MathWorks for more information on this general technique.

OTHER TIPS

I solved it, it was not so difficult, I just needed to interpolate the f at each value of the independent variable x. In this way the code works

function dy=odefun(x,y,f,xspan)
f=interp1(xspan,f,x);
dy(1) = y(2);
dy(2) = -f.*y(2);
dy    = dy(:);
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top