第11课:FM合成原理

阶段3:FM合成

FM合成是芯片音乐中最强大的音色设计技术。它最初由John Chowning在1967年发现,后来被Yamaha买断专利,推出了传奇的DX7合成器。本课深入FM合成的数学原理,理解为什么简单的频率调制能产生如此丰富的音色。

FM合成的数学基础

FM(Frequency Modulation,频率调制)的数学表达式:

y(t) = A × sin(2π × fc × t + I × sin(2π × fm × t))

其中:

📐 FM的频谱分析

FM信号的频谱由贝塞尔函数描述,包含的频率成分为:

fc ± n×fm (n = 0, 1, 2, 3, ...)

即载波频率两侧,每隔fm出现一个边带频率。每个边带的振幅由贝塞尔函数Jn(I)决定。

关键洞察:

调制指数的魔法

调制指数I是FM音色设计的核心参数:

I值边带数量音色特征模拟乐器
01(纯载波)纯正弦波音叉
0.5-12-3温暖、柔和长笛
1-34-6丰富、有表现力簧片乐器
3-56-10明亮、复杂铜管
5-1010+金属感、粗糙钟、锣
10+极多噪声化打击乐

载波比与调波比(C:M Ratio)

载波频率与调制频率的比值(C:M)决定了音色的"和谐度":

🔊 常见C:M比与音色

C:Mfm边带频率音色
1:1=fcfc, 2fc, 3fc...谐波系列,温暖
1:2=2fcfc, 3fc, 5fc...奇次谐波,类似方波
1:3=3fcfc, 4fc, 7fc...稀疏谐波
1:0.5=fc/2fc, 1.5fc, 2fc...密集谐波
1:1.414=√2×fc非谐波金属、钟声
1:π=π×fc非谐波奇异、外星感

FM与减法合成的对比

特性FM合成减法合成
原理频率调制产生泛音滤波器削减泛音
计算量需要正弦表+乘法需要滤波器
音色复杂度极高(少量算子)中等(需要多振荡器)
金属音色✅ 天然擅长❌ 较难实现
温暖音色✅ 可实现✅ 天然擅长
硬件需求ROM(正弦表)+乘法器乘法器+累加器(滤波)

Verilog中的正弦波查找表

FM合成需要正弦波(不能用方波或三角波近似)。硬件中通常用查找表实现:

  1. 用Verilator编译FM原理模块,验证不同I值下的输出波形
  2. 实验:C:M=1:1时,逐步增大I,观察波形如何从正弦波变得复杂
  3. 对比:C:M=1:1与C:M=1:2的音色差异
  4. 挑战:实现简化版贝塞尔函数近似,计算边带振幅

FM入门者 — 理解FM合成的数学原理,掌握调制指数和C:M比的概念,实现最简FM合成器!

Verilog 实现

