阶段一:信号基础

📡 第01课:DSP概述

数字信号处理的基石——从模拟世界到数字世界的桥梁

1. 什么是数字信号处理?

数字信号处理(Digital Signal Processing,DSP)是利用数字计算方法对信号进行变换、滤波、分析等技术处理的一门学科。与模拟信号处理相比,DSP具有以下核心优势:

🎯 DSP vs 模拟信号处理

特性模拟处理数字处理(DSP)
精度受元件容差限制由字长决定,可精确控制
稳定性受温度/老化影响软件实现,不受环境影响
灵活性修改需改硬件修改算法即可
可重复性存在偏差完全可重复
复杂算法难以实现可实现任意复杂算法
功耗通常较低较高(高速运算)

2. DSP系统的基本架构

一个完整的DSP系统包含以下关键组件,从天线接收的模拟信号到最终数字处理结果的完整链路:

模拟信号 → 抗混叠滤波器 → ADC(模数转换) → 数字信号处理 → DAC(数模转换) → 重建滤波器 → 模拟输出

2.1 ADC转换过程详解

模数转换器(ADC)是连接模拟世界与数字世界的桥梁。其核心参数包括:

量化噪声功率:P_q = (Δ²/12),其中Δ = V_ref / 2^N

2.2 典型DSP处理器架构

DSP处理器为信号处理算法优化了以下硬件特性:

3. 信号的基本分类

在DSP中,我们按不同维度对信号进行分类:

3.1 按时间连续性分类

类型时间幅度示例
模拟信号连续连续麦克风输出
离散信号离散连续采样保持输出
数字信号离散量化(离散)ADC输出

3.2 按确定性分类

4. Verilog实现:基础信号生成器

我们从最基础的DSP硬件模块开始——一个可配置的数字信号发生器,能产生正弦波、方波、三角波和锯齿波四种基本波形。

