一、经典信号生成方法:正弦波、方波、三角波与噪声
各位同学,欢迎来到《信号生成与机器学习融合实战》的第一章。
信号生成,说白了就是给机器“喂”数据。你想想看,没有数据,再牛的模型也是白搭。我刚开始做信号处理那会儿,总觉得生成几个波形很简单,不就是调几个参数嘛。结果呢?有一次项目里,就因为噪声类型选错了,模型训练出来完全没法用。嗯,从那以后,我对信号生成这件事就再也不敢马虎了。
1.1 正弦波与余弦波:最基础的“振动”
正弦波和余弦波,是所有周期信号的“祖宗”。它们描述的是最简单的振动——比如钟摆来回摆动,或者交流电的电压变化。
数学上,一个正弦波可以写成:
y(t) = A * sin(2 * π * f * t + φ)
其中:
- A 是振幅,决定波的高度
- f 是频率,决定波动的快慢
- φ 是相位,决定波在时间轴上的起始位置
余弦波其实就是相位偏移了 π/2 的正弦波。我个人习惯用正弦波作为基准,因为很多数学推导都是从它开始的。
实战小贴士: 在Python里生成正弦波,我一般用 NumPy 的 np.sin() 函数。采样率要设得够高,至少是信号最高频率的2倍,否则会出现“混叠”——说白了就是波形会失真。
import numpy as np
import matplotlib.pyplot as plt
# 参数设置
fs = 1000 # 采样率 1000 Hz
f = 5 # 信号频率 5 Hz
t = np.arange(0, 1, 1/fs) # 时间向量
A = 1.0 # 振幅
phi = 0 # 相位
# 生成正弦波
y_sin = A * np.sin(2 * np.pi * f * t + phi)
y_cos = A * np.cos(2 * np.pi * f * t + phi)
plt.plot(t, y_sin, label='正弦波')
plt.plot(t, y_cos, label='余弦波')
plt.legend()
plt.show()
1.2 方波与三角波:从“平滑”到“棱角”
方波和三角波,是正弦波的“变种”。方波在高低电平之间瞬间切换,像数字电路里的时钟信号。三角波则像锯齿,但上升和下降是对称的。
生成方波,我常用两种方法:
- 傅里叶级数法: 用无数个正弦波叠加。理论上,叠加的谐波越多,波形越接近理想方波。
- 符号函数法: 直接判断正弦波的正负,简单粗暴。
我的经验: 傅里叶级数法生成的方波,边缘会有“吉布斯现象”——就是过冲和振铃。如果你需要干净的方波,建议用符号函数法。我曾经在音频合成项目里吃过这个亏,听起来总有“滋滋”的杂音。
# 用符号函数生成方波
y_square = np.sign(np.sin(2 * np.pi * f * t))
# 三角波:对锯齿波取绝对值
y_sawtooth = 2 * (t * f - np.floor(t * f + 0.5))
y_triangle = 2 * np.abs(y_sawtooth) - 1
plt.plot(t, y_square, label='方波')
plt.plot(t, y_triangle, label='三角波')
plt.legend()
plt.show()
1.3 高斯白噪声与有色噪声:给信号加点“料”
真实世界里的信号,没有一个是干净的。噪声无处不在——传感器热噪声、量化误差、环境干扰……所以,学会生成噪声,是模拟真实场景的关键。
1.3.1 高斯白噪声
高斯白噪声,说白了就是每个时刻的噪声值服从正态分布,而且不同时刻之间互不相关。它的功率谱密度是平的——就像白光包含所有颜色一样。
# 生成高斯白噪声
mu = 0 # 均值
sigma = 0.1 # 标准差
noise_white = np.random.normal(mu, sigma, len(t))
plt.plot(t, noise_white)
plt.title('高斯白噪声')
plt.show()
注意: 白噪声的“白”是指功率谱平坦,不是指信号本身是白色的。我见过不少新手把“白噪声”和“高斯噪声”混为一谈。其实,白噪声可以是均匀分布、拉普拉斯分布……只要功率谱是平的就行。
1.3.2 有色噪声
有色噪声的功率谱不是平的。常见的有:
- 粉红噪声(1/f 噪声): 低频能量高,高频能量低。自然界里很常见,比如海浪声、心跳声。
- 布朗噪声(随机游走): 功率谱随频率的平方下降。听起来像沉闷的轰鸣声。
- 蓝噪声: 高频能量高,低频能量低。听起来尖锐。
生成有色噪声,我一般用“滤波法”:先产生白噪声,再用一个滤波器改变它的频谱形状。
from scipy import signal
# 生成粉红噪声:对白噪声进行低通滤波
b, a = signal.butter(2, 0.1, 'low') # 二阶巴特沃斯低通滤波器
noise_pink = signal.filtfilt(b, a, noise_white)
plt.plot(t, noise_pink)
plt.title('粉红噪声(1/f 噪声)')
plt.show()
避坑指南: 我曾经在训练一个语音识别模型时,直接用白噪声做数据增强,结果模型在真实场景下表现很差。后来换成粉红噪声,效果立马提升。为什么?因为真实环境里的噪声大多是低频的,粉红噪声更接近实际。
1.4 知识体系总览
下面这张图,是我自己总结的信号生成知识框架。你可以把它当作一张“地图”,随时回来查阅。
1.5 本章小结
这一章,我们走过了信号生成的基础:
- 正弦波和余弦波——最纯粹的振动
- 方波和三角波——从平滑到棱角的变形
- 高斯白噪声和有色噪声——模拟真实世界的“杂质”
记住,生成信号只是第一步。后面我们会把这些信号喂给机器学习模型,看看它们能学到什么。嗯,那才是真正有意思的地方。
课后练习: 试着用本章的代码,生成一个频率为 10 Hz、振幅为 2、相位为 π/4 的正弦波,然后叠加一个粉红噪声。看看波形变成什么样了?