0

我正在开发一种使用 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”。我使用断点来查找问题,但我无法弄清楚,需要一些帮助或指导才能克服这个问题。我有一种感觉,这是由于我的逻辑和实现中的一些问题。请查看我的代码和有关如何修复它的建议,这将有很大帮助。提前致谢。

4

2 回答 2

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(含)。通过写信给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;

这将起作用;您可能会收到关于双精度到浮点转换的警告,因为 2.0 被认为是双精度,但您存储的是浮点数。您可以通过附加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,只能从 0 到 99 进行索引。您的意思是返回x[0]吗?你想要哪个x?返回那个特定的。

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];
}

您可能混淆了本节中的循环索引。(但我对 Runge-Kutta 的了解还不够熟悉。) 应该是和i的索引吗?在哪里使用,应该使用吗?xyj

最后,返回y[i]似乎与前一个循环有类似的问题......事实上,你只是y从 0 初始化到 99,然后你返回y[100](因为 i == 100 在该函数的末尾)。

如果您对我提出的任何观点感到困惑,我会尽力澄清;问一下。

编辑:如前所述, (1/6) 将评估(使用整数除法)为零。用浮点替换一个或两个常量以确保浮点除法...例如1.0/6

data()因此,您希望在调用or ...后访问所有数据,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,它包含许多方便的操作作为库的一部分。

于 2015-03-16T17:18:27.423 回答
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;
}
于 2015-03-18T00:52:35.710 回答