如何找到潮汐数据的所有高峰和低谷?

时间:2010-11-12 19:38:31

标签: php multidimensional-array inflection

我正在处理一些结构如下的海潮数据:

$data = array('date' => array('time' => array('predicted','observed')));

以下是我正在使用的实际数据示例:http://pastebin.com/raw.php?i=bRc2rmpG

这是我尝试找到高/低值:http://pastebin.com/8PS1frc0

我的代码的当前问题:

  • 当读数波动时(如样本数据中的11/14/2010=>11:30:0011/14/2010=>11:54:00范围所示),它会在方向逻辑中产生“摆动”。这会产生错误的峰值和谷值。我该如何避免/纠正这个?

注意:我的方法非常“特别”..我认为我不需要任何令人敬畏的数学东西,因为我不想找到任何平均值,近似值或未来的估计值。我真的很感谢一个更好的方法的代码示例,即使它意味着抛弃我到目前为止编写的代码。

7 个答案:

答案 0 :(得分:2)

我必须在嘈杂的生理数据上执行类似的任务。在我看来,你有一个信号调节问题。这是一个对我有用的过程。

  1. 将时间值转换为秒,即(HH * 3600)+(MM * 60)+(SS),以生成数字“X”值。
  2. 使用滑动窗口平滑生成的X和Y数组,例如宽度为10个点。您还可以考虑在此步骤中使用冗余和/或伪造时间戳过滤数据。
  3. 通过比较平滑的Y [1]和Y [0]来执行指示相位检测。与上面的帖子类似,如果(Y [1]> Y [0]),您可以假设数据正在攀升到峰值。如果(Y [1]< Y [0]),您可以假设数据正在下降到谷。
  4. 一旦知道了初始阶段,就可以如上所述进行峰值和谷值检测:如果Y [i]> Y [i + 1]和Y [i]< Y [i-1],你遇到了一个高峰。
  5. 通过考虑滑动窗口大小(为了补偿滑动窗口引起的“信号滞后”),可以通过将平滑的X值投影回原始X数据来估计峰值/谷值时间。然后,可以将生成的时间值(以秒为单位)转换回HH:MM:SS格式进行报告。

答案 1 :(得分:2)

我想要寻找当地的最小值和最大值?这很容易做到:

<?php

$data = array(1, 9, 4, 5, 6, 9, 9, 1);

function minima($data, $radius = 2)
{
  $minima = array();

  for ($i = 0; $i < count($data); $i += $radius)
  {
    $minima[] = min(array_slice($data, $i, $radius));
  }

  return $minima;
}

function maxima($data, $radius = 2)
{
  $maxima = array();

  for ($i = 0; $i < count($data); $i += $radius)
  {
    $maxima[] = max(array_slice($data, $i, $radius));
  }

  return $maxima;
}

print_r(minima($data));
print_r(maxima($data));

?>

您只需指定搜索半径,它将返回一组本地最小值和数据的最大值。它以一种简单的方式工作:它将数组切割成长度为$radius的段,并找到该段的最小值。对整个数据集重复此过程。

小心半径:通常,您希望选择半径作为数据从峰到谷的平均距离,但您必须手动查找。它默认为2,并且只搜索半径为2的最小值/最大值,这可能会对您的数据集产生误报。 明智地选择半径。

你必须将它破解到你的脚本中,但这根本不应该太难。

祝你好运!

答案 2 :(得分:1)

我没有详细阅读,但你的方法看起来非常特别。一种更正确的方法可能是将其适合函数

 f(A,B,w,p;t)=Asin(wt+p)+B 

使用诸如non-linear least squares之类的方法(遗憾的是必须使用迭代方法解决)。查看您的示例数据,看起来它很合适。当你计算了w和p时,只需要取函数的时间导数并求零即可轻松找到峰和谷:

t = (pi(1+2n)-2p)/w

但我想,如果你的代码确实能达到你想要的效果,那么就没有必要使事情复杂化。不要再猜测自己了。 :)

答案 3 :(得分:1)

问题是我认为观察结果是观察结果并且可能包含小错误。至少需要考虑到这一点。例如:

  • 如果至少接下来的两个条目也在同一个方向,则只改变方向。

  • 不要让差异太小的数据做出决定。扔掉微不足道的数字。当你说$error = 0.10;并将你的条件改为if $previous - $error > $current等等时,它会好很多。

答案 4 :(得分:0)

峰值/谷值检测的准确度如何?如果您只是需要找到峰值或谷值出现的确切记录,那么检查拐点是不够的?

e.g。考虑到位置'i'的记录,如果记录[i-1]和记录[i + 1]都比记录[i]“更高”,那么你就有了一个山谷。如果记录[i-1]和记录[i + 1]都低于记录[i],你就有了一个高峰。只要您的采样率快于潮汐变化(查找Nyquist frequency),该过程就可以获得数据的峰值/谷值。

如果您需要从中生成图表并尝试为峰值/波谷推断更准确的时间点,那么您需要做更多的工作。

答案 5 :(得分:0)

一种方法可能是定义绝对或相对偏差,您可以将其他峰值/谷值分类为新的峰值/谷值,而不是现有峰值/谷值周围的波动。

目前,$direction确定您是在寻找峰值还是谷值,因此一旦衍生物在符号中发生变化,您就可以考虑更改状态,而不是转换到另一个状态(找到波谷或峰值)与当前峰值/谷值的偏差“足够大”。

答案 6 :(得分:0)

鉴于你不应该在不到12小时内看到两个最大值或2分钟,一个简单的解决方案是使用3-5小时左右的滑动窗口并找到最大值和最小值。如果它最终是在第一个或最后30分钟,请忽略它。

举个例子,给出以下数据:

1 2 3 4 5 6 5 6 7 8 7 6 5 4 3 2 1 2

和一个大小为8的窗口,第一个和最后一个被忽略,只看一眼你会看到:

1 2 | 3 4 5 6 | 5 6,  max = 6, ignore = Y
2 3 | 4 5 6 5 | 6 7,  max = 7, ignore = Y
3 4 | 5 6 5 6 | 7 8,  max = 8, ignore = Y
4 5 | 6 5 6 7 | 8 7,  max = 8, ignore = Y
5 6 | 5 6 7 8 | 7 6,  max = 8, ignore = N
6 5 | 6 7 8 7 | 6 5,  max = 8, ignore = N
5 6 | 7 8 7 6 | 5 4,  max = 8, ignore = N
6 7 | 8 7 6 5 | 4 3,  max = 8, ignore = N
7 8 | 7 6 5 4 | 3 2,  max = 8, ignore = Y
8 7 | 6 5 4 3 | 2 1,  max = 8, ignore = Y
7 6 | 5 4 3 2 | 1 2,  max = 7, ignore = Y