Поиск циклов в данных
Пытаюсь найти циклы в данных представленных ниже. Как сделать это правильно и эффективно?
import matplotlib.pyplot as plt
from scipy.misc import electrocardiogram
x = electrocardiogram()[2000:4000]
plt.plot(x)
plt.show()
Ответы (1 шт):
Под поисками циклов вы понимаете поиск периодических колебаний максимальными амплитудами?
Если да, то вам нужно построить спектр сигнала и найти частоты с максимальными амплитудами.
Пусть ваша ЭКГ снималась с частотой F отсчетов в секунду (частота дискретизации). Тогда спектр можно вычислить средствами scipy.signal.periodogram. Эта функция возвращает два массива - частоты и спектральную плотность сигнала, которая в простейшем случае равна просто квадрату модуля соотвествующего члена в разложении Фурье.
freqs, psd = signal.periodogram(x, fs=F)
plt.plot(freqs, psd)
Для упрощения картинки можно отбросить высокие частоты. Например, все частоты выше 4 Гц (т.е. сокращения сердца чаще, чем 240 в минуту)
low_freqs = freqs[freqs < 4.0]
psd_low_freqs = psd[:len(low_freqs)]
plt.plot(low_freqs, psd_low_freqs)
В результате картинка станет заметно менее "зубастой"

Я взял для примера кардиограмму из набора данных https://data.mendeley.com/datasets/7dybx7wyfn/3
Для выбранной кардиограммы получил частоту с максимальной амплитудой: freqs[np.argmax(psd)] результат равен 1.3
Частоты, соответствующие наибольшим амплитудам в нижней части спектра:
idx = np.argsort(psd_low_freqs)
idx_most = idx[-3:]
print(low_freqs[idx_most], psd_low_freqs[idx_most])
Результат
array([3.9, 2.6, 1.3]), array([1662.1819, 5103.5654, 9900.397 ], dtype=float32)
Код, данные и графики можно посмотреть в блокноте Junyper.
Там же добавлен пример обработки средствами быстрого преобразования Фурье, без периодограммы.

