背景:我的程序中有一个函数,它接受一组点并找到这些点生成的曲线的最小值和最大值。事情是它非常慢,因为它使用while循环根据近似误差计算出最小值/最大值。不完全确定这是什么形式的方法,因为我自己没有写,但我知道我们需要一个新的,更有效的方法。
问题:我的问题是使用C#查找曲线上最小最大点的最佳和最有效的方法/算法是什么?这也是非常准确的?
关于曲线:我的大学附近有我的数值分析书,所以我需要的是一个方法名称和正确方向的推动。我可以生成尽可能多的点来近似曲线,但我希望将点数保持在最小值。曲线始终为Sin / Cos曲线的一段形状,但并不总是相同的曲线,并且总是小于一个周期。 Theta的范围是0°到359.999 ...°它有一些相位和幅度偏移,Y永远不会是负的。这个函数/算法必须快速运行,因为它会随着曲线的变化每隔几百毫秒运行一次。
任何建议都表示赞赏。
修改
关于曲线的更多信息:这些点是在鼠标移动时生成的。这些点是基于带有惰轮的驱动设计中的橡胶带的长度的一组点,例如像汽车中的蛇形带那样的惰轮。惰轮的位置决定了皮带的长度,我得到了曲线[皮带长度(y)与惰轮位置(x)]。在这种情况下,惰轮是一个旋转惰轮,并将具有恒定的圆周运动。如果驱动器设计发生变化,曲线将发生变化,原因可能是长度点发生变化,或者因为惰轮的运动范围受到限制。惰轮的运动范围可能为0°至359.999 ...°,如上所述为θ。对于开槽惰轮,最大范围是曲线周期的1/2(更容易出问题)。
我想我需要的是两种类型闲人的一般解算器,但真正的问题在于旋转惰轮。
答案 0 :(得分:2)
如果你有一个二次方程,那么最大值或最小值总是在方程的微分为0时。如果你的二次方程有一个公式ax ^ 2 + bx + c = 0那么这一点将当x = -b / 2a时。
是否是最大opr最小值可以通过查看a来确定。如果a>然后它是最小值,如果是< 0然后是最大值(如果a = 0则不是二次方)。
我希望有所帮助。如果你没有得到这种形式的曲线方程,你能说出你必须要做的工作吗?
编辑:问题已更改,因此曲线是正弦曲线的一部分,而不再是二次曲线。因此,这个答案不再合适。
编辑2:
使用正弦曲线,一般方程式为y = a sin(mx + t)+ c。您永远无法确切地确定原始等式,因为对于任何解决方案,都会有更高频率的解决方案也匹配。我现在不确定需要多少点才能精确计算出它将会是什么(这将给出曲线的最小值和最大值)。
答案 1 :(得分:0)
您是否有可用的积分?对这些点所代表的功能的“形状”没有限制吗?如果是这样,那么你可能会陷入困境,迭代积分将是你最好的选择...
虽然如果您在此设置上还有其他工作要做,您可能希望通过Y-coord对其进行排序,以供将来处理使用。
(保持两个阵列 - 你输入的那个作为输入(它可能按x-corrd排序?)和按功能值排序的那个(y-coord))......
编辑:如果您知道曲线将始终形成“喜欢”Sin / Cos曲线的一部分,那么 如果您知道可能表示的最小周期 ,您可以通过使用二分搜索算法“查看”拐点来进行一些优化(其中斜率(Y向左和向右的变化)具有不同的符号。在左侧检查点,通过块移动到右边=允许周期的一半,直到找到拐点,或者斜率改变符号...然后向后移动x的最后一次更改的一半,直到找到点变形。[对右边的点做相反的事情]
检查/找到第一个和最后一个拐点的递归例程,比较它们以确定哪个最大,然后递归检查并找到它们之间的中间点,直到所涉及的两个点小于允许的最小点相互之间的期间,会产生一些性能提升......
第二次编辑:因为我读过其他评论,集合永远不会包含多个拐点......如果是这样,那么只需进行二元搜索即可找到它。
<强>伪码:强>
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
答案 2 :(得分:0)
由于曲线总是二次的(因而总是凸起的),应该有很多方法可用(虽然因为我不用c#编程,所以我不知道源是否可用)。首先想到牛顿的方法,但还有其他方法(如内点法)。有关这些算法的数学背景(但不幸的是,不是它们的实现),请参阅this教科书(pdf)。如果您使用这些方法中的任何一种,它们也适用于其他凸曲线。
答案 3 :(得分:0)
您应该使用的算法(以及您提供的参数)取决于您的数据集的外观。听起来您正在评估连续采集的某些物理测量的波形。
如果是这样,那么您需要决定是否要忽略局部最小值和最大值(例如信号中的噪声尖峰)。此外,您还需要一些方法来处理数据集的边缘。换句话说,如果数据的开头是当前数据集中的最高点但是仅仅是从前一个数据中的一个大峰下降,那么数据的开头是否会计为最大值?
固定峰值检测算法通常会有一些方法来指定阈值和宽度(控制对尖峰的敏感度)和缓冲区大小(以处理真正渐变的峰值)。
有很多算法,只需选择一个或两个并调整参数,直到它给出你期望的结果。
答案 4 :(得分:0)
在您收集了几个点(&gt; = 4)后,您可以使用局部搜索形式将您的点与正弦曲线y = A cos(Bx+C)+D
匹配,然后使用基于导数的简单公式来找到最小值。搜索时,应尽量少保持B,以避免冗余的高频解决方案。只是一个想法,效率可能非常低。
答案 5 :(得分:0)
从注释中输入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;
}
我希望这会很快。
答案 6 :(得分:0)
我有点困惑。
如果您自己正在生成这些点,为什么不在生成时跟踪最大/最小点?
如果你有一个功能,就像我确定其他人已经指出的那样,只需得到导数并求解为0.这将给你最小/最大的点数。