在 C# 中查找 sin/cos 曲线的最小值和最大值的最有效方法

发布于 2024-09-08 05:40:09 字数 785 浏览 7 评论 0原文

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

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

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

任何建议表示赞赏。

编辑

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

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

Background: I have a function in my program that takes a set of points and finds the minimum and maximum on the curve generated by those points. The thing is it is incredibly slow as it uses a while loop to figure out the min/max based on approximated error. Not completely sure what formal method this is because I did not write it myself, but I know we need a new and more efficient one.

Question: My question is what is the best and most efficient method/algorithm to finding the min max points on a curve, using C#, that is also very accurate?

About the curve: I have my Numerical Analysis book from college near me, so all I need is a method name and a nudge in the right direction. I can generate as many points as I choose to approximate the curve, but I want to keep the number of points to an efficient minimum. The curve is always in the shape of one segment of a Sin/Cos curve, but not always the same curve and will always be less that one period. The range of Theta is 0° to 359.999...° It has some phase and amplitude shift and Y will never be negative. This function/algorithm will have to run fast as it will be run every several hundred milliseconds as the curve changes.

Any suggestions are appreciated.

EDIT

More info on the curve: The points are generated on mouse move. The points are a set of points based on the length of a rubber belt in a drive design with an idler, such as one like the serpentine belt in a car. The position of the idler determines the length of the belt and I get the curve [belt length(y) vs idler position(x)]. The idler in this case is a pivoting idler and will have constant circular motion. If the drive design changes the curve will change, either because the length points change, or because the range of motion of the idler has been constrained. The range of motion in the idler is potentially 0° to 359.999...° and is theta as stated above. For a slotted idler the maximum range is 1/2 of the period of the curve (easier problem).

I guess what I need is a general solver for both types of idlers, but the real issue is with the pivoting idler.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

末が日狂欢 2024-09-15 05:40:09

如果您有一个二次方程,则最大值或最小值将始终位于方程的微分为 0 的点。如果您的二次方程的公式为 ax^2 + bx + c = 0,则该点将是当 x =-b/2a。

是否是最大opr最小值可以通过查看a来确定。如果a> 0 那么它是最小值并且如果 a < 0 则其最大值(如果 a = 0 则其不是二次方)。

我希望这有帮助。如果你没有得到这种形式的曲线方程,你能说一下你需要做什么吗?

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

编辑2:

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

If you have a quadratic equation then the maximum or minimum will always be at the point when the differential of the equation is 0. If your quadratic equation has a formula of ax^2 + bx + c = 0 then this point will be when x = -b/2a.

Whether it is a maximum opr minimum can be determined by looking at a. If a > 0 then its a minimum and if a < 0 then its a maximum (if a = 0 then its not a quadratic).

I hope that helps. If you haven't got the equation of the curve in this sort of form could you say what you have got to work from?

Edit: question has changed so that the curve is a section of a sine curve and not a quadratic any more. This answer is therefore no longer appropriate.

Edit2:

With a sine curve the general equation will be y = a sin(mx+t) + c. You will never be able to exactly determine the original equation because for any solution there will be a higher frequency solution that also matches. I'm unsure currently how many points are needed to precisely calculate what a would be (which would give the min and max of the curve).

情丝乱 2024-09-15 05:40:09

您应该使用的算法(以及您提供的参数)取决于您的数据集的外观。听起来您正在评估连续获取的某些物理测量的波形。

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

固定峰值检测算法通常有某种方式来指定阈值、宽度(以控制对尖峰的敏感度)和缓冲区大小(以处理真正渐进的峰值)。

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

The algorithm you should use (and the parameters you give it) depends on what your data set looks like. It sounds like you are evaluating a waveform of some physical measurement that is acquired continuously.

If so, then you need to decide whether you want to ignore local minima and maxima (eg spikes from noise in the signal). Also, you'll want some way to handle the edges of your data set. In other words, does the beginning of your data count as a maxima if it is the highest point in the current dataset but is merely coming down from a big peak in the previous one?

Canned peak detection algorithms will typically have some way to specify a threshold and also a width (to control sensitivity to spikes) and a buffer size (to handle really gradual peaks).

There are plenty of algorithms out there, just pick one or two and tweak parameters until it gives the results you expect.

相对绾红妆 2024-09-15 05:40:09

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

Since the curve is always quadratic (and thus always convex), there should be a lot of methods available (though since I don't program in c#, I don't know if source is available). Newton's method comes to mind first but there are others (like interior point methods). For a mathematical background of these algorithms (but not their implementations, unfortunately), see this textbook (pdf). If you do use any of these methods, they'll work for other convex curves as well.

扛刀软妹 2024-09-15 05:40:09

你有可用的所有点吗?并且这些点所代表的函数的“形状”没有限制吗?如果是这样,那么您可能会陷入困境,迭代这些点将是您最好的选择......
尽管如果您对此集还有任何其他工作要做,您可能希望按 Y 坐标对其进行排序,以供将来处理使用。

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

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

A。递归例程,检查/找到第一个和最后一个拐点,比较它们以确定哪个是最大的,然后递归地检查并找到它们之间的拐点,直到涉及的两个点小于距一个点的最小允许周期另一种,会产生一些性能提升...

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

伪代码:

  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

Is all you have available the set of points? And are there no restrictions on the "shape" of the function these points represent? If so, then you're probably stuck, iterating through the points will be your best bet...
Although if you have any other work to do on this set, you might want to sort it by the Y-coord for use by future processing.

(Keep both arrays around - the one you were fed as input (it's probably sorted by x-corrd ?) and the one sorted by function value(y-coord) ) ...

Edit: if you know that the curve will always be shaped "like" a portion of Sin/Cos curve, then if you know the smallest period that might be represented, you can do some optimizations by using binary search algorithm to "look" for the inflection points (where the slope (Change in Y to the left and to the right ) are of different signs. For each point examined on the left, move to the right by chunks = half the allowable period until you find the point of inflection, or the slope changes sign... Then move back by half the last change in x, until you find the point of inflection. [Do the opposite for the points on the right]

A recursive routine that examines/finds the first and last inflection point, compares them to determine which is greatest, and then recursively examines and finds, the inlfection point halfway between them, until the two points involved are less than the smallest allowable period aprt from one another, will produce some performance gains...

2nd EDIT: Since I read in yr other comment that set will never contain more than one inflection point... If this so, then just do binary search to find it.

PsuedoCode:

  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
半岛未凉 2024-09-15 05:40:09

收集了几个点 (>=4) 后,您可以使用本地搜索的形式将您的点与正弦曲线 y = A cos(Bx+C)+D 匹配,然后使用简单的根据导数公式求最小值。搜索时,B尽量少,避免出现多余的高频解。只是一个想法,可能效率很低。

After you collected a few points (>=4) you could use a form of local search to match your points to a sine curve y = A cos(Bx+C)+D then use a simple formula based on the derivative to find the minimum. While searching, you should keep B as little as possible to avoid redundant hi-frequency solutions. Just an idea, may be very inefficient.

青衫儰鉨ミ守葔 2024-09-15 05:40:09

从注释中,输入 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;
    }

我希望这会很快。

From the comment the input X and the output Y are arrays

"@Mike:I generate the values and put them in an array"

I suggest to use this approach.
All what you need from my code is {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;
    }

I hope that will be fast.

流星番茄 2024-09-15 05:40:09

我有点困惑。

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

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

I'm a little confused.

If you yourself are generating the points, why not just keep track of the largest/smallest points when doing the generating?

If you have a function, like I'm sure others have pointed out, just get the derivative and solve for 0. This will give you the point(s) of min/max.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文