原始波形把特征学习交给模型,能够保留完整局部形状;人工特征先压缩数据,常能用更小模型完成任务。两种方案的优劣取决于数据规模、任务复杂度和MCU预算。
选择输入形式时,应把预处理计算也计入系统成本。一个很小的特征模型,如果每个窗口需要昂贵FFT和大量浮点统计,整体资源未必更低。
| 输入方案的成本 = MCU预处理 + 模型推理 + 缓冲区;评价时不能只看神经网络本身。 |
| 完成本篇后,你应该能够
特征是从一段波形计算出的摘要,例如均值、RMS或某个频带的能量。模型可以接收波形,也可以接收这些摘要。 |
一、先把核心关系连起来
原始波形保留最多信息
1D CNN可以从局部波形中学习边缘、周期和跨通道组合。它减少了人工特征假设,适合事件形状复杂且数据量足够的任务。代价是输入维度和中间激活通常更大。
原始输入对采样一致性要求更高。采样率、窗口长度、通道顺序或相位关系变化,都可能直接改变模型看到的局部模式。

图1:原始波形、统计特征和频谱特征的定性取舍
人工特征把领域知识写进输入
RMS、峰峰值、峭度和频带能量能够把一个窗口压缩成少量数字。类别差异恰好由这些属性表达时,全连接网络或传统分类器即可完成任务。
特征也可能删除关键信息。两个波形具有相同RMS和方差时,时序结构仍可能完全不同。特征选择必须通过分布图和消融实验验证。
表1:三类输入方案的工程差异
| 原始波形 | 信息完整、可学习局部结构 | 输入和激活较大、数据需求高 |
| 时域特征 | 输入小、解释直接 | 依赖特征假设、可能丢失时序 |
| 频域特征 | 周期与频带差异清晰 | FFT、窗函数和缓冲成本 |
二、预处理成本应在目标MCU上测量
均值和RMS计算简单,FFT、MFCC和高阶统计需要额外缓冲与运算。使用CMSIS-DSP可以提高效率,但仍要记录预处理时间、RAM和常量表Flash。
PC端特征脚本与MCU实现可能在窗函数、归一化、浮点精度和边界处理上产生差异。黄金样本逐项对比是部署前的必要测试。
Python:为同一窗口同时生成简单时域特征
|
import numpy as np def time_features(window): # window形状: [time, channels] return np.concatenate([ window.mean(axis=0), window.std(axis=0), np.sqrt(np.mean(window ** 2, axis=0)), np.ptp(window, axis=0), ]).astype(np.float32) # 与原始波形模型使用同一数据划分进行对照。 |
三、用三条平行基线做选择
可以对同一数据分别训练统计特征+Dense、频谱特征+Dense、原始波形+1D CNN。每条路线统一记录模型指标、预处理时间、推理时间、Flash和RAM。
最终方案应处于资源与效果的合理前沿。若简单特征已经达到验收要求,增加复杂模型只会扩大维护成本。
输入表示决定模型需要自己学习多少工作
原始波形保留时间顺序,卷积网络可以学习局部形状、相位关系和跨通道组合。代价是输入元素多、中间激活大、需要更多训练数据。若任务证据只体现在一个稳定统计量上,直接使用波形会增加不必要的自由度。
人工特征把领域知识提前写进输入。RMS描述能量,峰峰值描述幅值范围,过零率描述变化快慢,频带能量描述特定频段。24维特征送入小型Dense网络,通常比600点原始窗口节省RAM和计算,但窗口内部细节被压缩后无法恢复。
特征不是免费计算。平方根、除法、FFT和滤波都消耗时间与工作区。比较方案时要把特征提取和模型推理合并计时;只比较模型Invoke会错误地认为复杂特征方案更快。
三类输入表示的工程差异
| 原始波形 | 时间顺序与局部形状 | 输入和激活较大 |
| 时域特征 | 幅值、能量、分布 | 丢失细节与相位 |
| 频域特征 | 周期、谐波和频带 | FFT工作区与窗口参数 |
| 混合输入 | 兼顾领域知识和细节 | 接口与模型更复杂 |
用相同划分建立可归因的对照实验
先冻结原始记录和按设备划分的训练、验证、测试清单,再从同一窗口生成三种表示。若每条路线重新随机划分,结果差异可能来自测试样本不同。每条路线还要使用相近的训练预算和一致的指标。
第一条基线可以是少量时域特征加线性分类器,用于判断任务是否简单;第二条是频带能量加小型Dense;第三条是原始窗口加轻量1D CNN。只要简单基线达到业务目标,就没有必要为了结构复杂而增加部署风险。
错误分析要寻找表示缺失。若两个类别RMS相近但频率不同,时域能量特征难以区分;若故障是短促冲击,整窗平均频谱可能稀释事件。此时更换表示比盲目增加神经元更有针对性。
| 特征分离度的直观指标: score = |mean_class_A – mean_class_B| / (std_A + std_B) 它只用于初筛单个特征,不能替代独立测试。 |
四、落地检查
动手:比较原始波形与四个时域特征
脚本生成两类信号:一类低幅平稳振动,一类包含更高幅值和偶发冲击。它提取均值、RMS、峰峰值和过零率,再计算每个特征的简单分离度。所有数据由固定种子生成。
实验环境与输入
- Python 3标准库。
- 保存为 `compare_representations.py` 并运行。
- 模拟信号用于学习方法,不作为真实设备性能证据。
按顺序完成实验
可直接运行:从模拟窗口提取特征并计算分离度
|
import math import random import statistics random.seed(13) FS, N = 100, 100 def make_window(label, index): values = [] for n in range(N): t = n / FS amp = 0.20 if label == 0 else 0.42 value = amp * math.sin(2*math.pi*(5+label*2)*t) value += random.gauss(0, 0.025) if label == 1 and n == 20 + index % 50: value += 1.1 values.append(value) return values def features(x): mean = sum(x) / len(x) rms = math.sqrt(sum(v*v for v in x) / len(x)) p2p = max(x) – min(x) zcr = sum((a >= 0) != (b >= 0) for a, b in zip(x, x[1:]))/(len(x)-1) return [mean, rms, p2p, zcr] groups = {0: [], 1: []} for label in groups: groups[label] = [features(make_window(label, i)) for i in range(30)] names = ["mean", "rms", "peak_to_peak", "zero_cross_rate"] print("raw elements/window:", N, "feature elements/window:", len(names)) for j, name in enumerate(names): a = [row[j] for row in groups[0]] b = [row[j] for row in groups[1]] score = abs(statistics.mean(a)-statistics.mean(b)) / (statistics.pstdev(a)+statistics.pstdev(b)+1e-12) print(f"{name:16s} mean0={statistics.mean(a):.4f} " f"mean1={statistics.mean(b):.4f} separation={score:.3f}") |
先读懂代码中的关键路径
你应该观察到什么
- 特征向量从100个元素压缩到4个元素,直接减少后续Dense层输入。
- RMS或峰峰值对当前幅值与冲击差异通常具有较高分离度。
- 删除冲击或修改类别差异后,最有效特征会变化,证明特征选择依赖任务。
成功标准
失败时从哪里查起
输入表示对照实验常见问题
| 训练很好、换设备很差 | 特征包含设备偏置 | 按设备隔离并检查均值类特征 |
| 特征模型完全分不开 | 摘要丢失关键时序 | 加入频域或原始波形路线 |
| 特征路线板端更慢 | 漏算FFT或除法成本 | 端到端测预处理加推理 |
特征工程的目标是用更低资源保留任务证据。每次添加特征都应说明它描述什么物理属性。
把实验迁移到真实MCU项目
把特征函数先用常量、正弦、单脉冲做单元测试,再移植C。计算耗时必须包含滤波、平方根、除法和跨通道操作。
若选择原始波形,仍需做单位换算和最小质量检查;“端到端学习”不意味着固件可以忽略采样率、通道和饱和。
把结果再向前推进一步
收束:原始波形与人工特征没有固定胜者。用同一数据、同一划分和完整板端资源账单比较,才能选出适合项目的输入方案。
参考资料: Arm CMSIS-DSP 官方文档 TensorFlow Lite Micro 官方代码仓库
网硕互联帮助中心




评论前必须登录!
注册