首页 > 解决方案 > C#中PointCollection的数值积分

问题描述

我有一个 PointCollection,其中包含我生成的正弦数据。现在我必须建立这些数据的数值积分并将其与正弦数据(每折线)一起绘制。我在stackoverflow上找到了这个函数,但它并没有真正起作用:(sin(x)的积分通常应该是-cos(x),但我得到的是-sin(x),我必须缩放是的,但在类似的插值函数中,它无需缩放即可工作.有人知道我的问题在哪里吗?

红色:原始噪声数据,蓝色:插值数据绿色:综合数据 图片

private PointCollection Numerical_Integration(PointCollection input_data)
{
      PointCollection integrated_data = new();
      for (int i = 1; i < input_data.Count; i++)
      {
            double integrated_ypos = (input_data[i].Y + input_data[i - 1].Y) / 2 * (input_data[i].X - input_data[i - 1].X);
            integrated_data.Add(new Point(input_data[i].X, integrated_ypos/5+300));
      }
      return integrated_data;
}

标签: c#pointnumerical-integration

解决方案


这使用标准梯形规则进行积分。

程序

static class Program
{
    static void Main(string[] args)
    {
        // Integrate f(x) = 10*cos(x) between x=0..4π
        var curve = new PointCollection();
        const int n = 180;
        for (int i = 0; i < n; i++)
        {
            float x = (float)( (4 * Math.PI * i) / n );
            float y = (float)( 10 * Math.Cos(x) );
            curve.Add(new PointF(x, y));
        }

        var integral = Integrate(curve, 0f);

        // Compare results to 10*sin(x)
        float max_error = 0;
        for (int i = 0; i < n; i++)
        {
            float x = (float)((4 * Math.PI * i) / n);
            float iy_expect = (float)(10 * Math.Sin(x));
            float iy_actual = integral[i].Y;
            float iy_error = Math.Abs(iy_actual - iy_expect);
            max_error = Math.Max(max_error, iy_error);
        }
        Console.WriteLine($"Steps = {n}, Max Error = {max_error}.");
    }

    public static PointCollection Integrate(PointCollection inputData, float integrationConstant = 0)
    {
        float h;
        var integral = new PointCollection();
        integral.Add(new PointF(inputData[0].X, integrationConstant));
        for (int i = 1; i < inputData.Count; i++)
        {
            h = inputData[i].X - inputData[i - 1].X;
            float iy = integral[i - 1].Y + h * (inputData[i].Y + inputData[i - 1].Y) / 2;
            integral.Add(new PointF(inputData[i].X, iy));
        }
        return integral;
    }
}

输出

Steps = 180, Max Error = 0.004058838.

从输出中可以看出,考虑到输入曲线的分辨率,误差非常好。

错误分析

考虑到越来越多的步骤,这是我报告的最大错误:

 Steps           Error
    16       0.5194054
    32       0.1288424
    64      0.03214836
   128     0.008034706
   256     0.002008438
   512    0.0005044937
  1024    0.0001296997
  2048     3.71933E-05
  4096    1.049042E-05
  8192    1.716614E-05
 16384    1.335144E-05
 32768    2.288818E-05

如您所见,我float在大约 4096 步处达到了数字的精度极限。


推荐阅读