Как мне найти все пики и впадины приливных данных? - PullRequest
4 голосов
/ 12 ноября 2010

Я работаю с некоторыми данными о приливе океана, которые структурированы следующим образом:

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

Вот пример реальных данных, которые я использую: http://pastebin.com/raw.php?i=bRc2rmpG

И это моя попытка найти высокие / низкие значения: http://pastebin.com/8PS1frc0

Текущие проблемы с моим кодом:

  • Когда показания изменяются (как видно из интервала от 11/14/2010=>11:30:00 до 11/14/2010=>11:54:00 в данных выборки), это создает "колебание" в логике направления. Это создает ошибочный пик и корыто. Как я могу избежать / исправить это?

Примечание: Мой метод очень "ad-hoc" .. Я предполагал, что мне не понадобятся какие-то потрясающие математические материалы, так как я не пытаюсь найти какие-либо средние значения, приближения или будущие оценки. Я был бы очень признателен за пример кода лучшего метода, даже если это означает отказ от написанного мною кода.

Ответы [ 7 ]

2 голосов
/ 22 ноября 2010

Я полагаю, вы ищете локальные минимумы и максимумы? Это действительно легко сделать:

<?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 голосов
/ 16 ноября 2010

Мне приходилось выполнять подобные задачи по шумным физиологическим данным. На мой взгляд, у вас есть проблема формирования сигнала. Вот процесс, который работал для меня.

  1. Преобразуйте значения времени в секунды, то есть (ЧЧ * 3600) + (ММ * 60) + (СС), чтобы сгенерировать числовое значение "X".
  2. Сгладьте полученные массивы X и Y с помощью скользящего окна, скажем, 10 точек по ширине. На этом этапе вы также можете рассмотреть возможность фильтрации данных с использованием избыточных и / или поддельных временных меток.
  3. Выполните определение фазы индикации, сравнив сглаженные Y [1] и Y [0]. Как и в предыдущем посте, если (Y [1]> Y [0]), вы можете предположить, что данные достигают пика. Если (Y [1]
  4. Как только вы узнаете, что начальная фаза, обнаружение пиков и впадин может быть выполнено, как описано выше: если Y [i]> Y [i + 1] и Y [i]
  5. Вы можете оценить время пика / спада, проецируя сглаженное значение X обратно на исходные данные X, учитывая размер скользящего окна (чтобы компенсировать «задержку сигнала, вызванную скользящим окном»). Полученное значение времени (в секундах) затем можно преобразовать обратно в формат ЧЧ: ММ: СС для создания отчетов.
1 голос
/ 22 ноября 2010

Проблема в том, что я считаю, что наблюдения являются наблюдениями и могут содержать небольшие ошибки. По крайней мере, это необходимо учитывать. Например:

  • Менять направление только в том случае, если хотя бы следующие 2 записи также находятся в том же направлении.

  • Не допускайте, чтобы решения принимались из-за слишком маленькой разницы. Выбрасывайте незначительные цифры. Вероятно, будет намного лучше, если вы скажете $error = 0.10; и измените условия на if $previous - $error > $current и так далее.

1 голос
/ 12 ноября 2010

Я не читал это подробно, но ваш подход кажется очень специальным.Возможно, более правильным способом было бы приспособить его к функции

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

, используя такой метод, как нелинейные наименьшие квадраты (который, к сожалению, должен быть решен с помощью итерационного метода),Глядя на ваши примеры данных, кажется, что это было бы хорошо.Когда вы вычислили w и p, легко найти пики и долины, просто взяв производную по времени от функции и решив для нуля:

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

Но я полагаю, что если ваш код действительно делает то, чтоВы хотите, нет смысла усложнять вещи.Хватит догадываться.:)

0 голосов
/ 22 ноября 2010

Учитывая, что вы никогда не должны видеть два максимума или 2 минуты менее чем за 12 часов, простое решение состоит в том, чтобы использовать скользящие окна 3-5 часов или около того и найти максимальное и минимальное значения.Если это заканчивается в первые или последние 30 минут, игнорируйте его.

В качестве примера, приведем следующие данные:

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

и окно размером 8, спервые и последние 2 игнорируются и выглядят только взглядом:

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
0 голосов
/ 22 ноября 2010

Одним из способов может быть определение абсолютного или относительного отклонения от прошлого, при котором вы классифицируете дальнейшие пики / впадины как новые, а не как колебания вокруг существующего пика / впадины.

В настоящее время $direction определяет, являетесь ли вынайти пик или впадину, поэтому вместо перехода в другое состояние (поиск впадины или пика) после того, как производная поменяет знак, вы можете рассмотреть возможность изменения состояния только тогда, когда отклонение от текущего пика / впадины достаточно «велико».

0 голосов
/ 13 ноября 2010

Насколько точным должно быть обнаружение пика / впадины? Если вам просто нужно найти точную запись о том, где находится пик или долина, не достаточно ли проверить точки перегиба?

например. рассматривая запись в позиции 'i', если запись [i-1] и запись [i + 1] оба "выше", чем запись [i], вы получаете долину. и если запись [i-1] и запись [i + 1] ниже, чем запись [i], у вас есть пик. Пока ваша частота выборки быстрее, чем изменяется прилив (посмотрите частота Найквиста ), этот процесс должен давать вам максимумы / минимумы ваших данных.

Если вам нужно сгенерировать график из этого и попытаться экстраполировать более точные временные точки для пиков / впадин, то вам предстоит дополнительная работа.

...