Определение начала наступления полезного сигнала по модальным частотам

У меня есть сигнал, например такой: введите сюда описание изображения

Я разбиваю сигнал на отрезки по 1 секунде. В каждом отрезке я раскладываю сигнал в ряд Фурье и определяю модальную (т. е. имеющую наибольшую амплитуду) частоту. У меня получается набор отрезков и модальные частоты на этих отрезках. Например, вот так: введите сюда описание изображения

Видно, что, когда наступает полезный сигнал(поезд, электричка и т.д.) доминируют низкие частоты 5-6 Гц. Во всё остальное время доминируют высокие частоты шума. Мне нужно в автоматическом режиме определять начала и концы наступлений полезного сигнала. Как мне это сделать? Есть идея со скользящим окном, но не могу понять, что какой конкретно критерий начала и конца участков с полезным сигналом. Подскажите, пожалуйста, алгоритм по которому это можно сделать.


Ответы (2 шт):

Автор решения: MBo

Если ваш первый график относится к реальному сигналу, то стоит использовать мощность сигнала (интеграл или сумма signal^2 по интервалу), а частоты использовать как подтверждение достоверности.

Если будете опираться на частоты, постройте спектрограмму - набор амплитуд Фурье-преобразований для последовательных (или перекрывающихся) интервалов, и оцените отношение мощности каждого спектра в нужном интервале частот (скажем, 5-15 гц) к общей мощности (нулевой, и, наверное, первый отсчет непременно удаляйте из подсчёта). Где это отношение выше порога (заависит от ваших конкретных данных) - преобладают низкие частоты.

Заметьте, что мода не очень для вашей задачи подходит.

→ Ссылка
Автор решения: CrazyElf

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

import pandas as pd
import numpy as np
import matplotlib.pylab as plt

data = np.array([50]*40+[5]*15+[50]*30+[5]*10+[50]*40)
data += np.random.randint(2, size=(len(data)))
data[45] = 30
data[50] = 40
data[90] = 25

series = pd.Series(data)
roll = series.rolling(3).mean()

found = roll < 20
result = (found != found.shift(-1))[:-1]
startstop = result[result].index

plt.figure()
plt.bar(range(len(data)), data)
plt.scatter(startstop, data[startstop], color='red', marker='*')
plt.savefig('data.png')

plt.figure()
roll.plot()
plt.scatter(startstop, roll[startstop], color='red', marker='*')
plt.savefig('dataroll.png')

for a, b in zip(startstop[::2], startstop[1::2]):
    print(f'{a}:{b}')

# 41:54
# 86:94

введите сюда описание изображения введите сюда описание изображения

→ Ссылка