Другое

Проблемы реализации FFT: исправление бессмысленных результатов

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

Я пытаюсь выполнить быстрое преобразование Фурье (FFT) над набором данных, содержащим значения времени и амплитуды, для анализа периодичности сигнала. В наборе данных содержится 2,793 выборок с частотой дискретизации 25 Гц, а общее время исследования составляет 111,76 секунд.

Вот мой текущий код:

python
# FFT

N = 2793  # Количество выборок
fs = 25.0  # частота сигнала
T = 1 / fs
Ny = fs / 2.0  # частота Найквиста

# создать массив, соответствующий значениям в сигнале

yf = fft(y)  # выполнить FFT над сигналом
xf = np.linspace(0.0, Ny, N // 2)  # создать новую ось X: частота

# построить график

plt.plot(xf, 2.0 / N * np.abs(yf[:N // 2]))
plt.grid(True)
plt.show()

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

Дополнительная информация:

  • Значения амплитуды масштабированы с коэффициентом 10
  • Данные могут быть не идеально периодическими, поэтому я использую FFT
  • Вот образец формата данных:
номер_строки, время(с), амплитуда, фаза, метка_времени, ...
0, 0.00, -190.919, 0.0698, 0, ...
1, 0.04, -190.814, 0.1397, 40, ...
2, 0.08, -190.769, 0.2094, 80, ...
...
2793, 111.72, -184.862, 0.8796, 111720, ...

Может ли кто-то с опытом работы с FFT помочь мне определить, что может быть не так с моим подходом или кодом?

Реализация FFT: распространенные проблемы и решения

В вашей реализации FFT присутствуют несколько проблем, которые могут приводить к бессмысленным результатам. Основные проблемы связаны с неправильным масштабированием частотной оси, возможным отсутствием оконной функции для непериодических сигналов и неправильной нормализацией FFT. Давайте предоставим comprehensive анализ и решение.

Содержание

Распространенные проблемы реализации FFT

На основе результатов исследования, в вашем коде присутствуют несколько распространенных ловушек FFT:

  1. Неправильный расчет частотной оси: Использование np.linspace(0.0, Ny, N // 2) создает равномерно распределенный массив частот, но это не учитывает фактическое частотное разрешение вашего FFT.

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

  3. Отсутствие оконной функции: Без применения оконной функции разрывы на границах сигнала могут создавать артефакты в частотной области.

  4. Проблемы с масштабированием амплитуд: Факт того, что ваши амплитуды масштабированы с коэффициентом 10, необходимо учитывать в результатах FFT.

Согласно Signal Processing Stack Exchange, “Причина коэффициента 2 заключается в том, что мы хотим компенсировать построение одностороннего спектра, поскольку энергия разделена между положительными и отрицательными частотами.”

Корректировка частотной оси

Расчет частотной оси в вашем коде неправильный. Для правильного анализа FFT следует использовать np.fft.fftfreq() или вычислять частотные корзины на основе частоты дискретизации и длины записи.

python
# Правильный расчет частотной оси
freq = np.fft.fftfreq(N, T)[:N//2]  # Получаем только положительные частоты

Как объясняется в обсуждении на Stack Overflow, частотная ось должна рассчитываться с использованием:

python
freq = np.linspace(0.0, fs/2, N//2)  # fs/2 - частота Найквиста

Однако fftfreq() более точен, так как он учитывает фактические частотные корзины FFT.

Правильное масштабирование и нормализация FFT

Ваш текущий коэффициент масштабирования 2.0/N частично правильный, но может потребовать корректировки в зависимости от вашего конкретного применения. Как отмечено в исследовании, “Ваше решение нормировать или не нормировать не меняет точности вашего ответа, так как это просто коэффициент масштабирования.”

Для одностороннего спектра действительных сигналов правильное масштабирование должно быть:

python
# Масштабирование одностороннего спектра
yf = np.fft.fft(y)
yf_scaled = 2.0 * np.abs(yf[:N//2]) / N

Коэффициент 2 компенсирует энергию, которая разделена между положительными и отрицательными частотами в действительном сигнале.

Оконные функции для непериодических сигналов

Поскольку ваши данные могут быть не идеально периодическими, применение оконной функции является критически важным для уменьшения спектральной утечки. Как упоминается в советах на LinkedIn, “Оконная функция - это математическая функция, которую вы применяете к своим выборкам перед выполнением FFT.”

Распространенные оконные функции включают:

python
from scipy import signal

# Применение оконной функции
window = signal.windows.hann(N)  # Окно Ханна
y_windowed = y * window

# Затем выполняем FFT для данных с оконной функцией
yf = np.fft.fft(y_windowed)

У разных окон разные характеристики:

  • Окно Ханна: Хорошее универсальное окно
  • Окно Хэмминга: Похожее на окно Ханна, но с другими характеристиками боковых лепестков
  • Окно Блэкмана: Лучше подавляет боковые лепестки, но имеет более широкий главный лепесток

Как отмечено в обзоре на ScienceDirect, “усреднение может значительно улучшить отношение сигнал/шум в отображении FFT, но с той же стоимостью замедления скорости измерения.”

Полная исправленная реализация

Вот полная исправленная реализация, которая решает все проблемы:

python
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# Ваши параметры
N = 2793  # Количество выборок
fs = 25.0  # Частота дискретизации (Гц)
T = 1.0 / fs  # Интервал между выборками (секунды)
total_time = N * T  # Общее время (должно быть 111.72 секунд)

# Загрузка ваших данных (предполагаем, что y - ваш массив амплитуд)
# y = ваши_данные_амплитуд  # Здесь должны быть ваши 2793 значения амплитуд

# Применение оконной функции для уменьшения спектральной утечки
window = signal.windows.hann(N)
y_windowed = y * window

# Выполнение FFT
yf = np.fft.fft(y_windowed)

# Расчет частотной оси
freq = np.fft.fftfreq(N, T)[:N//2]  # Только положительные частоты

# Масштабирование результатов FFT для одностороннего спектра
yf_scaled = 2.0 * np.abs(yf[:N//2]) / N

# Учет коэффициента масштабирования амплитуд 10
yf_scaled = yf_scaled / 10  # Поскольку ваши данные масштабированы на 10

# Построение графиков
plt.figure(figsize=(12, 6))
plt.plot(freq, yf_scaled)
plt.grid(True)
plt.xlabel('Частота (Гц)')
plt.ylabel('Амплитуда')
plt.title('Анализ FFT сигнала')
plt.xlim(0, fs/2)  # Показывать до частоты Найквиста
plt.show()

# Опционально: преобразование в децибелы для лучшей визуализации
yf_dB = 20 * np.log10(yf_scaled + 1e-10)  # Добавляем малое значение, чтобы избежать log(0)
plt.figure(figsize=(12, 6))
plt.plot(freq, yf_dB)
plt.grid(True)
plt.xlabel('Частота (Гц)')
plt.ylabel('Амплитуда (дБ)')
plt.title('Анализ FFT сигнала (шкала дБ)')
plt.xlim(0, fs/2)
plt.show()

Дополнительные лучшие практики

  1. Увеличение частотного разрешения: Как отмечено в обсуждении на Stack Overflow, “Не заполняйте нулями, а увеличьте временной интервал вашего сигнала для повышения частотного разрешения.”

  2. Работа со стационарными сигналами: Запись в Википедии предупреждает, что “FFT может быть плохим выбором для анализа сигналов со нестационарным частотным содержимым - где частотные характеристики меняются со временем.” Для таких сигналов рассмотрите использование кратковременного FFT (STFT) или вейвлет-преобразований.

  3. Проверка на периодичность: Как предлагается в документации Analog Devices, сначала следует изучить сигнал во временной области, чтобы понять его характеристики, прежде чем применять FFT.

  4. Учет вычислительной эффективности: Для приложений реального времени учебное пособие MIT по FFT обсуждает аппаратную реализацию и время выполнения, что может быть актуально для вашего приложения.

  5. Валидация с известными сигналами: Протестируйте вашу реализацию с простым синусоидальным сигналом известной частоты, чтобы убедиться, что все работает правильно перед анализом ваших реальных данных.

Ключевая идея из DSP Guide заключается в том, что “Когда два комплексных переменных умножаются, четыре отдельных компонента должны быть объединены для формирования двух компонентов произведения.” Эта сложность в расчетах FFT подчеркивает важность использования хорошо проверенных реализаций вместо написания собственной с нуля.

Источники

  1. Как правильно масштабировать частотную ось в Быстром Преобразовании Фурье?
  2. Следует ли нормировать FFT в Python?
  3. Построение быстрого преобразования Фурье в Python
  4. Масштабирование графиков после FFT
  5. Быстрое Преобразование Фурье - обзор
  6. Какие лучшие практики или советы по использованию FFT в DSP-проектах или исследованиях?
  7. Как работает FFT
  8. Улучшение разрешения FFT - масштабирование Y оси
  9. Как построить FFT сигнала с правильными частотами на оси X?

Заключение

Чтобы исправить вашу реализацию FFT, сосредоточьтесь на этих ключевых областях:

  1. Используйте правильный расчет частотной оси с помощью np.fft.fftfreq() вместо np.linspace()
  2. Применяйте оконные функции, такие как окно Ханна или Хэмминга, для уменьшения спектральной утечки
  3. Правильное масштабирование с коэффициентом 2.0/N для односторонних спектров и учет вашего коэффициента масштабирования амплитуд
  4. Рассмотрите использование шкалы децибел для лучшей визуализации слабых частотных компонент
  5. Тестируйте с известными сигналами для валидации вашей реализации

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

Авторы
Проверено модерацией
Модерация