//=============================================
// dsp_signal_generator.v
// 多波形数字信号发生器
// 功能:产生正弦波/方波/三角波/锯齿波
//=============================================
module dsp_signal_generator #(
    parameter DATA_WIDTH = 16,      // 输出数据位宽
    parameter PHASE_WIDTH = 12,     // 相位累加器位宽
    parameter LUT_DEPTH = 256       // 正弦查找表深度
)(
    input  wire                    clk,        // 系统时钟
    input  wire                    rst_n,      // 异步复位,低有效
    input  wire [1:0]              wave_sel,   // 波形选择:00=正弦 01=方波 10=三角 11=锯齿
    input  wire [PHASE_WIDTH-1:0]  freq_word,  // 频率控制字(决定输出频率)
    output reg  [DATA_WIDTH-1:0]   data_out,   // 波形输出
    output wire [PHASE_WIDTH-1:0]  phase_out   // 当前相位输出
);

    // 相位累加器
    reg [PHASE_WIDTH-1:0] phase_acc;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            phase_acc <= {PHASE_WIDTH{1'b0}};
        else
            phase_acc <= phase_acc + freq_word;
    end

    assign phase_out = phase_acc;

    // 正弦查找表(1/4周期压缩存储)
    // 完整256点正弦查找表
    reg [DATA_WIDTH-1:0] sine_lut [0:LUT_DEPTH-1];

    initial begin
        // 初始化正弦查找表
        // 正弦值范围:0 ~ 2^(DATA_WIDTH-1)-1(无符号表示)
        integer i;
        for (i = 0; i < LUT_DEPTH; i = i + 1) begin
            sine_lut[i] = $rtoi(
                (2.0**(DATA_WIDTH-1) - 1.0) * 
                $sin(2.0 * 3.14159265358979 * i / LUT_DEPTH)
                + 2.0**(DATA_WIDTH-1)
            );
        end
    end

    // 查找表地址(取相位高8位)
    wire [7:0] lut_addr = phase_acc[PHASE_WIDTH-1:PHASE_WIDTH-8];

    // 正弦波输出
    wire [DATA_WIDTH-1:0] sine_out = sine_lut[lut_addr];

    // 方波输出:相位在0~π时为高,π~2π时为低
    wire [DATA_WIDTH-1:0] square_out = phase_acc[PHASE_WIDTH-1] ? 
        {1'b0, {(DATA_WIDTH-1){1'b0}}} :              // 低电平
        {1'b0, {(DATA_WIDTH-1){1'b1}}};               // 高电平

    // 三角波输出
    // 前半周期递增,后半周期递减
    wire [DATA_WIDTH-1:0] triangle_out;
    wire [PHASE_WIDTH-2:0] phase_lower = phase_acc[PHASE_WIDTH-2:0];
    wire phase_msb = phase_acc[PHASE_WIDTH-1];

    assign triangle_out = phase_msb ? 
        ({DATA_WIDTH{1'b1}} - ({1'b0, phase_lower, {(DATA_WIDTH-PHASE_WIDTH+1){1'b0}}})) :
        ({1'b0, phase_lower, {(DATA_WIDTH-PHASE_WIDTH+1){1'b0}}});

    // 锯齿波输出:直接使用相位累加器值
    wire [DATA_WIDTH-1:0] sawtooth_out = {1'b0, phase_acc[PHASE_WIDTH-2:0], 
                                           {(DATA_WIDTH-PHASE_WIDTH+1){1'b0}}};

    // 波形选择多路器
    always @(*) begin
        case (wave_sel)
            2'b00: data_out = sine_out;
            2'b01: data_out = square_out;
            2'b10: data_out = triangle_out;
            2'b11: data_out = sawtooth_out;
        endcase
    end

endmodule

4.1 信号发生器测试台

//=============================================
// tb_signal_generator.v
// 多波形信号发生器测试台
//=============================================
`timescale 1ns/1ps

module tb_signal_generator;

    parameter DATA_WIDTH  = 16;
    parameter PHASE_WIDTH = 12;
    parameter LUT_DEPTH   = 256;
    parameter CLK_PERIOD  = 10;  // 100MHz时钟

    reg                     clk;
    reg                     rst_n;
    reg  [1:0]              wave_sel;
    reg  [PHASE_WIDTH-1:0]  freq_word;
    wire [DATA_WIDTH-1:0]   data_out;
    wire [PHASE_WIDTH-1:0]  phase_out;

    dsp_signal_generator #(
        .DATA_WIDTH(DATA_WIDTH),
        .PHASE_WIDTH(PHASE_WIDTH),
        .LUT_DEPTH(LUT_DEPTH)
    ) uut (
        .clk(clk),
        .rst_n(rst_n),
        .wave_sel(wave_sel),
        .freq_word(freq_word),
        .data_out(data_out),
        .phase_out(phase_out)
    );

    // 时钟生成
    initial clk = 0;
    always #(CLK_PERIOD/2) clk = ~clk;

    // 测试流程
    initial begin
        $dumpfile("signal_gen.vcd");
        $dumpvars(0, tb_signal_generator);

        // 初始化
        rst_n = 0;
        wave_sel = 2'b00;
        freq_word = 12'h010;  // 低频
        #100;
        rst_n = 1;

        // 测试正弦波
        wave_sel = 2'b00;
        freq_word = 12'h010;
        #50000;
        $display("正弦波测试完成,最终输出 = %d", data_out);

        // 测试方波
        wave_sel = 2'b01;
        freq_word = 12'h020;
        #50000;
        $display("方波测试完成,最终输出 = %d", data_out);

        // 测试三角波
        wave_sel = 2'b10;
        freq_word = 12'h015;
        #50000;
        $display("三角波测试完成,最终输出 = %d", data_out);

        // 测试锯齿波
        wave_sel = 2'b11;
        freq_word = 12'h008;
        #50000;
        $display("锯齿波测试完成,最终输出 = %d", data_out);

        // 频率扫描测试
        wave_sel = 2'b00;
        freq_word = 12'h001;
        #20000;
        freq_word = 12'h040;
        #20000;
        freq_word = 12'h100;
        #20000;
        $display("频率扫描测试完成");

        $display("=== 所有测试通过 ===");
        $finish;
    end

endmodule

5. Verilog实现:定点数运算模块

DSP硬件中,浮点运算代价高昂,定点数是主流选择。下面实现核心的定点数运算模块:

//=============================================
// dsp_fixed_point.v
// 定点数运算库
// 格式:Q1.(DATA_WIDTH-1) 有符号定点数
//=============================================

// 定点数乘法器
module dsp_fixed_mul #(
    parameter A_WIDTH = 16,
    parameter B_WIDTH = 16,
    parameter OUT_WIDTH = 16
)(
    input  wire signed [A_WIDTH-1:0]   a,
    input  wire signed [B_WIDTH-1:0]   b,
    output wire signed [OUT_WIDTH-1:0] result
);
    // 乘法结果位宽 = A_WIDTH + B_WIDTH
    wire signed [A_WIDTH+B_WIDTH-1:0] product = a * b;

    // Q格式调整:两个Q1.(N-1)相乘得Q2.(2N-2),需右移(N-1)位回到Q1.(N-1)
    // 同时截断到输出位宽
    assign result = product >>> (A_WIDTH - 1);
endmodule

// 定点数加法器(带饱和)
module dsp_fixed_add_sat #(
    parameter WIDTH = 16
)(
    input  wire signed [WIDTH-1:0] a,
    input  wire signed [WIDTH-1:0] b,
    output reg  signed [WIDTH-1:0] result
);
    wire signed [WIDTH:0] sum = {a[WIDTH-1], a} + {b[WIDTH-1], b};

    always @(*) begin
        if (sum > {(WIDTH+1){1'b0}} + {{WIDTH{1'b0}}, 1'b0} + 
                  (2**(WIDTH-1) - 1))
            result = {1'b0, {(WIDTH-1){1'b1}}};  // 正饱和
        else if (sum < -2**(WIDTH-1))
            result = {1'b1, {(WIDTH-1){1'b0}}};  // 负饱和
        else
            result = sum[WIDTH-1:0];
    end
endmodule

// 绝对值运算
module dsp_abs #(
    parameter WIDTH = 16
)(
    input  wire signed [WIDTH-1:0] data_in,
    output wire [WIDTH-1:0]        data_out
);
    assign data_out = data_in[WIDTH-1] ? (~data_in + 1'b1) : data_in;
endmodule

6. 信号采样与重建仿真

以下模块演示采样保持与零阶保持重建过程:

//=============================================
// dsp_sample_hold.v
// 采样保持与重建模块
//=============================================
module dsp_sample_hold #(
    parameter DATA_WIDTH = 16,
    parameter DECIM_RATE = 4       // 降采样率
)(
    input  wire                   clk,
    input  wire                   rst_n,
    input  wire signed [DATA_WIDTH-1:0] analog_in,  // 高速率输入
    output reg  signed [DATA_WIDTH-1:0] sampled_out, // 采样输出
    output reg  signed [DATA_WIDTH-1:0] zoh_out,     // 零阶保持重建输出
    output reg                     sample_valid       // 采样有效脉冲
);

    reg [$clog2(DECIM_RATE)-1:0] decim_cnt;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            decim_cnt <= 0;
            sampled_out <= 0;
            zoh_out <= 0;
            sample_valid <= 1'b0;
        end else begin
            decim_cnt <= decim_cnt + 1'b1;
            sample_valid <= 1'b0;

            if (decim_cnt == DECIM_RATE - 1) begin
                // 采样时刻
                sampled_out <= analog_in;
                zoh_out <= analog_in;      // 零阶保持
                sample_valid <= 1'b1;
                decim_cnt <= 0;
            end
            // zoh_out保持不变,实现零阶保持效果
        end
    end

endmodule

7. DSP系统性能指标

关键性能参数

指标定义典型值
采样率每秒采样点数44.1kHz~192kHz(音频)
动态范围最大/最小可表示信号比96dB(16bit)~120dB(20bit)
SFDR无杂散动态范围>80dB(优质ADC)
处理延迟输入到输出的时间差与滤波器阶数相关
MIPS每秒百万条指令取决于时钟和架构
MAC/s每秒乘加次数DSP核心性能指标

8. 练习

📝 练习1:频率计算

若系统时钟为100MHz,相位累加器位宽为32位,频率控制字为0x01000000,输出信号频率为多少?

提示:f_out = f_clk × freq_word / 2^N

📝 练习2:量化噪声

一个12位ADC,参考电压为3.3V,计算量化步长Δ和理论SNR。

📝 练习3:修改信号发生器

在 dsp_signal_generator.v 中添加频率调制(FM)功能:使用第二个相位累加器作为调制信号,叠加到频率控制字上。

📝 练习4:定点数精度分析

对于Q1.15格式的定点数,计算以下运算的精度损失:

  1. 两个Q1.15数相乘后截断回Q1.15
  2. 100次Q1.15数累加的溢出风险

🏆 成就解锁:DSP入门者

✅ 理解了模拟/数字信号处理的区别

✅ 掌握了DSP系统基本架构(ADC→处理→DAC)

✅ 实现了多波形数字信号发生器(Verilog)

✅ 掌握了定点数运算原理

✅ 理解了采样保持与零阶保持重建

11. 补充:DSP概述的进阶主题

DSP概述在进阶应用中还有以下重要主题值得深入研究:

📚 进阶研究方向

12. 与前后课程的关联

本课内容在整个DSP课程体系中处于承上启下的位置:

🔗 课程关联图

13. 设计经验总结

在实际工程中,DSP概述的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单

13. 设计经验总结

在实际工程中,DSP概述的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单

13. 设计经验总结

在实际工程中,DSP概述的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单