最近在用ode45解微分方程数值解,试图复现论文中的图。一般来说说微分方程(组)只要按照响应的条件去撰写好对应的回调函数即可,基本没什么难度,但对于本文遇到的的这个问题,可能还需要一些技巧去实现解法,这篇文章就来说说我们其中遇到的几个问题。
一、问题提出和简单分析:
方程的条件和初值如下:
常系数和初始变量:
模型参数:Ms=1.6×10^6;a=1000;alpha=0.001;,mu0=4πx10^7 ;c=0.1;gamma1=7×10^-18;gamma1_p=-1×10^-25 ;gamma2 =-3.3×10^-30 ;gamma2_p=2.1×10^-38 ;E=2.02×10^11 ;ksi=2000 ;H=40 ;
自变量σ区间为[0,300]MPa 注意:1MPa=1×106 Pa ,代入公式计算的时候注意这一点,上面的模型参数都是在Pa的基础上赋值的。
M初始值分别为: M(0)=0 ;M(0)=10000 ;M(0)=20000;M(0)=30000;M(0)=40000;
简单的分析,这应该是一个二元一阶常系数微分方程组,只有dM和dMan需要关注,其他变量,Heff,Hsigma都是与Man有关,Man是比较关键的变量,但是Man和dMan的表达都没有直接形式,这个需要注意。Hsigma是搭桥,基本联通Heff和Hman,Heff和Man相互纠缠。
二、解决初值问题
我们在带入ode45的表达式中,初值是一个必要的参数。
题目中给了M的初始值,但是Man没有给出,这个得想办法求出来。通过观察应该是由原方程组的前三个式子组成的方程来求解。
也即解决由这三个式子在sigma=0的条件下,Man的值
第三个式子由于sigma为零,Hsigma=0,另外Man 和Heff 这俩显然是个超越方程,估计没有解析解,我们求数值解。
我们使用fsolve解数值解,因为不知道初值,随便定了Man和Heff为1,Hsigma为0
% Man ,Heff,Hsigma 初值,sigma=0 下
[x,fval,exitflag]=fsolve(@myfun,[1 1 0]);
myfun中关键代码如下:
eq1 = Man -( Ms*(coth(Heff/a)-a/Heff));
eq2 = Heff- (H+Hsigma+alpha*Man);
eq3 = Hsigma - (3*sigma/mu0*((gamma1 + gamma1_p*sigma)*Man + 2*(gamma2 + gamma2_p*sigma)*Man*Man*Man));
F = [eq1;eq2;eq3];
结果是找不到,这说明初值没有选定,找了几个初值都不行,看来要具体分析一下Man和Heff的关系了,这边使用画图法,实际曲线来看看两者到底交叠在哪个点上,根据eq1和eq2,我们稍微变动一下,画出 Man和Heff的走势曲线
Ms = 1.6e6;
a = 1000;
H = 40;
alpha = 0.001;
Heff = [1:500];
for i = 1:length(Heff)
Man1(i) =( Ms*(coth(Heff(i)/a)-a/Heff(i)));
Man2(i) = (Heff(i)- H)/alpha;
end
plot(Heff,Man1,'r');
hold on
plot(Heff,Man2,'b');
大概交叉在Heff = 86,Man=46000,左右,【这种初值靠你随便指定手写,估计是不可能的】,好了初值问题选定,现在终于可以迈入第下一步了!, 这一步算出来的 Man的初值 是 45666.419496657
二、dMan的确定
[x,y] = ode45(@(x,y)f(x,y,st),[t(1),t(end)],y0,nstep);
其中y是[M0,Man0], 在回调函数内部,大致的结构如下
function dydt = f(x,y,st)
sigma = x;
dydt = zeros(size(y));
%y(1), y(2)
%M, Man
Man = y(2);
%想办法求出来 dMan_dt
dydt(2)= dMan_dt;
dydt(1) = sigma /(E*ksi) * (y(2) - y(1)) + c* dydt(2);
end
这里面的步骤很有讲究,你要先取出 积分自变量x也就是t,也是sigma,另外y的值y(1) = M,y(2)=Man, 但是M的值基本用不上,sigma、Man的值要用在 求dMan_dt上,算出来的dydt(2) 又要被dydt(1)用,所以写在最后面。
dMan不知道,是不是可以对前面三个式子都对sigma求导,解一个 [Man,Heff,dHsigma,dMan,dHeff,dHsigma,sigma] 这么一个五元的方程组(Man和sigma能知道),还得是数值解。这个最麻烦的就是初值,Heff的初值还好办,那些微分式子的初值很难估计。
求dMan_dsigma 非常关键。上述办法估计行不动,需要变通一下思维。经过前面的分析,Heff和Man相互嵌套,可以利用这点,
,
dMan_dHeff, 它出来的结果基本都是Man的函数,另外Heff的微分也都是sigma和Man,这就好办了, 也就是找到了下面的这个函数关系,最重要的是Man和sigma都是已知!
只是链式微分式子比较可怕
没有关系,我们交给Matlab吧
Hsigma = (3*sigma/mu0*((gamma1 + gamma1_p*sigma)*Man + 2*(gamma2 + gamma2_p*sigma)*Man*Man*Man));
Heff = H + Hsigma + alpha *Man;
pp = (gamma1 + 2*gamma1_p*sigma)*Man + 2*(gamma2 + 2*gamma2_p*sigma)*Man*Man*Man;
dMan_dt = 3*Ms/(mu0*a)*( -(csch(Heff/a))^2 + (a/Heff)^2) *pp;
至此已经解决掉这些问题了,我们最后看看图像如何;
三、心心念念的图
和论文的附图是可以对上的
另外观察到的Man的图,它的值是不随M的初值而改变的,显然,首先Man的初值固定的(在积分从0开始时候),另外dMan的过程和M0的初值也没毛线关系,一个变量就是这两个因素决定,积分初值和积分步长。M对Man相当于应变随自变量。
总结
常规的ode方程按基本调用就可以了,这篇文章的意思还是在于解决实际的ode方程,灵活应用各种方法,解决各种遇到的难题。
1、使用fsolve解决初值问题。初始值没有给全,那么需要建立方程求解。非线性或者超越方程也没有解析解,还得想办法用fsolve求数值解。数值解又特别依赖初始值,初始值选取根据建立曲线找到大致区间,再通过求解得到相对精确的解。
2、灵活应用链式法则。有些导数规则不存在,使用链式法则构造需要的导数方程。
3、根据需要排列ode回调函数的返回值,存在相互依赖关系的先解决,然后按照先后书写顺序排列返回值。
文章转载遵循CC 4.0 BY-SA版权协议,来源于互联网: 用ode45解微分方程遇到的实际问题 | https://blog.csdn.net/book_bbyuan/article/details/128608257