gpt4 book ai didi

c++ - Runge Kutta 圆周运动法

转载 作者:太空宇宙 更新时间:2023-11-04 13:21:55 27 4
gpt4 key购买 nike

有人要求我解这个微分方程:

(x,y,vx,vy)'=(vx,vy,vy,-vx)

它应该返回周期为 2*pi 的圆周运动。我实现了功能:

class FunzioneBase 
{
public:
virtual VettoreLineare Eval(double t, const VettoreLineare& v) const = 0;
};

class Circonferenza: public FunzioneBase
{
private:
double _alpha;

public:
Circonferenza(double alpha) { _alpha = alpha; };
void SetAlpha(double alpha) { _alpha = alpha; };
virtual VettoreLineare Eval(double t, const VettoreLineare& v) const;
};

VettoreLineare Circonferenza::Eval(double t, const VettoreLineare& v) const
{
VettoreLineare y(4);
if (v.GetN() != 4)
{
std::cout << "errore" << std::endl;
return 0;
};

y.SetComponent(0, v.GetComponent(2));
y.SetComponent(1, v.GetComponent(3));
y.SetComponent(2, pow(pow(v.GetComponent(0), 2.) + pow(v.GetComponent(1), 2.), _alpha) * v.GetComponent(3));
y.SetComponent(3, - pow(pow(v.GetComponent(0), 2.) + pow(v.GetComponent(1), 2.), _alpha)) * v.GetComponent(2));

return y;
};

其中 _alpha 等于 0。现在,这适用于欧拉方法:如果我对 2 * pi * 10 积分这个 ODE,给定初始条件 (1, 0, 0, -1) ,以 0.003 精度,我得到该位置与 (1, 0)1 ± 0.1 范围内相当,因为我们应该期待。但是,如果我将相同的 ODE 与 Runge Kutta 的方法(具有 0.003 精度,2 * pi * 10 秒)集成,实现如下:

class EqDifferenzialeBase 
{
public:
virtual VettoreLineare Passo (double t, VettoreLineare& x, double h, FunzioneBase* f) const = 0;
};

class Runge_Kutta: public EqDifferenzialeBase
{
public:
virtual VettoreLineare Passo(double t, VettoreLineare& v, double h, FunzioneBase* f) const;
};

VettoreLineare Runge_Kutta::Passo(double t, VettoreLineare& v, double h, FunzioneBase* _f) const
{
VettoreLineare k1 = _f->Eval(t, v);
VettoreLineare k2 = _f->Eval(t + h / 2., v + k1 *(h / 2.));
VettoreLineare k3 = _f->Eval(t + h / 2., v + k2 * (h / 2.));
VettoreLineare k4 = _f->Eval(t + h, v + k3 * h);
VettoreLineare y = v + (k1 + k2 * 2. + k3 * 2. + k4) * (h / 6.);

return y;
}

程序返回一个 x 位置,大约等于 0.39,对于四阶 Runge Kutta 方法,理论上精度应该在 1E- 附近6。我检查了一下,发现使用 Runge_Kutta 的周期似乎几乎翻了四倍(因为在 2 * pi 失效中,x10.48),但我不明白为什么。这是我主要的内容:

VettoreLineare DatiIniziali (4);
Circonferenza* myCirc = new Circonferenza(0);

DatiIniziali.SetComponent(0, 1.);
DatiIniziali.SetComponent(1, 0.);
DatiIniziali.SetComponent(2, 0.);
DatiIniziali.SetComponent(3, -1.);
double passo = 0.003;
Runge_Kutta myKutta;

for(int i = 0; i <= 2. * M_PI / passo; i++)
{
DatiIniziali = myKutta.Passo(0, DatiIniziali, passo, myCirc);
cout << DatiIniziali.GetComponent(0) << endl;
};

cout << 1 - DatiIniziali.GetComponent(0) << endl;

提前谢谢你。

最佳答案

更新:发现一个错误:始终使用 -Wall 选项进行编译,以捕获编译器的所有警告和自动代码更正。那么你会发现

fff: In member function ‘virtual VettoreLineare Circonferenza::Eval(double, const VettoreLineare&) const’:
fff:xxx:114: error: invalid operands of types ‘void’ and ‘double’ to binary ‘operator*’
y.SetComponent(3, - pow(pow(v.GetComponent(0), 2.) + pow(v.GetComponent(1), 2.), _alpha)) * v.GetComponent(2));
^

您在 _alpha 之后过早关闭,因此 SetComponentvoid 成为一个因素。


更新 II: 识别出的第二个错误:在 another post of yours 中给出了线性 vector 类的代码。在那里,与加法 (operator+) 相比,标量 vector 积 (operator*(double) ) 正在修改调用实例。因此,在计算 k2 时,k1 的分量将乘以 h/2。但是随后这个修改后的 k1(以及修改后的 k2k3)被用于组装结果 y 导致一些几乎完全无用的状态更新。


原始快速原型(prototype)制作:我可以告诉你,在 python 中精简的基本实现可以完美运行

import numpy as np

def odeint(f,t0,y0,tf,h):
'''Classical RK4 with fixed step size, modify h to fit
the full interval'''
N = np.ceil( (tf-t0)/h )
h = (tf-t0)/N

t = t0
y = np.array(y0)
for k in range(int(N)):
k1 = h*np.array(f(t ,y ))
k2 = h*np.array(f(t+0.5*h,y+0.5*k1))
k3 = h*np.array(f(t+0.5*h,y+0.5*k2))
k4 = h*np.array(f(t+ h,y+ k3))
y = y + (k1+2*(k2+k3)+k4)/6
t = t + h
return t, y

def odefunc(t,y):
x,y,vx,vy = y
return [ vx,vx,vy,-vx ]

pi = 4*np.arctan(1);

print odeint(odefunc, 0, [1,0,0,-1], 2*pi, 0.003)

结束于

(t, [ x,y,vx,vy]) = (6.2831853071794184,
[ 1.00000000e+00, -6.76088739e-15, 4.23436503e-12,
-1.00000000e+00])

如预期。您将需要一个调试器或中间输出来找出计算出错的地方。

关于c++ - Runge Kutta 圆周运动法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34965829/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com