一、经典信号生成方法:正弦波、方波、三角波与噪声

各位同学,欢迎来到《信号生成与机器学习融合实战》的第一章。

信号生成,说白了就是给机器“喂”数据。你想想看,没有数据,再牛的模型也是白搭。我刚开始做信号处理那会儿,总觉得生成几个波形很简单,不就是调几个参数嘛。结果呢?有一次项目里,就因为噪声类型选错了,模型训练出来完全没法用。嗯,从那以后,我对信号生成这件事就再也不敢马虎了。

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 方波与三角波:从“平滑”到“棱角”

方波和三角波,是正弦波的“变种”。方波在高低电平之间瞬间切换,像数字电路里的时钟信号。三角波则像锯齿,但上升和下降是对称的。

生成方波,我常用两种方法:

  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 知识体系总览

下面这张图,是我自己总结的信号生成知识框架。你可以把它当作一张“地图”,随时回来查阅。

信号生成方法知识体系 周期信号 非周期信号 噪声信号 正弦波 余弦波 方波 三角波 脉冲信号 阶跃信号 高斯白噪声 有色噪声(粉红/布朗/蓝) 生成方法: • 傅里叶级数法 • 符号函数法 生成方法: • 阶跃函数 • 脉冲函数 生成方法: • 随机数生成 • 滤波法(白→有色) 核心思想:所有信号都可以由基本波形组合而成 采样率 ≥ 2倍最高频率(奈奎斯特定理)

1.5 本章小结

这一章,我们走过了信号生成的基础:

  • 正弦波和余弦波——最纯粹的振动
  • 方波和三角波——从平滑到棱角的变形
  • 高斯白噪声和有色噪声——模拟真实世界的“杂质”

记住,生成信号只是第一步。后面我们会把这些信号喂给机器学习模型,看看它们能学到什么。嗯,那才是真正有意思的地方。

课后练习: 试着用本章的代码,生成一个频率为 10 Hz、振幅为 2、相位为 π/4 的正弦波,然后叠加一个粉红噪声。看看波形变成什么样了?

专注资料整理