嵌入式面试真题第 07 题:电源纹波影响 ADC 电量采样的软件滤波
1 | flowchart LR |
问题
硬件工程师告诉你,当前版图的电源纹波太大,可能会影响 ADC 电池电量采样精度。作为软件工程师,在硬件已经无法改版的前提下,你能通过哪些纯软件或数字滤波手段,最大限度地剔除这部分周期性电源噪声?
除了列出滤波算法,还需要说明:如何判断噪声来自 ADC 参考电压、模拟输入、电源地弹、DC-DC/PWM 开关、功放负载还是射频发射;采样时刻和采样率应如何选择;过采样、中值、均值、低通和陷波分别适合什么场景;如何处理负载引起的真实电压跌落;如何避免电量百分比抖动;以及如何在 MCU、DMA 和 RTOS 环境下落地实现并验证效果。
回答
结论:软件不能把已经污染、削顶或混叠后的 ADC 信号恢复成“真实无噪声电压”,也不能替代缺失的去耦、电源隔离、参考源和模拟前端设计。但软件可以把问题拆成“采样避噪、参考修正、稳健去异常、周期噪声抑制、负载状态补偿、慢变量估计、显示状态机”七层处理,从而显著降低周期纹波、偶发尖峰和负载瞬态对电量估算的影响。
最有效的方案通常不是单独使用某个滤波器,而是组合链路:先用定时器或 PWM 事件做同步采样,在开关噪声较小的相位窗口内通过 ADC+DMA 采集 16~64 点;再做饱和检查、去极值或中值/Hampel 异常点剔除;随后进行分组平均或一阶 IIR 低通;如果确认存在稳定且落入采样带宽内的固定频率纹波,再增加窄带陷波;同时采内部 Vref/Bandgap 修正 VDDA 波动;最后根据功放、无线发射、背光、马达、充电和温度状态做负载感知补偿,并通过充放电状态机、滞回、限速和时间确认更新电量百分比。
电池电量是秒级到分钟级变化的慢变量,因此不应让单次 ADC 原始值直接驱动 UI。软件真正需要估计的是“在已知温度和负载条件下的电池稳态电压或等效开路电压”,而不是某一个瞬间的端电压。
总体处理架构
1 | flowchart TD |
这一架构刻意把“原始采样值”“滤波电压”“补偿后电压”“最终 SOC”分成不同层级。工程上必须分别保存和观测这些量,否则当电量显示异常时,很难判断是 ADC 采样、滤波参数、参考电压、负载补偿还是 SOC 曲线的问题。
建议至少保留以下诊断量:
| 诊断量 | 含义 | 主要用途 |
|---|---|---|
adc_raw_min/max/mean |
一个采样窗口内的原始统计值 | 判断饱和、尖峰、纹波幅度和 ADC 稳定性。 |
vdda_mv |
通过内部参考估算的模拟电源电压 | 判断 ADC 参考是否跟随电源波动。 |
vbat_instant_mv |
窗口稳健统计后的瞬时电池电压 | 判断短时负载和周期噪声。 |
vbat_filtered_mv |
低通后的慢变量 | 作为负载补偿输入或 UI 基础值。 |
vbat_ocv_est_mv |
估算的等效开路电压 | 映射 SOC。 |
load_state |
当前负载状态 | 解释瞬态压降并选择不同参数。 |
filter_reject_count |
被判定为异常点的数量 | 监测噪声恶化、算法过严或采样窗口不合理。 |
soc_display |
最终显示电量 | 验证状态机、滞回和限速。 |
先判断“纹波”到底进入了哪一条路径
在写滤波器之前,必须先建立噪声路径模型。示波器上看到电源有纹波,并不等价于 ADC 结果中的误差只来自电源引脚。对于 MCU 内置 SAR ADC,常见耦合路径至少包括模拟输入、参考电压、模拟电源、地、电阻分压网络、采样保持电容充电、数字开关噪声和负载导致的真实电池端电压变化。
1 | flowchart LR |
可以把一次采样近似写成:
1 | x[n] = Vbat_true[n] |
其中:
Vbat_true[n]是真实电池端电压,它本身会随 SOC、温度、充放电电流和电芯内阻变化。eripple[n]是开关电源、PWM、功放或数字活动形成的周期干扰。eload[n]是真实负载电流引起的端电压跌落,不应简单当成噪声全部滤掉。eref[n]是 ADC 参考电压或 VDDA 波动导致的比例误差。espike[n]是开关边沿、射频发射、ESD、继电器或 GPIO 群切换产生的孤立尖峰。equant[n]是量化噪声及转换器本底噪声。eoffset[n]是偏置、增益、温漂、分压电阻误差和校准残差。
这几类误差的统计特征不同,不能只靠“加一个平均滤波”统一处理。
推荐的定位顺序
- 同时记录 ADC 原始码、内部 Vref 码、负载状态和触发相位。
- 用示波器分别测量电池分压输入、VDDA/VREF、ADC 地附近和主要开关节点。
- 对 ADC 原始序列做时域波形和频谱分析,确认主频、谐波、尖峰密度和低频包络。
- 改变采样率或采样相位,观察干扰频率是否发生混叠或幅值变化。
- 分别关闭 PWM、功放、无线发射、背光和充电,做 A/B 对比。
- 用已知稳定电压源替代电池分压输入,判断问题位于输入源还是 ADC 参考/电源路径。
- 对比固定相位采样、整周期均匀采样和自由运行采样的结果。
典型现象与判断
| 现象 | 更可能的原因 | 软件侧验证办法 |
|---|---|---|
| ADC 原始值与内部 Vref 码反向同步波动 | VDDA/VREF 变化导致比例误差 | 同时采 Vref 并换算 VDDA,修正前后比较。 |
| ADC 波形与 PWM 周期严格同步 | PWM/DC-DC 周期耦合 | 改触发相位或关 PWM 对比。 |
| 只在 PA 大音量、RF 发射或马达启动时下跌 | 真实负载压降叠加地弹 | 结合负载状态和电流数据判断恢复时间。 |
| 少量极端高低码、其余样本稳定 | 开关尖峰、通道切换或 ADC 采样未稳定 | 中值/Hampel 有效;延长采样时间并丢弃首样本。 |
| 改变采样率后低频拍频发生变化 | 高频纹波混叠到低频 | 重新选择采样率、模拟 RC 或同步触发。 |
| 不同 ADC 通道之间互相串扰 | 高源阻抗、采样保持电容未充分充电 | 增大采样时间,通道切换后丢弃首样本。 |
采样策略比滤波器更优先
周期性噪声最有效的处理往往发生在采样之前。若采样时刻总落在开关边沿附近,后端再复杂的滤波器也只能处理已经被污染的数据;如果采样频率与纹波频率形成不利的相位关系,还可能把高频纹波混叠为难以滤除的低频漂移。
同步采样:在“安静相位”取样
如果噪声源是可控的 PWM、DC-DC、音频 Class-D、LED 调光或系统周期任务,应尽量使用硬件事件链:定时器/PWM 比较事件触发 ADC,ADC 通过 DMA 搬运结果,CPU 只处理完成后的数据窗口。这样可减小 RTOS 调度和中断延迟造成的采样相位抖动。
1 | sequenceDiagram |
同步采样有两种目标,不能混淆:
- 若目标是获得“每个开关周期中噪声最小的瞬时值”,应固定在安静相位采样。
- 若目标是获得“一个完整纹波周期的平均电压”,应在一个或多个完整周期内均匀布点并平均。
固定相位采样并不一定等于平均电池电压。例如纹波是近似三角波,固定在谷值附近会形成稳定但有偏的结果。因此需要先定义测量目标,再选择相位。
整周期相干平均
已知纹波频率 fripple 时,可以在整数个纹波周期内采样并平均。理想情况下,周期干扰在完整周期上的正负分量相互抵消。设每周期采 N 点,累计 M 个完整周期,则窗口长度应满足:
1 | Fs = N * fripple |
工程上允许存在频率误差,但窗口越长,对频率漂移越敏感。若 DC-DC 采用 PFM、跳脉冲或扩频模式,纹波不再是严格稳定的单频信号,此时固定周期相干平均效果会下降,应改用相位窗口、稳健统计和宽带低通组合。
避免混叠
若实际纹波频率为 fripple,采样率为 Fs,则采样后可能观察到的混叠频率近似为:
1 | falias = |fripple - k * Fs| |
其中 k 取使 falias 落入 [0, Fs/2] 的整数。一个 500 kHz 的开关纹波,可能因为低速采样而表现成几赫兹甚至更低的“电池缓慢波动”。这种伪低频一旦与 SOC 变化频段重叠,就很难靠普通低通区分。
因此应优先采用以下手段:
- 用 PWM/定时器硬件同步,避免随机相位混叠。
- 提高原始采样率,使纹波频率和谐波可被识别,再数字低通和抽取。
- 让采样窗口覆盖整数周期。
- 如果硬件已有输入 RC,确认其截止频率与采样策略匹配。
- 不要让低速周期采样恰好锁定在纹波的固定坏相位。
ADC 采样时间与高阻分压
电池检测常用较大的分压电阻以降低静态功耗,这会提高 ADC 输入源阻抗。SAR ADC 内部采样保持电容需要在有限采样时间内通过外部等效电阻充电;若采样时间过短,会出现增益误差、通道串扰和首样本偏差。软件可采取:
- 选择更长的 ADC sample time。
- 唤醒分压或切换通道后等待 RC 稳定。
- 通道切换后丢弃第一次转换。
- 连续采两次或多次,使用后续样本。
- 先采低阻参考通道再采高阻通道时,检查残余电荷影响。
这类误差不是数字滤波能完全消除的;滤波只能让偏差更稳定,不能自动消除系统性偏差。
各类滤波算法如何选
过采样与平均
过采样是最基础的方法:在电池电压变化远慢于 ADC 采样速率时,短时间内采集多点并求平均,可以降低零均值、近似不相关噪声的方差。对于独立同分布噪声,N 点平均后的标准差理论上约降为原来的 1/sqrt(N)。
1 | y[k] = (x[kN] + x[kN+1] + ... + x[kN+N-1]) / N |
但必须注意:
- 固定相位的确定性纹波不会因为重复采相同相位而消失。
- 相关噪声、低频漂移和参考电压变化不会按
1/sqrt(N)理想下降。 - 增加采样次数提高的是噪声统计意义上的有效分辨率,不会自动修正增益、偏置、参考误差和电阻容差。
- 当输入噪声小到不足以跨越 ADC 量化码时,简单过采样也未必增加有效位数。
经典过采样理论常用“每增加 1 bit 有效分辨率,需要约 4 倍采样数”的近似,即增加 m bit 需要约 4^m 个样本。这一结论有前提:噪声应足以打散量化误差、样本之间不能高度相关,且后续要进行低通和抽取。不能把它当成所有 MCU ADC 都能无条件实现的精度承诺。
去最大最小值平均
对 16~64 点短窗口,去除若干最大值和最小值后求平均,是 MCU 上成本低、效果稳定的工程方法。它对少量正负尖峰比普通均值更稳健,又比完整排序的中值更能保留多点平均带来的降噪能力。
例如 32 点窗口可去除最大 2 点和最小 2 点,再对剩余 28 点求平均:
1 | trimmed_mean = sum(sorted(x)[2:30]) / 28 |
实现时不一定需要全排序。若只去一个最大和一个最小,只需单次遍历统计 sum/min/max;若去多个极值,可使用小顶堆、大顶堆,或在样本数较小的情况下直接插入排序。
适用场景:
- 窗口内大多数样本正常,仅少量毛刺。
- MCU 算力有限,不希望运行复杂滤波。
- 既希望抑制尖峰,又希望降低随机噪声。
不适用场景:
- 纹波占据整个窗口且具有稳定周期。
- 异常点比例过高。
- 真实负载突变导致整段数据都发生跃迁。
中值滤波
中值滤波将窗口排序后取中间值:
1 | y[n] = median{x[n-k], ..., x[n], ..., x[n+k]} |
它对孤立脉冲和毛刺非常有效,边沿保持能力也优于均值滤波。常用窗口为 3、5、7 或 9 点。窗口过大将增加延迟,并把真实的电压阶跃压平。
推荐用法不是“只做大窗口中值”,而是先用 3 点或 5 点中值去尖峰,再进入均值或一阶 IIR:
1 | Raw -> Median(3/5) -> Mean/Trimmed Mean -> IIR |
Hampel 异常点检测
Hampel 滤波比简单中值更适合需要保留原值并输出异常标志的场景。它使用窗口中位数 m 和中位数绝对偏差 MAD:
1 | MAD = median(|xi - m|) |
当 |x[n] - m| > threshold 时,把该点标为异常,可替换成中位数或直接丢弃。系数 1.4826 用于在高斯分布假设下把 MAD 标度到标准差量级。嵌入式实现中不必追求统计学形式完全精确,可以固定窗口和阈值,并对 MAD=0 做保护。
Hampel 的优势是能输出 reject_count,便于诊断噪声是否突然恶化,而不是无声地把所有异常都平滑掉。
滑动平均与分组平均
长度为 N 的滑动平均:
1 | y[n] = (x[n] + x[n-1] + ... + x[n-N+1]) / N |
可用运行和优化:
1 | sum[n] = sum[n-1] + x[n] - x[n-N] |
优点是实现简单、直流增益为 1、对高频噪声有明确抑制。缺点是需要保存窗口、产生约 (N-1)/2 样本群延迟,并在特定频率上形成梳状零点。若纹波频率恰好与窗口长度不匹配,抑制可能不稳定。
对电池电量采样,常见做法是“快速窗口分组平均 + 慢速 IIR”,而不是一个极大的滑动平均窗口:快速窗口负责原始噪声,慢速 IIR 负责 UI 稳定性。这样参数更容易解释和调试。
一阶 IIR 低通
一阶 IIR 是电量估计中最实用的滤波器之一:
1 | y[n] = y[n-1] + alpha * (x[n] - y[n-1]) |
其中 alpha 越小,滤波越平滑、响应越慢。若采样周期为 Ts,希望近似时间常数为 tau,可取:
1 | alpha = 1 - exp(-Ts / tau) |
当 Ts << tau 时,可近似为:
1 | alpha ≈ Ts / tau |
例如每 100 ms 得到一个稳健电压值,希望时间常数约 5 s,则 alpha ≈ 0.02。固定点实现可把 alpha 表示为 Q15 或选成 1/2^k:
1 | y += (x - y) >> k |
一阶 IIR 适合电池这种慢变量,但应根据状态动态调整时间常数:
| 状态 | 建议时间常数 | 原因 |
|---|---|---|
| 正常放电、轻载 | 5~20 s | 抑制慢纹波和 UI 抖动。 |
| 重载瞬态 | 10~60 s 或暂缓更新 | 避免瞬时压降被误认为 SOC 快速下降。 |
| 充电开始/结束 | 2~10 s 并配合状态确认 | 需要响应状态变化,但避免充电纹波。 |
| 低电告警 | 可使用独立快速支路 | 不能因 UI 慢滤波而延误保护。 |
| 休眠唤醒 | 先快速重建,再切慢滤波 | 避免沿用过期历史值。 |
保护阈值和 UI 电量应使用不同滤波链。低压关机、安全保护需要较快、可证明的响应;UI 则允许更慢、更平滑。
FIR 低通
FIR 具有线性相位和天然稳定性,适合采样率固定、频率指标明确、算力允许的系统。可以用窗函数法设计低通,在高采样率下抑制开关纹波后再抽取。但对普通电池电量显示,FIR 往往不是首选,因为:
- 需要较多系数和乘加运算。
- 截止频率很低时,阶数可能较高。
- 对频率漂移的窄带纹波不一定比同步采样更高效。
- UI 电量并不要求严格线性相位。
FIR 更适合作为“高采样率 ADC 数据的抗混叠数字滤波 + 抽取”模块,而不是单纯为显示平滑堆叠大量 tap。
固定频率陷波
当频谱确认存在稳定的窄带周期干扰,并且该干扰未被混叠成不可辨识的低频时,可以使用二阶 IIR 陷波器。常见传递函数为:
1 | 1 - 2*cos(w0)*z^-1 + z^-2 |
其中:
1 | w0 = 2*pi*f0/Fs |
零点放在单位圆的 ±w0 处形成陷波,极点半径 r 控制带宽;r 越接近 1,陷波越窄,但定点量化和频率漂移敏感度也越高。对应差分方程为:
1 | y[n] = x[n] |
实际实现时通常需要做直流增益归一化、系数量化和内部累加位宽保护。
陷波适用条件:
- 纹波主频稳定,采样率稳定。
- 频率落在可数字处理的带宽内。
- 频谱中有明显窄峰。
- 不希望用很低的低通截止频率牺牲响应速度。
陷波不适用条件:
- DC-DC 使用 PFM、跳脉冲或扩频,频率大幅漂移。
- 干扰是宽带噪声或随机尖峰。
- 采样率太低,纹波已混叠到接近直流。
- 真实电池变化和干扰频率重叠。
不要仅凭“硬件说有 500 kHz 纹波”就在 10 Hz 的采样序列上设计 500 kHz 陷波。数字滤波器只能处理采样后实际存在于离散频谱中的频率;若 500 kHz 已混叠为 1 Hz,必须围绕 1 Hz 现象重新分析,但此时也可能误伤真实电池变化。
自适应陷波
若纹波频率缓慢漂移,可用频率估计加自适应陷波,例如基于 Goertzel/短时 FFT 估计主峰,再更新 w0。但在低成本 MCU 的电量采样里,自适应陷波通常不是第一选择,原因是参数稳定性、误锁定和验证成本较高。优先顺序应是:
- 硬件同步触发。
- 整周期平均或相位窗口。
- 稳健统计和低通。
- 固定陷波。
- 最后才考虑自适应陷波。
内部 Vref/Bandgap 修正
如果 ADC 参考电压来自 VDDA,而 VDDA 本身被 DC-DC 纹波或负载拉动,同一个电池分压输入会得到不同 ADC 码。很多 MCU 提供内部 bandgap/Vref 通道以及出厂校准值,可通过采内部参考估算当前 VDDA,再修正外部通道。
通用关系为:
1 | ADC_code = Vin / Vref_actual * ADC_full_scale |
若内部参考名义电压为 Vbg,其 ADC 码为 Code_bg:
1 | Vref_actual ≈ Vbg * ADC_full_scale / Code_bg |
电池经分压比 Kdiv = (Rtop + Rbottom) / Rbottom 后:
1 | Vbat ≈ Code_bat / ADC_full_scale * Vref_actual * Kdiv |
对带出厂校准常量的 MCU,应使用芯片参考手册给出的公式和校准电压条件,不要把某一系列 MCU 的常量直接复制到另一系列。还要注意:内部参考本身有容差、温漂和启动稳定时间,它适合修正 VDDA 的相对变化,但不等于高精度外部基准。
推荐采样顺序:
- 同一时间窗口内采电池通道和 Vref 通道。
- Vref 通道启用后等待稳定。
- 对 Vref 也做稳健平均,但不要过度延迟,使其无法跟踪同一窗口的 VDDA 波动。
- 对
Code_bg设置合理范围,防止除零或异常值造成电压计算爆炸。 - 使用 64 位中间量避免整数乘法溢出。
如果 ADC 输入和参考电压受到完全相同的比例变化,某些比例式测量可能天然抵消;但电池分压通常是绝对电压测量,仍需明确参考电压来源和公式。
负载感知补偿:不要把真实压降当噪声
播放大音量、低频增强、马达启动、背光升亮、蓝牙/Wi-Fi 发射或 CPU 突发运算时,电池端电压会因为电芯内阻、连接器、电源路径阻抗和保护器件压降而真实下降。简单低通只能把这一下降“延迟显示”,却不能判断它是 SOC 下降还是负载造成的暂态。
最简单的电池等效模型可写成:
1 | Vterminal = OCV(SOC, T) - Iload * R0 - Vrc |
其中:
OCV是与 SOC 和温度相关的开路电压。Iload * R0是瞬时欧姆压降。Vrc是电化学极化形成的慢恢复分量。
若有电流传感器,可做一阶补偿:
1 | OCV_est = Vterminal + Iload * R0_est |
R0_est 可随温度、SOC 和老化程度查表。若没有电流传感器,可以使用负载状态估算:
1 | Vcomp = Vfiltered + DeltaV(load_state, volume, tx_power, temperature) |
例如在功放大音量或 RF 发射窗口内,暂缓 UI 电量下降;负载结束后等待恢复窗口,再使用恢复后的电压更新 SOC。这里的“暂缓”不能影响真正的欠压保护,保护路径仍需依据更快的端电压和持续时间判定。
推荐的双路径设计
1 | flowchart LR |
快速保护路径关注“端电压是否持续危险”;慢速 UI 路径关注“用户可理解的剩余电量”。两者不能共用同一组极慢滤波参数。
电量百分比状态机
从电压映射到电量百分比时,必须引入状态机、滞回和更新限速。否则即使电压只波动几十毫伏,也可能在 SOC 曲线陡峭区造成多个百分点跳变。
1 | stateDiagram-v2 |
状态机需要解决的问题
- 充电时电压抬升,不能直接按放电 OCV 曲线映射。
- 大负载下电压瞬降,不能立即降低大量电量。
- 负载解除后电压回弹,不能让电量反复上涨。
- 满电和低电需要持续时间确认,避免单点触发。
- UI 百分比应限制每次变化幅度和最短更新时间。
- 充电状态下通常只允许电量不下降,放电状态下通常只允许电量不无故上升,但需为重估和校准留出受控例外。
- 休眠很久后重新唤醒,应允许根据稳定电压重新锚定,而不是死守旧值。
滞回示例
假设 20% 对应某个补偿电压阈值 V20,可设置:
1 | 从 21% 降到 20%:V <= V20_down 持续 Tdown |
同一阈值上下使用不同边界,避免在边界附近来回跳变。
更新限速示例
- 正常放电:每 30~120 s 最多下降 1%。
- 充电:根据充电阶段每 10~60 s 最多上升 1%。
- 重载期间:冻结 UI 或只允许非常慢的下降。
- 低压持续:允许快速下降并触发告警,但必须与保护路径一致。
- 开机初始化:收集数秒稳定数据后一次性设置初值。
这些数值不能直接照搬,应由电池容量、产品功耗、用户体验和安全策略共同确定。
推荐的组合滤波流程
面试回答可以给出一条可落地的默认链路:
1 | Timer/PWM 硬件触发 |
这条链路并不是越多级越好。每一级都应有明确目标和可观察效果;如果无法说明某一级抑制的噪声类型,就不应盲目加入。
参数如何量化
原始采样率
采样率应同时考虑:
- 纹波频率和谐波。
- ADC 转换时间和源阻抗。
- DMA 带宽与 CPU 处理预算。
- 期望的更新周期。
- 是否需要相位同步或整周期平均。
若只做 UI 电量,每秒更新 1~10 次已经足够,但原始 ADC 可以在每次更新窗口内以更高频率突发采样。例如 UI 每 100 ms 更新一次,每次由定时器在 2 ms 内采 32 点。这样既能做稳健统计,也不必长期占用 ADC。
窗口长度
窗口长度需要覆盖期望抑制的噪声,同时不能让真实状态变化延迟过大。可按以下思路设置:
1 | N_window >= Fs_raw * T_cover |
其中 T_cover 至少覆盖若干个纹波周期或一次典型干扰突发。若噪声源是 1 kHz PWM,原始采样率 16 kHz,32 点窗口覆盖 2 ms,即 2 个 PWM 周期;如果希望覆盖 8 个周期,应增加到 128 点或调整采样布局。
IIR 时间常数
时间常数应从产品允许的响应时间反推,而不是凭感觉设置。假设每 100 ms 更新一次,希望电压阶跃在约 15 s 内接近稳定,可先选择 tau=5 s,因为一阶系统约在 3*tau 后达到最终值的 95%。随后通过实测重载恢复和 UI 体验调整。
陷波半径
二阶陷波的 r 决定带宽。r 过小会形成较宽抑制带,可能影响有用信号;r 过大则对频率漂移敏感。固定点 MCU 上还要评估:
- Q 格式系数量化后极点是否仍在单位圆内。
- 内部累加器是否溢出。
- 初始状态是否导致启动瞬态。
- 采样率漂移是否使陷波中心偏移。
建议使用离线脚本生成系数和频响,再把定点系数固化到代码,并用单元测试验证稳定性。
MCU/RTOS 落地架构
1 | flowchart LR |
线程与中断职责
- 定时器/PWM:生成确定相位的硬件触发。
- ADC:按固定通道序列扫描电池、Vref、温度等通道。
- DMA:把数据写入 ping-pong 缓冲区,避免 CPU 逐样本中断。
- ADC/DMA ISR:只确认缓冲区、记录时间戳并投递事件,不执行排序、浮点计算或日志打印。
- Filter Task:做窗口统计、参考修正、陷波和低通。
- Battery Estimator:做负载/温度补偿、SOC 映射和状态机。
- UI/Power Manager:分别消费显示电量和保护状态。
数据一致性
DMA 缓冲区应避免在 CPU 处理时被覆盖。常见方案:
- 双缓冲/ping-pong。
- 半传输和全传输中断分别处理两个半区。
- ISR 只传递缓冲区索引,不复制大量数据。
- 如果处理任务可能跟不上,记录 overrun 并丢弃旧窗口,不要悄悄读取正在写入的数据。
- 原始数据、滤波状态和 SOC 状态使用明确的所有权或短临界区保护。
C 语言实现示例
下面示例展示“去一个最大值和最小值平均 + 一阶 IIR + 状态化参数”的最小实现。实际项目仍需增加 ADC 通道交织解析、Vref 校准、单位换算、异常统计和平台适配。
1 |
|
Vref 修正的整数计算框架
1 | /** |
注意:上面把内部参考简化为“已知校准电压”。具体 MCU 可能给的是某个校准供电电压下的原始 ADC 校准码,公式会不同,必须以芯片参考手册为准。
二阶陷波状态结构
1 | /** |
陷波器实现需要根据输入范围选择状态和累加器位宽。若 ADC 电压已经换算为毫伏,内部乘加建议至少使用 64 位。系数符号约定必须与设计工具一致,避免把差分方程中的 -a1*y1-a2*y2 和存储系数符号搞反。
推荐配置结构
1 | /** |
将参数集中配置有两个好处:一是便于不同硬件版本和电池型号复用;二是可以在测试报告中明确记录每次实验使用的参数,避免“改了几个魔法数但无法复现”。
如何选择一套默认方案
在没有完整频谱数据、但需要先交付一个可靠版本时,可以采用保守方案:
| 模块 | 默认建议 | 说明 |
|---|---|---|
| ADC 触发 | 定时器硬件触发 | 避免 RTOS 抖动。 |
| 原始窗口 | 32 点 | 在算力、延迟和稳健性之间折中。 |
| 异常处理 | 去 1~2 个最大/最小值,或 Median(5) | 抑制尖峰。 |
| Vref | 每个电池窗口同步采样 | 修正参考变化。 |
| 快速输出 | 每 100 ms 一次 | 供保护和诊断。 |
| UI IIR | tau=5~15 s |
具体由产品体验调参。 |
| 重载策略 | 冻结或 tau=20~60 s |
等待端电压恢复。 |
| 陷波 | 默认关闭 | 只有频谱证据充分时启用。 |
| SOC | 分充电/放电曲线,带温度和滞回 | 避免单一电压线性映射。 |
| 保护 | 独立快速路径和持续时间确认 | 不受 UI 慢滤波拖延。 |
测试与验证流程
软件滤波的效果必须通过可重复实验验证,不能只看 UI“似乎更稳定”。建议建立原始数据回放和自动化指标。
1 | flowchart TD |
基础测试工况
- 稳定直流源代替电池,系统轻载。
- 稳定直流源,PWM/DC-DC 全功能运行。
- 电池供电,功放从静音切到最大负载。
- 蓝牙/Wi-Fi 周期发射和连续发射。
- 背光、马达、LED、振动器等负载阶跃。
- 充电器插入、恒流、恒压和充满阶段。
- 高低温环境下的静置与负载测试。
- 不同 SOC 区间,尤其是电压平台区和低电陡降区。
- 休眠唤醒、ADC 重新初始化和通道切换。
- 故意改变采样率和相位,验证混叠假设。
需要记录的数据
- ADC 原始样本及时间戳。
- PWM/定时器相位或触发编号。
- 内部 Vref 原始码。
- 电池分压通道原始码。
- 负载状态、音量、RF 发射功率、CPU 频点。
- 充电状态和充电电流。
- 温度。
- 各级滤波输出。
- 最终 SOC 和 UI 百分比。
- 欠压告警、限功率和关机事件。
评价指标
| 指标 | 定义 | 用途 |
|---|---|---|
峰峰值 Vpp |
稳态窗口最大值减最小值 | 观察纹波和毛刺。 |
| 标准差/RMS | 稳态噪声统计 | 比较滤波前后随机噪声。 |
| 最大绝对误差 | 相对高精度表或稳定电源 | 验证绝对精度。 |
| 95/99 百分位误差 | 排除单点偶然性 | 评价长尾。 |
| 阶跃响应时间 | 负载或输入变化后的收敛时间 | 检查滤波是否过慢。 |
| 过冲/欠冲 | 阶跃后的最大偏离 | 检查 IIR/FIR/陷波瞬态。 |
| 异常拒绝率 | 被丢弃样本占比 | 判断阈值是否合理。 |
| UI 跳变次数 | 固定工况下百分比变化次数 | 评价用户体验。 |
| 保护触发延迟 | 欠压到保护动作的时间 | 验证安全路径。 |
建议验收条件示例
以下仅为测试模板,实际阈值应由产品定义:
- 稳定输入下,滤波后电压标准差低于指定值。
- PWM/RF/功放开启前后,补偿后稳态误差不超过目标范围。
- 单次尖峰不引起 UI 百分比变化。
- 重载持续时间较短时,UI 不出现多百分点瞬降。
- 真实电池电压持续下降时,UI 在规定时间内跟随。
- 欠压保护不因慢滤波延迟超过安全上限。
- ADC/Vref 异常时输出明确故障,不使用无效数据更新 SOC。
常见错误方案
只做大窗口平均
问题:若采样始终落在相同噪声相位,平均只会得到稳定的错误值;若负载跌落持续整个窗口,平均也无法判断它是噪声还是真实压降。
改进:先优化触发相位,再用稳健统计和负载状态解释。
盲目增加 IIR 平滑时间
问题:UI 看起来稳定,但真正的低电状态被延迟,甚至影响关机保护。
改进:保护路径和 UI 路径分离,分别定义响应时间。
看到固定开关频率就直接加陷波
问题:实际采样序列中的频率可能已经混叠,或 DC-DC 处于变频/扩频模式,固定陷波中心无效。
改进:先记录原始数据并做频谱分析,再决定是否启用陷波。
不采内部 Vref
问题:参考电压波动会被误判为输入电压波动,任何后级滤波都只能平滑比例误差。
改进:在同一窗口采 Vref 并使用芯片校准公式修正。
把负载压降全部滤掉
问题:大电流下的端电压下降是真实物理现象,可能反映电池内阻增大或供电能力不足。完全隐藏会错过低温、老化和接触不良风险。
改进:UI 可以补偿和暂缓,保护路径仍需监控真实端电压及持续时间。
直接用电压线性映射 SOC
问题:多数电池的 OCV-SOC 关系非线性,并受温度、充放电滞回、负载和老化影响。
改进:使用经过电池测试得到的分段查表,区分充电/放电曲线,必要时结合库仑计量。
在 ISR 里完成全部滤波和日志
问题:排序、浮点、FFT 或日志打印可能拉长中断,影响采样确定性并引入新的系统抖动。
改进:ISR 只投递缓冲区事件,复杂处理放在线程中。
算法选择决策表
| 噪声特征 | 首选方法 | 辅助方法 | 不建议的首选 |
|---|---|---|---|
| 与 PWM/DC-DC 相位固定 | 硬件同步采样 | 整周期平均、低通 | 仅靠大窗口平均。 |
| 少量孤立尖峰 | Median/Hampel/Trimmed Mean | 输入合法性检查 | 窄带陷波。 |
| 宽带随机噪声 | 过采样、均值、FIR/IIR | 降采样 | 只去极值。 |
| 稳定窄带纹波 | 同步采样或 Notch | 低通 | 超大中值窗口。 |
| 频率漂移/扩频纹波 | 同步窗口、宽带低通 | 自适应估计 | 过窄固定 Notch。 |
| VDDA/Vref 波动 | 内部参考修正 | 稳健平均 Vref | 仅平滑电池通道。 |
| 大负载真实压降 | 负载感知补偿/OCV 估计 | 状态机和恢复等待 | 把所有下降都当异常点。 |
| UI 百分比抖动 | 滞回、限速、状态机 | 慢 IIR | 直接显示单次 ADC。 |
频域分析与参数辨识
只看均值和峰峰值,往往无法区分随机噪声、固定纹波、拍频和负载包络。建议在开发阶段保留一条原始数据导出通道,把 ADC 原始码、Vref 码、触发计数和负载标志输出到文件,再在 PC 上进行频谱和相关性分析。
采集长度与频率分辨率
对长度为 N、采样率为 Fs 的数据做离散傅里叶变换,频率分辨率约为:
1 | Delta_f = Fs / N |
例如 Fs=8 kHz、N=8192 时,频率分辨率约为 0.9766 Hz。如果只采 128 点,虽然可以快速观察波形,但很难准确区分相邻的低频拍频。采集长度应覆盖多个干扰周期和完整的负载工作周期。
窗函数与谱泄漏
当采样窗口不包含整数个信号周期时,FFT 会出现谱泄漏。开发分析时可使用 Hann 窗等窗函数观察主频和谐波,但窗函数会改变幅值,需要做相应校正。对于算法上线,不一定需要在 MCU 上做 FFT;频谱分析主要用于确定采样相位、采样率、陷波中心和低通截止频率。
相干性与相关分析
如果可以同时记录 PWM 周期计数、RF 发射标志或音频帧边界,可计算 ADC 数据与这些控制信号的相关性。若 ADC 波动在负载事件后具有固定延迟和恢复曲线,更可能是供电路径压降;若每次都集中在开关边沿附近,更可能是耦合尖峰或地弹。
推荐做以下对比:
| 对比实验 | 观察重点 | 可得结论 |
|---|---|---|
| 固定相位采样 vs 随机相位采样 | 均值、Vpp 和频谱主峰 | 判断周期噪声是否与触发相位相关。 |
| 同步采 Vref 前后 | 修正前后的电压波动 | 判断参考电压波动占比。 |
| 轻载 vs 重载 | 阶跃幅度和恢复时间 | 估算供电路径等效内阻和 RC 特征。 |
| 不同采样率 | 低频峰位置是否移动 | 判断是否存在混叠。 |
| 关闭某个噪声源 | 对应频谱峰是否消失 | 建立噪声源与观测结果的因果关系。 |
估算等效内阻
若能获得负载阶跃前后的电流和端电压,可粗略估算瞬时等效内阻:
1 | R0_est = -(V_after - V_before) / (I_after - I_before) |
应选取负载变化后很短时间内的电压差,减少慢极化分量影响。估算结果需要按温度和 SOC 分桶,并限制异常值。该参数可用于负载补偿,也可用于判断电池老化、连接器接触不良或保护 MOS 阻抗上升。
典型场景设计实例
场景一:500 kHz DC-DC,ADC 每 100 ms 读取一次
如果软件任务每 100 ms 直接启动一次 ADC,且启动时刻受 RTOS 调度影响,500 kHz 纹波会以随机相位进入采样。单点结果可能在纹波上下沿之间跳动,若任务周期与开关控制存在弱同步,还可能形成低频拍频。
推荐改法:
- 使用定时器在每 100 ms 打开一次突发采样窗口。
- 窗口内以较高采样率采 32~64 点,或由 DC-DC/PWM 同步事件触发。
- 选择稳定平台相位,避开开关边沿和大电流切换时刻。
- 采样电池通道和内部 Vref。
- 对窗口做去极值平均,再输出一个 100 ms 级瞬时值。
- UI 支路再用 5~15 s 时间常数的一阶 IIR。
如果 ADC 和定时器资源无法达到足够高的原始采样率,应优先找“安静相位”,而不是尝试在低速数据上恢复 500 kHz 波形。
场景二:Class-D 功放引起音量相关电压波动
Class-D 或大功率音频负载的电流与音频包络相关,既有高频开关成分,也有低频真实负载变化。单纯陷波只能处理某个固定载波,无法消除音乐包络引起的端电压下降。
推荐把问题分成两层:
- 高频开关噪声:通过同步采样、短窗口稳健平均和输入带宽限制处理。
- 音频包络负载:根据音量、限幅器增益、功放使能和估计输出功率做状态补偿;负载解除后等待电压恢复再更新 SOC。
如果系统可以获得音频 RMS、峰值或功放电流估计,可用作负载模型输入。若只能知道“功放开启/关闭”,至少建立轻载、普通播放和大音量三个状态,分别设置补偿量和恢复延时。
场景三:蓝牙或 Wi-Fi 周期发射造成尖峰
无线发射常表现为短时大电流脉冲,ADC 数据中可能出现少量低值尖峰。如果尖峰占窗口样本比例很低,Median(3/5)、Hampel 或去极值平均通常有效。如果发射持续时间占窗口大部分,则应结合射频调度标志改变采样时刻,或在发射结束后的稳定窗口采样。
对射频事件不能无限期冻结电量更新。应设置最大冻结时间;若设备长时间持续发射,仍需基于滤波后的端电压和负载补偿更新 SOC,并确保保护路径持续工作。
场景四:充电纹波与电量显示上升
充电时,充电器开关纹波、恒流/恒压阶段转换和充电终止脉冲都可能影响 ADC。充电状态下端电压通常高于静置 OCV,不能直接套用放电曲线。建议:
- 独立配置充电状态滤波参数。
- 结合充电 IC 的状态脚、充电电流和终止条件。
- 充电过程中使用单独的 SOC 更新策略,必要时以库仑计量为主。
- “100%”需要满足电压、电流和持续时间条件,不能因瞬时高压直接置满。
- 充电器拔出后等待表面电荷和端电压回落,再切换回放电估算。
校准、量产与长期漂移
滤波只改善重复性,不等于校准。若分压电阻误差、ADC 增益误差和参考电压误差形成固定偏差,输出可以非常平滑但始终不准确。因此量产前应建立最少一到两点电压校准流程。
一点校准
在已知输入电压 Vcal 下测得软件计算值 Vmeas,得到比例修正:
1 | Gain = Vcal / Vmeas |
一点校准主要修正增益误差,不能同时区分偏置。
两点校准
在两个已知电压 V1、V2 下测得 M1、M2,建立线性模型:
1 | Vcorrected = A * M + B |
校准系数应带版本号、CRC 和有效范围,存储在可靠的非易失区域。启动时校验失败,应回退到默认系数并记录诊断,而不是继续使用随机数据。
温度与批次差异
电阻温漂、内部参考温漂、电芯内阻和 OCV-SOC 曲线都会随温度变化。高低温测试不应只验证滤波是否稳定,还要验证:
- 同一真实电压在不同温度下的测量偏差。
- 负载压降和恢复时间随温度的变化。
- SOC 映射是否需要温度分区。
- 低温大负载时是否会误触发低电或关机。
- 不同 PCB 批次、ADC 芯片和电阻容差下的分布。
在线健康监测
量产版本可增加轻量诊断:
- Vref 码超范围次数。
- ADC 饱和次数。
- 单窗口异常样本比例。
- 估算内阻突增。
- 负载解除后的恢复时间异常。
- 校准数据 CRC 错误。
这些指标有助于区分“算法参数不合适”和“硬件已出现故障”。当异常比例持续过高时,应降低对电量百分比的置信度,必要时显示保守值或提示维护,而不是继续输出看似平滑但不可信的结果。
工程调参顺序
建议严格按以下顺序调参,避免多个参数同时变化导致无法归因:
- 固定硬件工况,确认 ADC sample time、通道顺序和触发时刻正确。
- 确认 Vref 修正公式和校准常量正确。
- 只启用原始窗口统计,选择样本数和异常点策略。
- 做采样相位扫描,寻找稳定相位或确定整周期平均方式。
- 记录频谱,决定是否需要陷波。
- 调整快速路径的噪声与响应折中。
- 再调整 UI IIR 时间常数、滞回和限速。
- 最后加入负载补偿、温度补偿和 SOC 曲线。
- 在所有工况下回归保护延迟,防止 UI 优化影响安全动作。
- 固化参数、数据集和验收阈值,纳入持续回归。
每一步都应保留 A/B 数据。没有原始数据和参数版本记录的“滤波调优”通常不可复现,也无法判断后续硬件变更是否使旧参数失效。
面试中应如何组织回答
可以按以下顺序作答:
- 先说明边界:软件不能消除硬件纹波本身,只能降低其对采样和 SOC 估算的影响。
- 先定位噪声路径:输入、Vref、VDDA、地弹、开关耦合、量化噪声和真实负载压降。
- 优先优化采样:定时器/PWM 同步触发、安静相位、整周期平均、提高采样率并避免混叠。
- 做稳健预处理:中值、Hampel、去极值平均,剔除尖峰和异常窗口。
- 做参考修正:同步采内部 Vref/Bandgap,修正 VDDA 波动。
- 根据频谱选滤波器:宽带噪声用均值/FIR/IIR,稳定窄带纹波才用陷波。
- 区分真实负载压降:结合电流、功放、RF、温度和充电状态估算 OCV。
- UI 使用慢变量:SOC 查表、滞回、更新限速和充放电状态机。
- 保护路径独立:欠压保护不能被 UI 慢滤波拖延。
- 最后给出验证方法:记录 ADC Raw、Vref、相位和负载状态,做频谱、阶跃和 A/B 测试。
一句话概括:先通过同步采样和参考修正减少“采错”,再用稳健统计、低通或陷波减少“噪声”,最后用负载模型和状态机避免把真实瞬态误判为电量变化。
参考资料
- STMicroelectronics AN2834:How to get the best ADC accuracy in STM32 microcontrollers
- STMicroelectronics:How to improve ADC accuracy when using STM32F2xx and STM32F4xx microcontrollers
- Microchip AVR121 / AN8003:Enhancing ADC resolution by oversampling
- Microchip AN1152:Achieving Higher ADC Resolution Using Oversampling
- Texas Instruments AN-1261:Power Supply Effects on Noise Performance
- Texas Instruments:MSPM0 ADC Noise Analysis and Application
- Analog Devices:Designing Power Supplies for High Speed ADC










