Passing extra output arguments from ode
이 질문을 팔로우합니다.
- 팔로우하는 게시물 피드에서 업데이트를 확인할 수 있습니다.
- 정보 수신 기본 설정에 따라 이메일을 받을 수 있습니다.
오류 발생
페이지가 변경되었기 때문에 동작을 완료할 수 없습니다. 업데이트된 상태를 보려면 페이지를 다시 불러오십시오.
이전 댓글 표시
0 개 추천
I've the following code to obtain [t,x] after simulating odes . In addition to the solution, I also want to obtain the functiion values F(x,t) in the below equation.
% obtains the dynamics from a system of odes
x0 = initial values;
tspan = 0:0.0001:0.5;
options = odeset('abstol', 1e-10, 'reltol', 1e-9);
% generate solution
[t, x] = ode15s(@(t,x) fun(t,x), tspan , x0 ,options);
% obtain function values ,f, from ode
[dy f] = fun([ ], [ ])
function [dy f] = fun(t,x)
persistent f
f = []
A = % Matrix
dy = A*x
if nargout >1
f = horzcat(f, A*x)
end
end
In the code, I've defined a persistent variable, f, that stores F for each time step that I solver takes. And I receive f using `[dy f] = fun([ ], [ ])``
But the size of f and x are not equl because from what I understand the output of x is given (after interpolation I guess) only at the time points defined in tspan. Whereas, f is saved for very time instant t that the solver takes internally.
In summary my question is, how do I obtain f for the same time instants at which x is obtained.
채택된 답변
"In summary my question is, how do I obtain f for the same time instants at which x is obtained."
Using a persistent variable or OutputFcn is a red-herring. The simple solution is to call the function after calling the ODE solver, using exactly the values that the ODE solver returns. Here is a complete working example simply based on the first example from the ode15s documentation:
tspan = [0,2];
x0 = 1;
fun = @(t,x) -10*t;
[t,x] = ode15s(fun, tspan, x0)
Then you just need this:
dy = arrayfun(fun,t,x)
댓글 수: 15
Thanks a lot for the response. Could you please explain how to use arrayfun when x is a vector (i.e when x = [x1 x2 x3..] like the e.g. provided in my original post)?
Either use a loop or cellfun, e.g. using the second example from the ode15s documentation:
>> [t,y] = ode15s(@vdp1000,[0 3000],[2 0]);
>> dydt = cellfun(@vdp1000,num2cell(t),num2cell(y,2),'UniformOutput',false);
>> dydt = [dydt{:}].' % optional
dydt =
0 -2
-2.817e-05 -1.9155
-5.5179e-05 -1.8345
-8.105e-05 -1.7569
-0.0001866 -1.4402
-0.00027362 -1.1791
-0.00034496 -0.96512
-0.00040334 -0.78997
... lots of lines here
0.00068031 1.7023e-05
0.00068638 2.6636e-05
0.00072007 1.1815e-05
0.00075974 0.00012112
0.00080746 0.00037099
0.00086676 0.00031263
0.00095752 0.00041708
0.001089 0.00047778
0.0011951 0.00022839
No persistent variables, no changing the function code, no complicated interpolation, no mismatched sample times, no messing around with OutputFcn... just two lines of simple code.
Deepa Maheshvare
2020년 3월 26일
편집: Deepa Maheshvare
2020년 3월 26일
For instance , if my y has size 500*10
num2cell(y,2) returns
500×1 cell array
{1×10 double}
{1×10 double}
:
:
{1×10 double}
Now the problem is , I want to pass y to function fun as 10 x 1 double for matrix multiplication to be consistent.
"Now the problem is , I want to pass y to function fun as 10 x 1 double for matrix multiplication to be consistent."
You could:
- make a small change to fun so that it reshapes the input into a column vector.
- call fun from an anonymous function, which reshapes the input into a column vector.
- use a loop or cellfun to reshape the cell contents, before calling fun via cellfun.
If you showed your code and gave some sample data then I could test these for you too.
I could implement your first suggestion.
Here I am presenting a complete code
clc;
clear all;
global ngrid
ngrid = 10;
phi0 = 300*ones(ngrid,1);
tspan = 0:0.01:0.5;
options = odeset('abstol', 1e-10, 'reltol', 1e-9);
D = 9*ones(ngrid-1,1);
%% generate exact solution
[t, y] = ode15s(@(t,phi) fun(t,phi,D), tspan , phi0 ,options);
dydt = cellfun(@fun,num2cell(t),num2cell(y,2),num2cell(D),'UniformOutput',false);
dydt = [dydt{:}].' % optional
function dphi = fun(t,phi,D)
phi
[m,n] = size(phi);
if n ~= 1
phi = transpose(phi); % reshapes row vector to a column vector
end
MT = [-1 0 0 0 0 0 0 0 0;...
1 -1 0 0 0 0 0 0 0;...
0 1 -1 0 0 0 0 0 0;...
0 0 1 -1 0 0 0 0 0;...
0 0 0 1 -1 0 0 0 0;...
0 0 0 0 1 -1 0 0 0;...
0 0 0 0 0 1 -1 0 0;...
0 0 0 0 0 0 1 -1 0;...
0 0 0 0 0 0 0 1 -1;...
0 0 0 0 0 0 0 0 1];
M = transpose(MT);
A = MT*diag(D)*M
dphi = A*phi;
end
I have a new addition here,
% generate solution
[t, x] = ode15s(@(t,x) fun(t,x), D tspan , x0 ,options);
In addition to x and t , fun takes an additional argument D as an input.
In such a case, I am not sure how to use cellfun
I understand
dydt = cellfun(@fun,num2cell(t),num2cell(y,2),num2cell(D),'UniformOutput',false);
will not work
But I am not sure how to pass D in cellfun.. Should I convert D as a 51 x 9 matrix, convert to cell array and then pass? Is there an alternate way?
Please note:
I can't define D inside fun, D comes from an upstream function.
For cellfun use exactly the same anonymous function like you did with ode15s:
@(t,phi) fun(t,phi,D)
Yes, I tried the same way. The problem is, D is not a function of time. So the size of D is not equal to size of t or size(x,1). I have to pass D for every t, time step that the cellfun calls the anonymous function fun
Stephen23
2020년 3월 27일
"The problem is, D is not a function of time.
Sure, that is clear.
So the size of D is not equal to size of t or size(x,1). I have to pass D for every t, time step that the cellfun calls the anonymous function fun"
That is exactly what the anonymous function does.
When fun is parameterized exactly as you did for ode15s then array D is passed complete as an input to fun every time ode15s calls the anonymous function, or every time cellfun calls the anonymous function. The code I showed you does NOT require/assume that D has the same number of elements as t.
You seem a bit confused about parameterizing the function. I recommend that you reassure yourself by using the anonymous functions exactly as I wrote and printing D to the command window (from inside fun) and you will see that in fact both ode15 and cellfun get the complete D array (and so its size is completely unrelated to t or anything else, D can be literally any size or class that you want).
"When fun is parameterized exactly as you did for ode15s then array D is passed complete as an input to fun every time ode15s calls the anonymous function, or every time cellfun calls the anonymous function"
Yes, I tried this
[t, y] = ode15s(@(t,phi) fun(t,phi,D), tspan , phi0 ,options);
dydt = cellfun(@fun,num2cell(t),num2cell(y,2),D,'UniformOutput',false);
Error:
Error in ----
f = cellfun(@predicted,num2cell(t),num2cell(phi_tilde,2),Dhat,'UniformOutput',false);
Error using cellfun
Input #4 expected to be a cell array, was double instead.
What you did:
cellfun(@fun, ...
cellfun(@(t,phi) fun(t,phi,D), ...
Just like I wrote, you need to use exactly the same anonymous function as you did with ode15s. For whatever reason you continue to call fun directly, even though I told you to use that anonymous function.
You could even just define it once (which is what I would do):
D = [...];
afun = @(t,phi) fun(t,phi,D); % define the anonymous function once!
[t,y] = ode15s(afun, ...);
dydt = cellfun(afun, ...);
Thank you
I tried the second suggestion
afun = @(t,phi) fun(t,phi,D); % define the anonymous function once!
[t,y] = ode15s(afun, ...);
dydt = cellfun(afun, ...);
Code:
clc;
clear all;
global ngrid
ngrid = 10;
phi0 = 300*ones(ngrid,1);
tspan = 0:0.01:0.5;
options = odeset('abstol', 1e-10, 'reltol', 1e-9);
D = 9*ones(ngrid-1,1);
%% generate exact solution
% [t, y] = ode15s(@(t,phi) fun(t,phi,D), tspan , phi0 ,options);
% f = cellfun(@(t,phi) fun(t,phi,D),'UniformOutput',false)
afun = @(t,phi) fun(t,phi,D); % define the anonymous function once!
[t,y] = ode15s(afun,tspan , phi0 ,options);
f = cellfun(afun,'UniformOutput',false);
f = [f{:}].' % optional
function dphi = fun(t,phi,D)
phi
[m,n] = size(phi);
if n ~= 1
phi = transpose(phi);
end
MT = [-1 0 0 0 0 0 0 0 0;...
1 -1 0 0 0 0 0 0 0;...
0 1 -1 0 0 0 0 0 0;...
0 0 1 -1 0 0 0 0 0;...
0 0 0 1 -1 0 0 0 0;...
0 0 0 0 1 -1 0 0 0;...
0 0 0 0 0 1 -1 0 0;...
0 0 0 0 0 0 1 -1 0;...
0 0 0 0 0 0 0 1 -1;...
0 0 0 0 0 0 0 0 1];
M = transpose(MT);
A = MT*diag(D)*M
dphi = A*phi;
end
Error:
Error using cellfun
Input #2 expected to be a cell array, was char instead.
Error in simulate (line 18)
f = cellfun(afun,'UniformOutput',false);
For some reason you decided to call cellfun without any data input arguments. In your previous comments you showed that you called cellfun correctly with fun and two cell array input arguments (corresponding to t and y). Now you need to do the same with afun: you still need to provide input arguments to cellfun otherwise it cannot provide the data (i.e. t and y) when it calls the anonymous function.
What you did:
dydt = cellfun(afun,'UniformOutput',false); % where are t and y ?
What you need to do:
dydt = cellfun(afun,num2cell(t),num2cell(y,2),'UniformOutput',false);
Earlier I told you to use the anonymous function. I did NOT tell you to remove all of the other inputs!
Thank you. After correcting the stupid mistake from my side,
line 18 is now:
f = cellfun(afun,num2cell(t),num2cell(y,2),num2cell(D),'UniformOutput',false);
Error:
Error using cellfun
All of the input arguments must be of the same size and shape.
Previous inputs had size 51 in dimension 1. Input #4 has size 9
Error in simulate (line 18)
f = cellfun(afun,num2cell(t),num2cell(y,2),num2cell(D),'UniformOutput',false);
D is not an input to cellfun or ode15s.
The array D is passed to fun solely via the anonymous function definition, which access D directly from the workspace where the anonymous function is defined. You do NOT need pass D as an input to cellfun.
What you did:
f = cellfun(afun,num2cell(t),num2cell(y,2),num2cell(D),'UniformOutput',false);
% ^^^^^^^^^^^^ does not belong here
What you need to do:
dydt = cellfun(afun,num2cell(t),num2cell(y,2),'UniformOutput',false);
% ^^^^ D is already in this function definition!!!!!!!
I suggest that you read the link I gave you earlier on how to parameterize functions. Then you would get it working in 20 seconds. Making code changes randomly, without understanding how the anonymous function is used, is not an efficient use of your time:
추가 답변 (1개)
Ameer Hamza
2020년 3월 25일
You need to use OutputFcn to get the value of a variable at the same time instant as the value in the output vector: https://www.mathworks.com/help/matlab/ref/odeset.html#d120e857290. Following code shows an example
clear global
global x_vector;
opts = odeset('OutputFcn', @outfcn);
[t,x] = ode45(@(t,x) [x(2); -x(1)], [0, 2*pi], [0; 1], opts);
plot(t, x_vector)
function s = outfcn(t,x,f)
if strcmp(f, 'done')
return
end
global x_vector;
x_vector = [x_vector x(1, :).^2];
s = 0;
end
Note that in this code, I used the global variable to get value out of outfcn, to show a general idea. In practice, global variables are not recommended. I suggest you look at John D'Errico's answer here: https://www.mathworks.com/matlabcentral/answers/510713-is-it-possible-to-store-the-intermediate-values-of-fmincon to see a more efficient way to get value out of the outfcn.
카테고리
도움말 센터 및 File Exchange에서 Mathematics에 대해 자세히 알아보기
태그
참고 항목
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!웹사이트 선택
번역된 콘텐츠를 보고 지역별 이벤트와 혜택을 살펴보려면 웹사이트를 선택하십시오. 현재 계신 지역에 따라 다음 웹사이트를 권장합니다:
또한 다음 목록에서 웹사이트를 선택하실 수도 있습니다.
사이트 성능 최적화 방법
최고의 사이트 성능을 위해 중국 사이트(중국어 또는 영어)를 선택하십시오. 현재 계신 지역에서는 다른 국가의 MathWorks 사이트 방문이 최적화되지 않았습니다.
미주
- América Latina (Español)
- Canada (English)
- United States (English)
유럽
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
