4. 特征工程

任务目标

本案例以一段加速度计原始信号为输入,通过Python实现特征工程,提取时域统计特征(均值、标准差、均方根、峰值、峰峰值、过零率)与频域特征(主频幅值、频谱质心),输出结构化特征向量,为后续边缘AI分类模型提供输入。

环境依赖

仅需Python 3.8+与NumPy,无需其他第三方库。若需可视化可安装Matplotlib(本案例不强制)。

关键完整代码

import numpy as np

def extract_time_features(signal, fs):
    """提取时域统计特征"""
    n = len(signal)
    mean = np.mean(signal)
    std = np.std(signal)
    rms = np.sqrt(np.mean(signal**2))
    peak = np.max(np.abs(signal))
    peak_to_peak = np.max(signal) - np.min(signal)
    # 过零率:信号穿越零点的次数 / 样本数
    zero_crossings = np.sum(np.diff(np.signbit(signal)) != 0)
    zcr = zero_crossings / n
    return {
        'mean': mean,
        'std': std,
        'rms': rms,
        'peak': peak,
        'peak_to_peak': peak_to_peak,
        'zcr': zcr
    }

def extract_freq_features(signal, fs):
    """提取频域特征:主频幅值、频谱质心"""
    n = len(signal)
    # 去除直流分量后加窗,减少频谱泄漏
    windowed = signal - np.mean(signal)
    windowed = windowed * np.hanning(n)
    spectrum = np.fft.rfft(windowed, n)
    freqs = np.fft.rfftfreq(n, d=1/fs)
    magnitudes = np.abs(spectrum)
    # 忽略直流分量(freq=0)
    nonzero = freqs > 0
    freqs_nz = freqs[nonzero]
    mags_nz = magnitudes[nonzero]
    if len(mags_nz) == 0:
        return {'dominant_freq': 0.0, 'dominant_mag': 0.0, 'spectral_centroid': 0.0}
    # 主频及其幅值
    idx = np.argmax(mags_nz)
    dominant_freq = freqs_nz[idx]
    dominant_mag = mags_nz[idx]
    # 频谱质心(幅值加权平均频率)
    centroid = np.sum(freqs_nz * mags_nz) / np.sum(mags_nz)
    return {
        'dominant_freq': dominant_freq,
        'dominant_mag': dominant_mag,
        'spectral_centroid': centroid
    }

def extract_all_features(signal, fs):
    """组合时域与频域特征,返回扁平字典"""
    features = {}
    features.update(extract_time_features(signal, fs))
    features.update(extract_freq_features(signal, fs))
    return features

# ===== 最小可运行示例 =====
if __name__ == '__main__':
    # 生成模拟信号:2Hz正弦 + 0.5Hz低频漂移 + 噪声
    fs = 100  # 采样率100Hz
    t = np.arange(0, 2, 1/fs)  # 2秒数据
    np.random.seed(42)
    signal = 1.5*np.sin(2*np.pi*2*t) + 0.3*np.sin(2*np.pi*0.5*t) + 0.1*np.random.randn(len(t))
    
    feats = extract_all_features(signal, fs)
    for k, v in feats.items():
        print(f"{k}: {v:.4f}")

运行方式

python feature_engineering.py

验证方法与判定标准

运行后观察输出特征值,验证逻辑如下:

  • 主频验证:信号主成分为2Hz正弦,dominant_freq应接近2.0Hz(因加窗与噪声影响,允许±0.2Hz偏差);
  • 均值验证:信号无直流偏置,mean应接近0(允许±0.05偏差);
  • RMS验证:2Hz分量幅值1.5,其RMS理论值为1.5/√2≈1.061,叠加噪声后rms应接近1.0~1.2范围;
  • 过零率验证:2Hz信号每秒穿越零点4次,2秒共约8次,zcr应接近8/200=0.04(噪声会使其略增,允许±0.02偏差);
  • 频谱质心验证:能量集中在2Hz附近,spectral_centroid应落在1.5~3.0Hz区间。

若上述数值均在合理范围内,说明特征提取逻辑正确。将signal替换为实际传感器采集数据(一维NumPy数组)即可直接复用extract_all_features函数。

常见问题

  • 输入信号含直流偏置:频域特征提取前已自动去除均值,但时域mean特征会保留该偏置,属预期行为;
  • 采样率不匹配:fs必须与实际采样率一致,否则dominant_freq和spectral_centroid会系统性偏移;
  • 信号长度过短:建议至少包含5个以上完整周期,否则频域分辨率不足,主频估计误差增大。