锯齿波是所有波形中最"丰富"的一个——它包含所有整数次谐波(基频、2次、3次...),因此音色最为明亮和饱满。在SID芯片(Commodore 64)中,锯齿波是最常用的波形之一。
锯齿波的傅里叶级数:
f(t) = (2A/π) × [sin(ωt) - sin(2ωt)/2 + sin(3ωt)/3 - sin(4ωt)/4 + ...]
包含所有整数次谐波(1, 2, 3, 4, ...),幅度按1/n衰减。这使锯齿波成为:
| 芯片 | 是否支持 | 典型应用 |
|---|---|---|
| SID 6581 (C64) | ✅ 主要波形 | 主旋律、领奏、贝斯 |
| 2A03 (NES) | ❌ 不直接支持 | — |
| AY-3-8910 | ❌ 不支持 | — |
| SN76489 | ❌ 不支持 | — |
| DMG-CPU (GB) | ✅ 波表通道 | 可自定义波形 |
有趣的是,NES不支持锯齿波,但C64的SID芯片将锯齿波作为核心波形。这也是为什么C64音乐通常比NES音乐更"丰满"——锯齿波丰富的谐波给了SID更多的音色可能性。
锯齿波在所有波形中生成逻辑最简单——相位累加器本身就是锯齿波!
考虑32位相位累加器的行为:
这正是锯齿波的定义!线性上升→瞬间下降→重复。
我们只需要取相位的高8位作为输出,就得到了8位锯齿波。不需要任何额外的计算逻辑。
正向锯齿波从0上升到最大值再跳回0;反向锯齿波从最大值下降到0再跳回最大值。两者听感几乎相同(人耳对相位不敏感),但在某些调制应用中有区别。
| 波形 | 谐波 | 衰减速率 | 频谱宽度 | 听感 |
|---|---|---|---|---|
| 正弦波 | 仅基频 | — | 最窄 | 纯净、空洞 |
| 三角波 | 奇次 | 1/n² | 较窄 | 柔和、温暖 |
| 方波 | 奇次 | 1/n | 中等 | 明亮、锋利 |
| 锯齿波 | 全部 | 1/n | 最宽 | 明亮、丰满 |
积分 积分
锯齿波 ──────→ 方波 ──────→ 三角波
↑ │
│ 微分 │
└──────── 三角波 ←─────────┘
(微分)
正弦波 ──(硬限幅)──→ 方波
正弦波 ──(全波整流)──→ 去直流=偶次谐波方波
这些数学关系在硬件中也有对应:积分≈低通滤波,微分≈高通滤波。理解这些关系有助于设计更复杂的合成器。
既然NES没有锯齿波通道,作曲家如何获得类似效果?
波形三剑客 — 完成方波、三角波、锯齿波三大基础波形,掌握相位累加器DDS架构,理解波形频谱与听感的关系!
// sawtooth_wave.v - 锯齿波发生器
// 相位累加器直接输出,最简单的波形之一
module sawtooth_wave #(
parameter CLK_FREQ = 50000000,
parameter BIT_DEPTH = 8,
parameter PHASE_BITS = 32
)(
input wire clk,
input wire rst_n,
input wire [PHASE_BITS-1:0] freq_tune,
output wire [BIT_DEPTH-1:0] wave_out
);
reg [PHASE_BITS-1:0] phase;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
phase <= {PHASE_BITS{1'b0}};
else
phase <= phase + freq_tune;
end
// 锯齿波:直接取相位高位
// 相位从0线性增长到最大值,然后跳回0——这就是锯齿波!
assign wave_out = phase[PHASE_BITS-1 -: BIT_DEPTH];
endmodule
// 反向锯齿波(下降沿)
module reverse_sawtooth_wave #(
parameter CLK_FREQ = 50000000,
parameter BIT_DEPTH = 8,
parameter PHASE_BITS = 32
)(
input wire clk,
input wire rst_n,
input wire [PHASE_BITS-1:0] freq_tune,
output wire [BIT_DEPTH-1:0] wave_out
);
reg [PHASE_BITS-1:0] phase;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
phase <= {PHASE_BITS{1'b0}};
else
phase <= phase + freq_tune;
end
// 反向锯齿:取反即可
assign wave_out = ~phase[PHASE_BITS-1 -: BIT_DEPTH];
endmodule
✅ Verilator验证通过
锯齿波最强大的应用是作为减法合成的起始材料:
锯齿波(丰富谐波) → 滤波器(削减不需要的谐波) → 包络 → 输出
示例:
锯齿波 + 低通滤波器(截止=2kHz) → 温暖的弦乐音色
锯齿波 + 带通滤波器(中心=1kHz) → 管乐器音色
锯齿波 + 高通滤波器(截止=500Hz) → 薄的鼻音音色
虽然FPGA中的数字滤波器需要乘法器和延迟线,但这正是锯齿波+减法合成的价值——一个波形+一个滤波器就能产生无数音色。
锯齿波的瞬时跳变(从最大值跳到0)在数学上意味着无限带宽——需要无限高的采样率才能完美表示。在有限采样率下,跳变处会产生混叠(Aliasing)失真。
根据奈奎斯特定理,采样率Fs只能表示0到Fs/2的频率。锯齿波跳变产生的超过Fs/2的频率成分会"折叠"回可听范围,产生不悦耳的非谐波。
解决方案:
我们的四种基本波形与NES 2A03的通道对应关系:
| 波形 | NES通道 | NES特色 | 我们的实现 |
|---|---|---|---|
| 方波 | CH1+CH2 | 4种占空比+Sweep | DDS+可调占空比 |
| 三角波 | CH3 | 固定音量,32级阶梯 | DDS+线性映射 |
| 锯齿波 | ❌ | 不支持 | DDS直取高位 |
| 噪声 | CH4 | 2种模式+16级音量 | LFSR+7种模式 |
NES不支持锯齿波,但C64 SID支持——这是两个平台音色差异的根本原因之一。SID的锯齿波让它能模拟更多真实乐器音色。
在实际项目中,四种波形发生器应该有统一的接口:
// 统一接口
module wave_generator #(
parameter WAVE_TYPE = 0 // 0=方波,1=三角,2=锯齿,3=噪声
)(
input wire clk, rst_n,
input wire [31:0] freq_tune,
input wire [7:0] param, // 占空比/模式等
output wire [7:0] wave_out
);
这种设计让音序器可以用同一套接口驱动不同波形的通道,极大简化系统设计。
消除锯齿波混叠的高级技术:
BLIT(Band-Limited Impulse Train)的核心思想:不生成理想锯齿波再滤波,而是直接生成无混叠的锯齿波。
// BLIT锯齿波生成步骤:
// 1. 生成无混叠的脉冲序列(使用sinc函数)
// 2. 对脉冲序列积分得到锯齿波
// 3. 积分在离散域等价于累加
// 简化BLIT实现(Verilog近似)
// 使用预计算的sinc查找表代替实时计算
// 牺牲少量精度换取硬件效率
注意:在我们的课程中,我们使用简单的DDS锯齿波(有混叠),因为混叠在8位系统中是可接受的,甚至是"味道"的一部分。BLIT是高级优化,用于需要高保真度的场景。
C64 SID芯片之所以音色丰富,核心原因就是锯齿波+滤波器的组合:
| 滤波器类型 | 截止频率 | 从锯齿波产生的音色 |
|---|---|---|
| 低通 | 高 | 温暖Pad,弦乐 |
| 低通 | 中 | 木管,柔和领奏 |
| 低通 | 低 | 低沉贝斯 |
| 高通 | 中 | 鼻音,电话效果 |
| 带通 | 中 | 人声模拟,哇音 |
| 陷波 | 中 | 空心,相位效果 |
理解波形需要同时看时域和频域:
时域(波形形状):
方波: ┌──┐ ┌──┐
│ │ │ │
────┘ └────┘ └────
三角波: /\ / / \ / ────/ \/ \────
锯齿波: │ /│ /
│ / │ /
│/ │/
────/─────/────
噪声: ╪╪╪╪╪╪╪╪╪╪╪╪╪
随机、无规律
频域(谐波分布):
方波: * * * * (奇次谐波, 1/n衰减)
1 3 5 7 9 11 13
三角波: * * (奇次谐波, 1/n²衰减)
1 3 5 7 9 11 13
锯齿波: * * * * * * * * (全部谐波, 1/n衰减)
1 2 3 4 5 6 7 8
噪声: ████████████████████ (全频段能量)
连续频谱