信号基础:采样定理、量化与编码、时域与频域的基本概念

各位同学,咱们今天聊点硬核的。信号处理,说白了就是跟数据打交道。你想想看,胎压传感器里出来的那些电压、电流,都是模拟信号。但咱们的MCU只认0和1。怎么把连续的物理量变成离散的数字?这里头学问大了。

我个人习惯,讲信号基础一定从采样定理开始。为什么?因为这是模拟世界和数字世界之间的那座桥。桥没搭好,后面全白搭。

1. 采样定理:别让你的信号“说谎”

采样定理,也叫奈奎斯特-香农定理。名字挺唬人,其实道理很简单:采样频率必须大于信号最高频率的两倍

为什么会这样?我举个例子。你拿手机拍车轮转动的视频,如果快门速度太慢,拍出来的轮子看起来是倒着转的。这就是典型的“混叠”现象。在信号处理里,这叫频谱混叠

核心公式:

fs ≥ 2 × fmax

其中 fs 是采样频率,fmax 是信号最高频率。

我在项目中遇到过一件事。有次做胎压监测模块,传感器输出的信号里混着发动机的电磁干扰。我没注意,直接用10Hz采样。结果呢?干扰信号被“折叠”进了有效频带,数据全乱了。后来加了抗混叠滤波器,才把问题解决。

避坑指南:

我曾经吃过亏,现在养成了习惯:采样前先做低通滤波。把高于 fs/2 的频率成分统统滤掉。这叫抗混叠滤波,是信号处理的第一道防线。

2. 量化与编码:从连续到离散的“翻译”

采样把时间轴离散化了,但幅度还是连续的。量化,就是把连续的幅度值,映射到有限个离散的层级上。

你想想看,一个12位的ADC,能表示212 = 4096个不同的值。每个值代表一个电压区间。这个区间的大小,就是量化步长

ADC位数 量化层级 量化步长(5V参考)
8位 256 19.53 mV
10位 1024 4.88 mV
12位 4096 1.22 mV
16位 65536 76.29 μV

量化必然带来误差。这个误差叫量化噪声。我刚开始做嵌入式时,总觉得位数越高越好。后来发现,12位ADC配上一个好的参考电压源,比16位ADC配个烂电源强得多。嗯,这里要注意:量化噪声是不可避免的,但可以控制

编码就更直接了。就是把量化后的数值,用二进制表示出来。比如量化结果是1023,12位ADC编码就是 0011 1111 1111。就这么简单。

重要提醒:

编码方式不止一种。除了自然二进制,还有补码、格雷码等。在胎压数据中,我建议用自然二进制,因为解析起来最直观。格雷码适合用在旋转编码器上,咱们这里用不上。

3. 时域与频域:同一枚硬币的两面

时域,就是信号随时间变化的曲线。你打开示波器,看到的那条波形,就是时域表示。频域呢?是把信号分解成不同频率成分的集合。

说白了,时域告诉你“信号什么时候变了”,频域告诉你“信号以什么频率在变”。

我举个例子。胎压传感器输出的信号,在时域上看,是一条缓慢变化的曲线。但如果你做FFT变换到频域,你会发现:

  • 直流分量:代表静态胎压值
  • 低频成分:代表轮胎滚动时的压力波动
  • 高频成分:代表路面颠簸或传感器噪声

你看,频域分析能帮你把不同来源的信号分开。这在故障诊断中特别有用。

实用技巧:

我个人习惯,做胎压数据分析时,先看时域波形,确认数据有没有明显异常。然后做FFT,看频谱里有没有不该出现的频率成分。比如,如果出现了50Hz的工频干扰,那肯定是布线或者屏蔽出了问题。

4. 代码实战:用Python看时域和频域

光说不练假把式。咱们写段代码,看看实际效果。

import numpy as np
import matplotlib.pyplot as plt

# 生成一个模拟的胎压信号
fs = 100  # 采样频率 100Hz
t = np.arange(0, 10, 1/fs)  # 10秒数据

# 真实胎压:220 kPa,加上一些波动
pressure = 220 + 5 * np.sin(2 * np.pi * 0.5 * t)  # 0.5Hz的波动
noise = 0.5 * np.random.randn(len(t))  # 加一点噪声
signal = pressure + noise

# 时域图
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(t, signal)
plt.xlabel('时间 (秒)')
plt.ylabel('胎压 (kPa)')
plt.title('时域波形')
plt.grid(True)

# 频域图
from scipy.fft import fft, fftfreq
N = len(signal)
yf = fft(signal)
xf = fftfreq(N, 1/fs)[:N//2]

plt.subplot(1, 2, 2)
plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]))
plt.xlabel('频率 (Hz)')
plt.ylabel('幅值')
plt.title('频谱分析')
plt.grid(True)
plt.tight_layout()
plt.show()

这段代码做了三件事:生成模拟信号、画时域图、画频域图。你运行一下就能看到,时域里那条弯弯曲曲的线,在频域里变成了几个清晰的尖峰。

避坑指南:

我曾经在FFT分析时忘了加窗函数,结果频谱泄露得一塌糊涂。后来养成了习惯:做FFT之前,先对数据加汉宁窗或海明窗。这能有效减少频谱泄露,让分析结果更准确。

5. 总结:这些概念怎么用在胎压数据上?

好了,咱们把今天的内容串起来。在胎压监测系统里:

  1. 采样定理:决定了你的ADC采样率。胎压信号变化很慢,一般10-100Hz就够了。但要注意,别让高频干扰混进来。
  2. 量化与编码:决定了你的数据精度。12位ADC足够用,但要注意参考电压的稳定性。
  3. 时域与频域:时域看趋势,频域找问题。两者结合,才能全面掌握信号特征。

我个人觉得,这些基础概念就像盖房子的地基。地基打不牢,后面做再复杂的算法也是空中楼阁。你想想看,如果连采样定理都没搞明白,那后面做滤波、做特征提取,不都是瞎忙活吗?

下一章,咱们聊聊具体的滤波算法。到时候我会分享一些我在项目中踩过的坑,保证让你少走弯路。