[英]Index peaks of FFT waveform in Python
我有從加速度計獲得的采樣數據,每個軸上的加速度('x','y'和'z')。
該數據存儲為 Pandas DataFrame,每個軸都有一個列。
有了這個,我得到了這樣的 FFT:
import pandas as pd
from scipy import fft
from typing import Optional
def fft_raw(df: pd.DataFrame) -> pd.DataFrame:
"""Calculates the raw Fast Fourier Transform of a DataFrame
Parameters
----------
df : pd.DataFrame
DataFrame whose FFT should be calculated
Returns
-------
pd.DataFrame
Raw FFT
"""
fft_raw = pd.DataFrame()
for c in df:
fft_raw = fft_raw.join(
pd.DataFrame(fft.rfft(np.array(df[c])), columns=[c]), how="outer"
)
return fft_raw
def norm_fft(fft_raw: pd.DataFrame, length: Optional[int] = None) -> pd.DataFrame:
"""Normalizes a raw FFT
Parameters
----------
fft_raw : pd.DataFrame
Raw FFT to be normalized
length : int, optional
How many sample points were used for calculating the raw FFT
It uses the length of `fft_raw` by default
Returns
-------
pd.DataFrame
Normalized FFT
"""
if length is None:
length = len(fft_raw)
return 2.0 * (fft_raw.abs() / length)
然后我想從這種 FFT 中提取峰值。
在上面給出的示例中,“z”軸的峰值約為:
2.90 Hz at 0.15 g
54.56 Hz at 0.90 g
106.22 Hz at 0.10 g
我考慮做的一件事是過濾掉所有幅度低於給定閾值的頻率(例如,它可能在0.1 g
左右),這會給我一個只有峰值的波形。
這樣做的問題是我在峰值周圍仍然會有很多采樣點,因為它通常會“上升”到峰值的最大值,然后“下降”到幾乎沒有,這會占用多個點,不止一個。
然后我考慮嘗試將波形“拆分”成代表單個峰值的點組,這樣我就可以找到它們的最大值,但我不太確定這樣做的有效方法。
我試圖找到一個類似的問題,然后遇到了這個問題,但我無法讓它工作,即使在將我的數據簡化回 Numpy 數組之后。
所以我決定在這里問是否有人知道一種有效的方法,最好是使用 Pandas 來獲得 FFT 的峰值。
我找到了一種實現理想結果的方法,基於這個問題,並使用PeakUtils庫:
import pandas as pd
import peakutils
def find_peaks(
df: pd.DataFrame, threshold: pd.Series, min_dist: int = 50
) -> Dict[str, pd.Series]:
index = df.index
df.reset_index(drop=True, inplace=True)
all_peaks = dict()
for c in df:
if c in threshold:
data = df[c]
peaks = peakutils.indexes(
data, thres=threshold[c], min_dist=min_dist, thres_abs=True
)
all_peaks[c] = pd.Series()
for peak in peaks:
peak_index = index[peak]
val = data[peak]
to_append = pd.Series([val], index=[peak_index])
all_peaks[c] = all_peaks[c].append(to_append)
return all_peaks
def find_fft_peaks(
df: pd.DataFrame, threshold: pd.Series, dist_hz: float = 1
) -> Dict[str, pd.Series]:
index = df.index
index_interval = index[-1] - index[0]
points_per_hz = len(index) / index_interval
min_dist = int(points_per_hz * dist_hz)
return find_peaks(df=df, threshold=threshold, min_dist=min_dist)
它似乎做得很好,雖然我仍然覺得它有點hacky。
它可能不是超級高效或干凈,但它現在可以完成這項工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.