【问题标题】:Most efficient way to find min and max of a sin/cos curve in C#在 C# 中查找 sin/cos 曲线的最小值和最大值的最有效方法
【发布时间】:2010-07-06 15:24:47
【问题描述】:

背景: 我的程序中有一个函数,它采用一组点并在这些点生成的曲线上找到最小值和最大值。问题是它非常慢,因为它使用 while 循环根据近似误差来计算最小值/最大值。不完全确定这是什么正式方法,因为我不是自己编写的,但我知道我们需要一种新的更高效的方法。

问题:我的问题是使用 C# 在曲线上找到最小最大点的最佳和最有效的方法/算法是什么,也非常准确?

关于曲线:我附近有一本大学的数值分析书,所以我只需要一个方法名称和一个正确的方向。我可以生成尽可能多的点来逼近曲线,但我想将点数保持在有效的最小值。曲线总是呈正弦/余弦曲线的一段形状,但并不总是相同的曲线,而且总是小于一个周期。 Theta 的范围是 0° 到 359.999...° 它有一些相位和幅度偏移,并且 Y 永远不会是负数。这个函数/算法必须快速运行,因为它会随着曲线的变化每隔几百毫秒运行一次。

欢迎提出任何建议。

编辑

关于曲线的更多信息:这些点是在鼠标移动时生成的。这些点是基于带惰轮的驱动设计中的橡胶带长度的一组点,例如汽车中的蛇形皮带。惰轮的位置决定了皮带的长度,我得到曲线[皮带长度(y)与惰轮位置(x)]。在这种情况下,惰轮是一个可旋转的惰轮,将具有恒定的圆周运动。如果驱动设计改变,曲线也会改变,要么是因为长度点改变,要么是因为惰轮的运动范围受到限制。惰轮的运动范围可能是 0° 到 359.999...°,并且是如上所述的 theta。对于开槽惰轮,最大范围是曲线周期的 1/2(更简单的问题)。

我想我需要的是这两种惰轮的通用求解器,但真正的问题是旋转惰轮。

【问题讨论】:

  • 您的积分是如何产生的?起初我以为它们是从其他地方采样的,但现在我发现它们随着您移动鼠标而发生变化。这是否意味着您有一个方程正在以某种方式被鼠标移动改变?如果您以编程方式创建这些点,那么您应该拥有(或能够推导出)曲线的方程...
  • @Chris,在帖子中添加了有关您的问题的更多信息。
  • 某个范围内 sin(或 cos)的最小值/最大值为 -1、1 或端点的 sin(或 cos)。你还需要什么?
  • @Mike:你的值是数组还是列表?
  • 听起来你应该能够直接计算最小值/最大值,但不幸的是我不完全理解手头问题的机制 - 主要是因为我不确定闲人是什么或确实(并且对传动带的细节有点模糊,等等。除非你有时间做一个图表或向可怜的小我解释问题到底是什么样的,否则我将退出这里。;-)希望其他人能更好地理解您的问题并能够提供帮助。 :)

标签: c# algorithm math curve numerical-analysis


【解决方案1】:

如果你有一个二次方程,那么最大值或最小值总是在方程的微分为 0 时。如果你的二次方程有一个公式 ax^2 + bx + c = 0,那么这个点将当 x = -b/2a 时。

是否是最大 opr 最小值可以通过查看 a 来确定。如果 a > 0 则它是最小值,如果 a

我希望这会有所帮助。如果你还没有这种形式的曲线方程,你能说一下你要从什么开始工作吗?

编辑: 问题已更改,因此曲线是正弦曲线的一部分,不再是二次曲线。因此,这个答案不再合适。

编辑2:

对于正弦曲线,一般方程为 y = a sin(mx+t) + c。您将永远无法准确确定原始方程,因为对于任何解决方案,都会有一个更高频率的解决方案也匹配。我不确定目前需要多少点来精确计算 a 将是什么(这将给出曲线的最小值和最大值)。

