VC ++中的Runge Kutta方法

时间:2015-03-16 16:53:10

标签: c++ visual-studio-2010 runge-kutta

我正在开发一种使用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”。我使用断点来找到问题,但我无法弄明白,需要一些帮助或方向来克服这个问题。我有一种感觉,这是由于我的逻辑和一些问题。实现。请检查我的代码和如何解决它的建议将是非常有帮助的。提前致谢。

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的熟悉程度不够。)xy的{​​{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;
}
相关问题