C#中PointCollection的数值积分

Posted

技术标签:

【中文标题】C#中PointCollection的数值积分【英文标题】:Numerical Integration of PointCollection in C# 【发布时间】:2021-12-25 21:57:05 【问题描述】:

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

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

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;

【问题讨论】:

幻数y/5+300是什么意思? 这就是缩放,我已经谈过了。而且我不明白,为什么我需要它来适应我的画布。 您的问题是正 y 值指向下方(像素坐标)并且您的输入数据有 y 值指向上方,就像在正常的笛卡尔坐标中一样系统? 这应该不是问题,因为原始数据和插值数据显示正确。并且所有这些函数都得到相同的输入数据,除了积分函数。得到的就是插值数据。 从笛卡尔坐标系到像素坐标系的转换发生在我从 csv 文件中读取数据的函数中。 【参考方案1】:

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

程序

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

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

【讨论】:

PointCollection 表示 Point 结构的集合,其 coordinates 是 double 而不是 float

以上是关于C#中PointCollection的数值积分的主要内容,如果未能解决你的问题,请参考以下文章

《数值分析》-- 数值积分

数值积分 模板

数值分析实验之数值积分法(java 代码)

数值分析实验之数值积分法(java 代码)

计算方法数值积分

6.1 数值分析: 数值积分的基本概念