【讨论】:

  • 我有一组工作要点。正如我所提到的,我可以根据需要生成尽可能多的这些点,但我需要将其保持在最低限度以保持功能高效。
  • 他说他可以生成任意多的点,因此我推断他有一个曲线方程。您可以从该曲线上的三个点获得曲线的方程,但是对于三个点,您应该能够使用此方法。我只需要弄清楚如何在代码中求解联立方程...
  • 曲线的公式是一个 n-1 度方程。对于五分,它是一个四阶公式,如 y=ax^4+bx^3+cx^2+dx+e。你只需要推导出它并确定它在哪里找到最小和最大点。
  • 你有y = ax^2 + bx + c插入3点(x1, y1), (x2, y2), (x3, y3),找出abc然后这个答案应该是你需要的。
  • 我更多地考虑了我所拥有的点生成的曲线,发现它将是正弦/余弦曲线的形状,而不是二次曲线。它将始终处于这种形状,并且始终小于一个阶段。我相应地编辑了我的帖子。
【解决方案2】:

你应该使用的算法(以及你给它的参数)取决于你的数据集是什么样的。听起来您正在评估一些连续采集的物理测量的波形。

如果是这样,那么您需要决定是否要忽略局部最小值和最大值(例如信号中的噪声尖峰)。此外,您还需要某种方法来处理数据集的边缘。换句话说,如果数据的开头是当前数据集中的最高点,但只是从前一个大峰值下降,那么它是否算作最大值?

标准峰检测算法通常有一些方法来指定阈值、宽度(以控制对尖峰的敏感性)和缓冲区大小(以处理真正渐变的峰)。

那里有很多算法,只需选择一两个并调整参数,直到得到您期望的结果。

【讨论】:

  • 你能引导我到我能找到他们的地方吗?我应该只用谷歌搜索“峰值检测算法”吗?此外,在回答您的问题时,该集合非常受限。它是由带惰轮的皮带传动点 [皮带长度与惰轮位置] 生成的波形,很像汽车发动机中的蛇形皮带传动。
  • 当我的程序的用户在鼠标移动事件上更改驱动器设计时,需要更新最小值和最大值。
  • 另外,开头和结尾都算数,就像你上面问的那样。
  • AFAIK 峰值检测算法包括与前一篇文章中描述的 bretana 类似的内容。但是,通常执行的关键步骤是在搜索之前进行某种类型的过滤。您需要对波形进行足够的过滤,以便忽略比预期峰值窄得多(或宽得多)的峰值。这样,在您的数据集中进行斜率测量时,可以跳过更多的点。能够在搜索中进行较大的跳跃会使其更快。
【解决方案3】:

