簡體   English   中英

Python中FFT波形的索引峰值

[英]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

然后我想從這種 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM