我正在开发一种使用Runge Kutta方法计算新数据点的算法。以下是实施此方法的参考 - http://calculuslab.deltacollege.edu/ODE/7-C-3/7-C-3-h.html。这是我的代码:
#include<iostream>
#include<math.h>
class Runge_Kutta
{
public:
float x[100];
float y[200];
float h; // step size
float K_1,K_2,K_3,K_4;
float compute(); // function to compute data point
float data(); //function to generate data signal
Runge_Kutta();
~Runge_Kutaa();
}
Runge_Kutta::Runge_Kutta()
{
x[100] = 0; // input signal
y[200] = 0; // output accumulator
h = 0.2;
K_1 = K_2 = K_3 = K_4 = 0;
}
~Runge_Kutta::Runga_Kutta(){}
float Runge_Kutta::data()
{
int i = 0;
for(i=0 ; i<100 ; i++)
{
x[i] = 5*sin((2*3.14*5*i)*0.01); /*x[i] = A*sin(2*Pi*f*i*Ts)
} Ts-sampling period, A-amplitude,
return x[i]; f-frequency*/
}
float Runge_Kutta::compute()
{
int j = 0;
int i = 0;
for(i = 0 ; i<100 ; i++) // indexing through the input samples
{
for(j = 0 ; j<i+1 ; j++) // compute data points btw i and i+1
{
K_1 = h*x[i];
K_2 = h*((x[i]+(h/2) + K_1/2);
K_3 = h*((x[i]+(h/2) + K_2/2);
K_4 = h* ((x[i] + h) + K_3);
}
y[i] = (1/6)*(K_1 + 2*K_2 + 2*K_3 + K_4); //new data value
}
return y[i];
}
int main()
{
Runga_Kutta Interpolate;
Interpolate.data();
Interpolate.compute();
return 0;
}
问题是:y [i]没有存储新数据值并显示“0”或一些垃圾值。第二个问题是,在这种情况下,我不可能在浮点方面将循环索引值(x轴)增加为“h = 0.2”。我使用断点来找到问题,但我无法弄明白,需要一些帮助或方向来克服这个问题。我有一种感觉,这是由于我的逻辑和一些问题。实现。请检查我的代码和如何解决它的建议将是非常有帮助的。提前致谢。
答案 0 :(得分:1)
你的代码中有几个问题......我会指出我看到的内容。
class Runge_Kutta
{
public:
float x[100];
float y[200];
float h; // step size
float K_1, K_2, K_3, K_4;
float compute(); // function to compute data point
float data(); //function to generate data signal
Runge_Kutta();
~Runge_Kutaa();
};
到目前为止,好吧......
Runge_Kutta::Runge_Kutta()
{
x[100] = 0; // input signal
这是你的第一个问题。 x
数组是100个浮点数,您尝试设置 101st 。请记住,C ++使用从零开始的索引,因此唯一有效的索引是0到99(包括0和99)。通过写x[100]
,你在数组之外写...可能是y
,但你肯定不应该这样做。
更有可能的是,您希望对整个阵列进行零初始化。有不同的方法来创建/初始化一系列值(例如矢量,动态分配),但正如你所做的那样,最简单的方法可能是:
for (int i = 0; i < 100; ++i) { x[i] = 0.0f; }
最好创建一个命名常量来替换“幻数”100.继续使用代码:
y[200] = 0; // output accumulator
与上述x
类似的问题。再一次,我怀疑你是在尝试对整个阵列进行零初始化;替换为:
for (int i = 0; i < 200; ++i) { y[i] = 0.0f; }
然后:
h = 0.2;
这将有效;你可能会收到关于double to float转换的警告,因为2.0被认为是double,但你存储了一个float。您可以通过附加f
来强制浮动文字。
h = 0.2f;
继续:
K_1 = K_2 = K_3 = K_4 = 0;
}
~Runge_Kutta::Runga_Kutta(){}
float Runge_Kutta::data()
{
int i = 0;
for(i=0 ; i<100 ; i++)
{
x[i] = 5*sin((2*3.14*5*i)*0.01); /*x[i] = A*sin(2*Pi*f*i*Ts)
} Ts-sampling period, A-amplitude,
return x[i]; f-frequency*/
}
也许你实际上并没有使用多行注释(例如/ *和* /),但实际上你在这里注释了一些代码......足够它不应该编译。如果要在代码右侧创建块注释,请确保使用每行注释(例如//)。
假设你确实这样做了,你在这里有一个更大的问题。首先声明i
,将其设置为零,然后将其用作循环索引。就其本身而言,这不是一个问题,尽管使用for
内的类型循环更为惯用,如下所示:
for (int i = 0; i < 100; ++i)
最大的问题是在循环后访问x[i]
。此时i
为100,而x[i]
之前的x
位于x[0]
数组之外,只能从0到99进行索引。您的意思是返回float Runge_Kutta::compute()
{
int j = 0;
int i = 0;
for(i = 0 ; i<100 ; i++) // indexing through the input samples
{
for(j = 0 ; j<i+1 ; j++) // compute data points btw i and i+1
{
K_1 = h*x[i];
K_2 = h*((x[i]+(h/2) + K_1/2);
K_3 = h*((x[i]+(h/2) + K_2/2);
K_4 = h* ((x[i] + h) + K_3);
}
y[i] = (1/6)*(K_1 + 2*K_2 + 2*K_3 + K_4); //new data value
}
return y[i];
}
吗?你想要哪个x?返回特定的那个。
i
您可能在本节中混淆了循环指示。 (但我对Runge-Kutta的熟悉程度不够。)x
和y
的{{1}}应该是j
的索引吗? y[i]
在哪里使用,应该使用吗?
最后,返回y
似乎会遇到与上一个循环类似的问题......实际上,您只是将y[100]
从0初始化为99,然后返回{{1} (因为在该函数结束时i == 100)。
如果你对我所提出的任何观点感到困惑,我会尽力澄清;请问。
编辑:如前所述,(1/6)将评估(使用整数除法)为零。用浮点替换一个或两个常量以确保浮点除法...例如1.0/6
因此,您希望在调用data()
或compute()
后访问所有数据...但是现在您要返回单个float
而不是整个数组。这里有一些选择。
首先,您已将x
公开访问。通常不推荐,但如果这是学习或实验,因为它是public
,您可以直接访问该数据。
Runge_Kutta Interpolate;
Interpolate.data();
Interpolate.compute();
for (int i = 0; i < 100; ++i) {
printf("Data point x[%d] = %f\n", i, Interpolate.x[i]);
}
您可以更改data()
和compute()
以返回指向数组的指针,但通常也不建议这样做:
float* Runge_Kutta::data()
{
// the bulk of the function...
return &x[0];
}
// Use:
float* pData = Interpolate.data();
printf("First data signal: %f\n", pData[0]);
另一种选择是提供索引数据访问器:
class Runge_Kutta {
public:
// everything else you already have...
float getDataSignal(size_t i) const {
return x[i];
}
float getDataPoint(size_t i) const {
return y[i];
}
};
另一个选择是使用C ++标准库中的容器,例如vector
,它包含许多方便的操作作为库的一部分。
答案 1 :(得分:0)
您不应该通过引入其他约束(例如必须插入数据集以获取系统函数)来使情况复杂化。
RK::dydx(x,y)
{
return 5*sin(2*M_PI*5*x);
}
并使用RK4食谱配方的正确转录
RK::step(x,y,h)
{
double K1 = h*dydx(x,y);
double K2 = h*dydx(x+h/2, y+K1/2);
double K3 = h*dydx(x+h/2, y+K2/2);
double K4 = h*dydx(x+h , y+K3 );
return y+(K1+2*(K2+K3)+K4)/6
}
然后你可以循环
for(i=0;i<100-1; i++)
{
y[i+1] = step(x,y[i],h);
x +=h;
}