由于曲线总是二次的(因此总是凸的),应该有很多可用的方法(虽然因为我没有用 c# 编程,我不知道是否有源)。首先想到的是牛顿法,但还有其他方法(如内点法)。有关这些算法的数学背景(不幸的是,不是它们的实现),请参阅this 教科书 (pdf)。如果您确实使用了这些方法中的任何一种,它们也适用于其他凸曲线。

【讨论】:

  • 其实我没有注意到你只有一组点。不确定答案在这种情况下的适用性,但如果您对一般凸优化技术感兴趣,请查看链接。
  • 现在我想它可能最终会形成一段正弦/余弦曲线的形状,但总是小于一个完整的相位。我已经相应地编辑了我的帖子。
  • 在这种情况下,如果您可以将域限制为函数为凸的集合(例如,在标准正弦图上从 pi 到 2*pi),并找到适用于你,你可以找到一个最低限度。 (您可以使用类似的技巧来找到最大值。)
  • 我的意思是少于一个时期。
  • 如果明显小于一个周期并且不包含拐点,则曲线段将始终是凸的或凹的。
【解决方案4】:

你有所有可用的点吗?这些点所代表的功能的“形状”是否没有限制?如果是这样,那么您可能会被卡住,迭代积分将是您最好的选择...
尽管如果您对这个集合有任何其他工作要做,您可能希望按 Y 坐标对其进行排序以供将来处理使用。

(保留两个数组 - 作为输入提供的一个(它可能按 x-corrd 排序?)和按函数 value(y-coord) 排序的一个)...

编辑:如果您知道曲线的形状总是“像”Sin/Cos 曲线的一部分,那么 如果您知道可能表示的最小周期,您可以通过使用二分搜索算法来“寻找”拐点(其中斜率(Y 向左和向右的变化)具有不同符号的地方)来进行一些优化。对于每个检查左边的点,向右移动块 = 允许周期的一半,直到找到拐点,或者斜率改变符号... 然后向后移动 x 最后一次变化的一半,直到找到点拐点。[对右边的点做相反的事情]

检查/找到第一个和最后一个拐点的递归例程,比较它们以确定哪个最大,然后递归检查并找到它们中间的感染点,直到所涉及的两个点小于允许的最小点彼此之间的周期会产生一些性能提升......

第二次编辑:因为我在 yr 中阅读了其他评论,该集永远不会包含一个以上的拐点......如果是这样,那么只需进行二进制搜索即可找到它。

伪代码:

  Check Leftmost point to see slope (Up Down or Zero)
       If Zero, done
  Check RightMost Slope 
       If Zero - Done
  If two Slopes are same sign - Done 
        - pick Bigger of two points ( - or smaller if looking for min)
  Check point in the Middle slope
     If Zero, Done
     If slope has same sign as left pt, Change Left to this Point and repeat
     If slope has same sign as right pt, Change Right to this Point and repeat

【讨论】:

  • 形状总是呈正弦/余弦曲线的某个部分的形状,尽管它总是小于一个相位。我编辑了我的帖子以包含此信息。
  • 我的意思是,少一点。
  • @Charles,这就是算法现在所做的。评估很好,但效率不足以满足我的需要,并且在持续更新时会在我的程序中产生延迟。
  • @Mike,那我恐怕没有其他更好的主意了……抱歉!
  • @Charles Bretana,不用担心。感谢您的帮助。
【解决方案5】:

收集几个点 (>=4) 后,您可以使用一种局部搜索形式将您的点与正弦曲线 y = A cos(Bx+C)+D 匹配,然后使用基于导数的简单公式来找到最小值。在搜索时,您应该尽可能少地保留 B 以避免冗余的高频解决方案。只是一个想法,可能效率很低。

【讨论】:

    【解决方案6】:

    从注释中输入 X 和输出 Y 是数组

    "@Mike:我生成值并将它们放入一个数组"

    我建议使用这种方法。 你需要从我的代码中得到的只是 {getMaxIndex}

        private void Test()
        {
            double[] X = SetLinearRange(0, Math.PI * 2, 1000);
            double[] Y = GetOutput(X);
            int MaxIndex = getMaxIndex(Y);
            double MaxX = X[MaxIndex];
            double MaxY = Y[MaxIndex];
        }
        private double[] SetLinearRange(double Start, double End, int Sample)
        {
            double Step = (End - Start) / Sample;
            double CurrentVaue = Start;
            double[] Array = new double[Sample];
            for (int Index = 0; Index < Sample; Index++)
            {
                Array[Index] = CurrentVaue;
                CurrentVaue += Step;
            }
            return Array;
        }
        private double[] GetOutput(double[] X)
        {
            double[] Array;
            Array = (from double Item in X select myFunction(Item)).ToArray();
            return Array;
        }
        private double myFunction(double x)
        {
            double y;
            //put any function
            y = 3 * Math.Sin(5 * x + 2);
            return y;
        }
        private int getMaxIndex(double[] Y)
        {
            double YM = Y.Max();
            int Index = Y.ToList().IndexOf(YM);
            return Index;
        }
    

    我希望这会很快。

    【讨论】:

      【解决方案7】:

      我有点困惑。

      如果您自己在生成点,为什么不在生成时跟踪最大/最小点?

      如果你有一个函数,就像我相信其他人已经指出的那样,只需求导数并求解 0。这将为你提供最小值/最大值的点。

      【讨论】:

        猜你喜欢
        • 2015-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-18
        • 1970-01-01
        • 2023-03-09
        • 2012-09-16
        相关资源
        最近更新 更多