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

我有一个 PointCollection,其中包含我生成的正弦数据。 现在我必须建立这些数据的数值积分并将其与正弦数据(每折线)一起绘制。 我在stackoverflow上找到了这个函数,但它并没有真正起作用:( 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 文件中读取数据的函数中。

标签: c# point numerical-integration


【解决方案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 数字的精度极限。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2022-10-05
  • 2011-05-13
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
  • 2022-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多