fm_principle.v
// fm_principle.v - FM合成原理演示
// 最简FM:一个正弦载波被一个正弦调制波调制
module fm_principle #(
    parameter CLK_FREQ  = 50000000,
    parameter BIT_DEPTH = 8,
    parameter PHASE_BITS = 32,
    parameter SIN_BITS  = 10          // 正弦表地址位宽
)(
    input  wire clk,
    input  wire rst_n,
    input  wire [PHASE_BITS-1:0] carrier_freq,  // 载波频率
    input  wire [PHASE_BITS-1:0] mod_freq,       // 调制波频率
    input  wire [SIN_BITS:0] modulation_index,    // 调制指数
    output wire [BIT_DEPTH-1:0] audio_out
);
    // 正弦波查找表 (1024点 × 8位)
    reg [BIT_DEPTH-1:0] sin_table [0:1023];
    integer i;
    real angle;
    initial begin
        for (i = 0; i < 1024; i = i + 1) begin
            angle = 3.14159265 * 2.0 * i / 1024.0;
            sin_table[i] = $rtoi(127.5 + 127.5 * $sin(angle));
        end
    end
    
    // 调制波相位累加器
    reg [PHASE_BITS-1:0] mod_phase;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            mod_phase <= {PHASE_BITS{1'b0}};
        else
            mod_phase <= mod_phase + mod_freq;
    end
    
    // 读取调制波正弦值
    wire [SIN_BITS-1:0] mod_addr = mod_phase[PHASE_BITS-1 -: SIN_BITS];
    wire [BIT_DEPTH-1:0] mod_value = sin_table[mod_addr];
    
    // 调制信号 = mod_value × modulation_index
    // 将8位调制值转为有符号(-128到+127)
    wire signed [BIT_DEPTH:0] mod_signed;
    assign mod_signed = $signed({1'b0, mod_value}) - $signed(9'd128);
    
    wire signed [BIT_DEPTH+SIN_BITS:0] mod_scaled;
    assign mod_scaled = mod_signed * $signed({1'b0, modulation_index});
    
    // 载波相位累加器(含调制)
    reg [PHASE_BITS-1:0] carrier_phase;
    wire signed [PHASE_BITS:0] modulated_phase_inc;
    assign modulated_phase_inc = $signed({1'b0, carrier_freq}) + 
                                  (mod_scaled >>> (SIN_BITS-2));
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            carrier_phase <= {PHASE_BITS{1'b0}};
        else
            carrier_phase <= carrier_phase + modulated_phase_inc[PHASE_BITS-1:0];
    end
    
    // 读取载波正弦值
    wire [SIN_BITS-1:0] carrier_addr = carrier_phase[PHASE_BITS-1 -: SIN_BITS];
    assign audio_out = sin_table[carrier_addr];
endmodule

✅ Verilator验证通过

John Chowning与FM的发现

FM合成的发现是一个有趣的科学故事:

📜 FM合成的意外发现

1967年,Stanford大学的John Chowning在实验中发现了FM的音频应用:

Chowning的论文标题是《The Synthesis of Complex Audio Spectra by Means of Frequency Modulation》,至今仍是FM合成理论的权威参考。

FM与加法合成的效率对比

为什么FM合成比加法合成更高效?

目标音色加法合成所需振荡器FM合成所需算子
纯音11
简单谐波5-102
铜管音色20+2-4
钟声50+2
复杂非谐波100+3-4

FM用2个算子就能产生需要20+个正弦波叠加才能达到的音色——这是FM被声音芯片采用的核心理由:硬件成本极低。

正弦查找表的优化

1024点×8位正弦表占用1KB,但有优化空间:

🔧 利用对称性压缩

// 正弦波的四分之一对称性:
// sin(π/2 + x) = sin(π/2 - x)   → 只需0到π/2的数据
// sin(π + x) = -sin(x)           → 下半周期取反
// sin(2π - x) = -sin(x)          → 反向读表

// 256点×8位 = 256字节(1/4周期)
// 地址映射:
// 0-255:   直接读表(第一象限)
// 256-511: 反向读表(第二象限)
// 512-767: 取反+直接读表(第三象限)
// 768-1023: 取反+反向读表(第四象限)

这样只需要256字节的ROM,节省75%存储空间。代价是地址计算更复杂,但在FPGA中只是一点组合逻辑。

Chowning的FM参数映射

John Chowning原始论文中的参数映射方法:

📐 Chowning的统一参数空间

// 三个参数决定所有音色:
// 1. I(调制指数) → 泛音丰富度
// 2. fc/fm(载波调制频率比) → 谐波/非谐波
// 3. 包络随时间变化 → 音色演变

// Chowning的音色分类:
I < 1:    "简单FM" — 少量边带
1 < I < 5: "中等FM" — 丰富但可控
I > 5:    "复杂FM" — 接近噪声

fc/fm = 1: 谐波(温暖)
fc/fm = 整数 > 1: 稀疏谐波
fc/fm = 非整数: 非谐波(金属)

FM合成的历史意义

FM合成的发现改变了整个音乐产业:

FM合成的Verilog仿真技巧

验证FM模块需要观察波形和频谱变化:

🔧 FM验证testbench

// FM验证关键步骤:
// 1. 固定载波频率,扫描调制指数
// 2. 观察输出波形复杂度变化
// 3. 固定I值,改变C:M比
// 4. 观察谐波结构变化

module tb_fm_principle;
    reg clk = 0;
    reg rst_n = 0;
    reg [31:0] carrier_freq = 32'd18928;  // A4
    reg [31:0] mod_freq = 32'd18928;      // 1:1
    reg [10:0] mod_index = 11'd0;
    wire [7:0] audio_out;
    
    always #10 clk = ~clk;
    
    initial begin
        $dumpfile("fm_test.vcd");
        $dumpvars(0, tb_fm_principle);
        
        rst_n = 0; #100; rst_n = 1;
        
        // 扫描调制指数:0 → 200
        repeat(200) begin
            mod_index = mod_index + 11'd1;
            #50000;
        end
        $finish;
    end
endmodule