Самым простым способом определения периодичности данных является автокорреляция .Это также довольно просто реализовать.Чтобы получить автокорреляцию на i
, вы просто умножаете каждую точку данных ваших данных на каждую точку данных, смещенную на i
.Вот некоторый псевдокод:
for i = 0 to length( data ) do
autocorrel[ i ] = 0;
for j = 0 to length( data ) do
autocorrel[ i ] += data( j ) * data( ( j + i ) mod length( data ) )
done
done
Это даст вам массив значений.Наибольшая «периодичность» находится у индекса с наибольшим значением.Таким образом, вы можете извлекать любые периодические части (обычно их больше одной).
Кроме того, я бы посоветовал вам не пытаться внедрять свои собственные БПФ в приложение.Несмотря на то, что этот алгоритм очень хорош для обучения, многое можно сделать неправильно, что сложно проверить, и вполне вероятно, что ваша реализация будет намного медленнее, чем те, которые уже доступны.Если это возможно в вашей системе, я бы посоветовал вам использовать FFTW , который невозможно превзойти, когда дело доходит до реализации FFT.
РЕДАКТИРОВАТЬ:
Объяснение, почему это работает даже для значений, которые не повторяются в точности:
Обычный и полностью правильный способ расчета автокорреляции состоит в том, чтобы вычесть среднее значение из ваших данных.Допустим, у вас есть [1, 2, 1.2, 1.8 ]
.Затем вы можете извлечь 1,5 из каждого образца, оставив вас с [-.5, .5, -.3, .3 ]
.Теперь, если вы умножите это на себя при нулевом значении, негативы будут умножены на негативы, а позитивы на позитивы, что даст (-.5)^2 + (.5)^2 + (-.3)^2 + (.3)^2=.68
.При смещении в 1 негативы будут умножены на позитивы, дающие (-.5)*(.5) + (.5)*(-.3) + (-.3)*(.3) + (.3)*(-.5)=-.64
.При смещении в два раза негативы будут умножаться на негативы, а позитивы - на позитивы.При смещении три снова происходит что-то похожее на ситуацию смещения.Как видите, вы получаете положительные значения со смещением 0 и 2 (периоды) и отрицательные значения при 1 и 4.
Теперь для определения только периода не нужно вычитать среднее значение.Если вы просто оставляете образцы как есть, среднее значение suqared будет добавляться при каждом добавлении.Поскольку для каждого вычисленного коэффициента будет добавлено одно и то же значение, сравнение даст такие же результаты, как если бы вы сначала вычли среднее значение.В худшем случае либо ваш тип данных может быть переполнен (если вы используете какой-то целочисленный тип), либо вы можете получить ошибки округления, когда значения начинают становиться большими (в случае, если вы используете float, обычно это не проблема).Если это произойдет, сначала вычтите среднее значение и попробуйте, если ваши результаты улучшатся.
Самый сильный недостаток использования автокорреляции по сравнению с каким-либо быстрым преобразованием Фурье - это скорость.Автокорреляция занимает O(n^2)
, тогда как для БПФ - O(n log(n))
.Если вам нужно вычислять период очень длинных последовательностей очень часто, автокорреляция может не сработать в вашем случае.
Если вы хотите знать, как работает преобразование Фурье, и что все это говорит о реальной части, имнимая часть, величина и фаза (посмотрите на код, выложенный, например, Ману) означает, я предлагаю вам взглянуть на эту книгу .
EDIT2:
В большинстве случаев данные не являются ни полностью периодическими, ни полностью хаотичными и апериодическими.Обычно ваши данные состоят из нескольких периодических компонентов различной силы.Период - это разница во времени, на которую вы можете сместить ваши данные, чтобы они стали похожими на себя.Автокорреляция вычисляет, насколько похожи данные, если вы сдвинете их на определенную величину.Таким образом, это дает вам силу всех возможных периодов.Это означает, что не существует «индекса повторяющегося значения», потому что, когда данные являются идеально периодическими, все индексы будут повторяться.Индекс с самым сильным значением дает вам сдвиг, при котором данные наиболее похожи на себя.Таким образом, этот индекс дает временной сдвиг, а не индекс ваших данных.Чтобы понять это, важно понять, как временной ряд можно представить как составной из суммы идеально периодических функций (синусоидальных базовых функций).
Если вам нужно обнаружить это для очень длинных временных рядов, обычно также лучше скользить в окне над вашими данными и просто проверять период этого меньшего фрейма данных.Однако вы должны знать, что ваше окно добавит дополнительные периоды к вашим данным, о которых вы должны знать.
Подробнее по ссылке, которую я разместил в последнем редакторе.