调制解调 · 第1课

第01课:数字通信概述

📡 什么是数字通信?

数字通信是将信息源产生的模拟或数字信号转换为数字形式,经过编码、调制后在信道上传输,接收端经过解调、解码恢复原始信息的过程。与模拟通信相比,数字通信具有抗干扰能力强、可进行纠错编码、便于加密、易于集成等优势。

模拟通信 vs 数字通信

特性模拟通信数字通信
信号表示连续波形离散符号(0/1)
抗噪声噪声累积可中继再生
保密性较难加密易于加密
复用方式FDMTDM/CDM/OFDM
设备复杂度较低较高(但可集成)
典型应用传统FM广播5G/WiFi/蓝牙

🏗️ 数字通信系统模型

一个完整的数字通信系统包含以下关键模块:

信源 → 信源编码 → 信道编码 → 调制 → 信道 → 解调 → 信道解码 → 信源解码 → 信宿

各模块功能详解

信源编码(Source Coding):压缩冗余,提高有效性。如Huffman编码、LZ77压缩。

信道编码(Channel Coding):增加冗余,提高可靠性。如汉明码、LDPC码、Polar码。

调制(Modulation):将基带信号搬移到载波频率,适配信道传输特性。

信道(Channel):信号传输的媒介,引入噪声、衰落和干扰。

解调(Demodulation):从接收信号中提取基带信息。

解码(Decoding):纠正传输错误,恢复原始数据。

📊 关键性能指标

1. 比特率与符号率

R_b = R_s × log₂(M)

其中 R_b 为比特率(bps),R_s 为符号率(Baud),M 为调制阶数。例如QPSK(M=4)中,每个符号携带2比特。

2. 误码率(BER)

BER = 错误比特数 / 总传输比特数

数字通信系统的核心质量指标。典型要求:语音 10⁻³,数据 10⁻⁶,视频 10⁻⁹。

3. 信噪比(SNR)与Eb/N0

Eb/N0 = (S/N) × (B/R_b)

Eb/N0 是归一化信噪比,用于公平比较不同速率和带宽的系统。它是数字通信最重要的度量之一。

4. 频谱效率

η = R_b / B (bps/Hz)

单位带宽传输的比特率。Shannon极限给出理论上限:C = B × log₂(1 + S/N)

🔧 Verilog实现:数字通信系统顶层框架

我们用Verilog搭建数字通信系统的顶层模块框架,后续课程将逐步填充每个子模块的实现。

// digital_comm_top.v - 数字通信系统顶层框架
// 第01课:数字通信概述
module digital_comm_top (
    input  wire        clk,          // 系统时钟
    input  wire        rst_n,        // 异步复位(低有效)
    // 发送端接口
    input  wire [7:0]  tx_data,      // 待发送数据
    input  wire        tx_valid,     // 数据有效信号
    output wire        tx_ready,     // 发送端就绪
    // 接收端接口
    output wire [7:0]  rx_data,      // 接收数据
    output wire        rx_valid,     // 接收数据有效
    output wire        rx_error,     // 接收错误指示
    // 调制器DAC接口
    output wire [11:0] dac_i,        // I路DAC输出
    output wire [11:0] dac_q,        // Q路DAC输出
    // 解调器ADC接口
    input  wire [11:0] adc_i,        // I路ADC输入
    input  wire [11:0] adc_q,        // Q路ADC输入
    // 状态指示
    output wire [3:0]  link_status,  // 链路状态
    output wire        carrier_lock, // 载波锁定
    output wire        frame_sync    // 帧同步指示
);

    // ============================================================
    // 内部信号定义
    // ============================================================
    
    // 信源编码 → 信道编码
    wire [7:0]  src_enc_data;
    wire        src_enc_valid;
    wire        src_enc_ready;
    
    // 信道编码 → 加扰
    wire [7:0]  ch_enc_data;
    wire        ch_enc_valid;
    wire        ch_enc_ready;
    
    // 加扰 → 调制
    wire [7:0]  scram_data;
    wire        scram_valid;
    wire        scram_ready;
    
    // 解调 → 解扰
    wire [7:0]  demod_data;
    wire        demod_valid;
    wire        demod_ready;
    
    // 解扰 → 信道解码
    wire [7:0]  descram_data;
    wire        descram_valid;
    wire        descram_ready;
    
    // 信道解码 → 信源解码
    wire [7:0]  ch_dec_data;
    wire        ch_dec_valid;
    wire        ch_dec_ready;
    
    // ============================================================
    // 发送链路 (TX Chain)
    // ============================================================
    
    // 信源编码器 - 移除冗余,压缩数据
    source_encoder u_src_enc (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (tx_data),
        .s_valid  (tx_valid),
        .s_ready  (tx_ready),
        .m_data   (src_enc_data),
        .m_valid  (src_enc_valid),
        .m_ready  (src_enc_ready)
    );
    
    // 信道编码器 - 添加纠错冗余
    channel_encoder u_ch_enc (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (src_enc_data),
        .s_valid  (src_enc_valid),
        .s_ready  (src_enc_ready),
        .m_data   (ch_enc_data),
        .m_valid  (ch_enc_valid),
        .m_ready  (ch_enc_ready)
    );
    
    // 加扰器 - 保证信号随机性
    scrambler u_scram (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (ch_enc_data),
        .s_valid  (ch_enc_valid),
        .s_ready  (ch_enc_ready),
        .m_data   (scram_data),
        .m_valid  (scram_valid),
        .m_ready  (scram_ready)
    );
    
    // 调制器 - 基带调制,输出I/Q
    modulator u_mod (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (scram_data),
        .s_valid  (scram_valid),
        .s_ready  (scram_ready),
        .dac_i    (dac_i),
        .dac_q    (dac_q)
    );
    
    // ============================================================
    // 接收链路 (RX Chain)
    // ============================================================
    
    // 解调器 - 从I/Q采样恢复符号
    demodulator u_demod (
        .clk      (clk),
        .rst_n    (rst_n),
        .adc_i    (adc_i),
        .adc_q    (adc_q),
        .m_data   (demod_data),
        .m_valid  (demod_valid),
        .m_ready  (demod_ready),
        .carrier_lock (carrier_lock),
        .frame_sync   (frame_sync)
    );
    
    // 解扰器
    descrambler u_descram (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (demod_data),
        .s_valid  (demod_valid),
        .s_ready  (demod_ready),
        .m_data   (descram_data),
        .m_valid  (descram_valid),
        .m_ready  (descram_ready)
    );
    
    // 信道解码器
    channel_decoder u_ch_dec (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (descram_data),
        .s_valid  (descram_valid),
        .s_ready  (descram_ready),
        .m_data   (ch_dec_data),
        .m_valid  (ch_dec_valid),
        .m_ready  (ch_dec_ready)
    );
    
    // 信源解码器
    source_decoder u_src_dec (
        .clk      (clk),
        .rst_n    (rst_n),
        .s_data   (ch_dec_data),
        .s_valid  (ch_dec_valid),
        .s_ready  (ch_dec_ready),
        .m_data   (rx_data),
        .m_valid  (rx_valid),
        .m_ready  (1'b1)
    );
    
    // 错误检测
    assign rx_error = ~ch_dec_valid & descram_valid;
    
    // 链路状态机
    link_status_fsm #(
        .SYNC_THRESHOLD(4'd8)
    ) u_link_fsm (
        .clk          (clk),
        .rst_n        (rst_n),
        .carrier_lock (carrier_lock),
        .frame_sync   (frame_sync),
        .rx_valid     (rx_valid),
        .rx_error     (rx_error),
        .status       (link_status)
    );

endmodule

// ============================================================
// 链路状态机
// ============================================================
module link_status_fsm #(
    parameter SYNC_THRESHOLD = 4'd8
)(
    input  wire       clk,
    input  wire       rst_n,
    input  wire       carrier_lock,
    input  wire       frame_sync,
    input  wire       rx_valid,
    input  wire       rx_error,
    output reg [3:0]  status
);
    localparam IDLE      = 4'd0;  // 空闲
    localparam SEARCH    = 4'd1;  // 搜索载波
    localparam LOCKING   = 4'd2;  // 载波锁定中
    localparam SYNCING   = 4'd3;  // 帧同步中
    localparam LINKED    = 4'd4;  // 链路建立
    localparam ERROR     = 4'd5;  // 错误状态
    
    reg [3:0] sync_cnt;
    reg [3:0] err_cnt;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            status   <= IDLE;
            sync_cnt <= 4'd0;
            err_cnt  <= 4'd0;
        end else begin
            case (status)
                IDLE: begin
                    status <= SEARCH;
                end
                SEARCH: begin
                    if (carrier_lock)
                        status <= LOCKING;
                end
                LOCKING: begin
                    if (!carrier_lock)
                        status <= SEARCH;
                    else if (frame_sync) begin
                        status   <= SYNCING;
                        sync_cnt <= 4'd1;
                    end
                end
                SYNCING: begin
                    if (!carrier_lock)
                        status <= SEARCH;
                    else if (!frame_sync) begin
                        status <= LOCKING;
                        sync_cnt <= 4'd0;
                    end else if (rx_valid) begin
                        if (sync_cnt < SYNC_THRESHOLD)
                            sync_cnt <= sync_cnt + 1'b1;
                        else
                            status <= LINKED;
                    end
                end
                LINKED: begin
                    if (!carrier_lock) begin
                        status   <= SEARCH;
                        sync_cnt <= 4'd0;
                        err_cnt  <= 4'd0;
                    end else if (rx_error) begin
                        err_cnt <= err_cnt + 1'b1;
                        if (err_cnt >= SYNC_THRESHOLD)
                            status <= ERROR;
                    end else if (rx_valid && !rx_error) begin
                        err_cnt <= 4'd0;
                    end
                end
                ERROR: begin
                    if (!carrier_lock) begin
                        status  <= SEARCH;
                        err_cnt <= 4'd0;
                    end else if (rx_valid && !rx_error) begin
                        err_cnt <= 4'd0;
                        status  <= LINKED;
                    end
                end
                default: status <= IDLE;
            endcase
        end
    end
endmodule

// ============================================================
// 子模块存根 (后续课程逐步实现)
// ============================================================

module source_encoder (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [7:0] m_data,
    output wire       m_valid,
    input  wire       m_ready
);
    assign s_ready = m_ready;
    assign m_data  = s_data;
    assign m_valid = s_valid;
endmodule

module channel_encoder (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [7:0] m_data,
    output wire       m_valid,
    input  wire       m_ready
);
    assign s_ready = m_ready;
    assign m_data  = s_data;
    assign m_valid = s_valid;
endmodule

module scrambler (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [7:0] m_data,
    output wire       m_valid,
    input  wire       m_ready
);
    assign s_ready = m_ready;
    assign m_data  = s_data;
    assign m_valid = s_valid;
endmodule

module modulator (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [11:0] dac_i,
    output wire [11:0] dac_q
);
    assign s_ready = 1'b1;
    assign dac_i   = {s_data, 4'b0};
    assign dac_q   = 12'd0;
endmodule

module demodulator (
    input  wire        clk, rst_n,
    input  wire [11:0] adc_i, adc_q,
    output wire [7:0]  m_data,
    output wire        m_valid,
    input  wire        m_ready,
    output wire        carrier_lock,
    output wire        frame_sync
);
    assign m_data  = adc_i[11:4];
    assign m_valid = 1'b0;
    assign carrier_lock = 1'b0;
    assign frame_sync   = 1'b0;
endmodule

module descrambler (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [7:0] m_data,
    output wire       m_valid,
    input  wire       m_ready
);
    assign s_ready = m_ready;
    assign m_data  = s_data;
    assign m_valid = s_valid;
endmodule

module channel_decoder (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [7:0] m_data,
    output wire       m_valid,
    input  wire       m_ready
);
    assign s_ready = m_ready;
    assign m_data  = s_data;
    assign m_valid = s_valid;
endmodule

module source_decoder (
    input  wire       clk, rst_n,
    input  wire [7:0] s_data,
    input  wire       s_valid,
    output wire       s_ready,
    output wire [7:0] m_data,
    output wire       m_valid,
    input  wire       m_ready
);
    assign s_ready = m_ready;
    assign m_data  = s_data;
    assign m_valid = s_valid;
endmodule
✅ Verilator --lint-only 验证通过:模块层次结构完整,AXI-Stream接口定义规范

🐍 Python仿真:Shannon容量与信噪比关系

用Python仿真Shannon信道容量公式,理解数字通信的基本极限。

#!/usr/bin/env python3
"""shannon_capacity.py - Shannon信道容量仿真
第01课:数字通信概述
验证Shannon公式 C = B * log2(1 + SNR)
"""
import numpy as np
import matplotlib.pyplot as plt
from typing import List, Tuple

def shannon_capacity(bandwidth_hz: float, snr_linear: float) -> float:
    """计算Shannon信道容量
    
    Args:
        bandwidth_hz: 信道带宽 (Hz)
        snr_linear: 线性信噪比 (非dB)
    
    Returns:
        信道容量 (bps)
    """
    if snr_linear <= 0:
        return 0.0
    return bandwidth_hz * np.log2(1 + snr_linear)

def snr_db_to_linear(snr_db: float) -> float:
    """dB转线性值"""
    return 10 ** (snr_db / 10)

def eb_n0_from_snr(snr_db: float, spectral_eff: float) -> float:
    """从SNR计算Eb/N0
    
    Args:
        snr_db: 信噪比 (dB)
        spectral_eff: 频谱效率 (bps/Hz)
    
    Returns:
        Eb/N0 (dB)
    """
    snr_lin = snr_db_to_linear(snr_db)
    eb_n0_lin = snr_lin / spectral_eff
    return 10 * np.log10(eb_n0_lin) if eb_n0_lin > 0 else float('-inf')

def plot_shannon_limit():
    """绘制Shannon极限与各调制方式对比"""
    snr_db = np.linspace(-5, 30, 500)
    snr_lin = snr_db_to_linear(snr_db)
    
    # Shannon容量 (1 Hz带宽)
    capacity = np.log2(1 + snr_lin)  # bps/Hz
    
    # 各调制方式的频谱效率上界
    modulations = {
        'BPSK':  1.0,
        'QPSK':  2.0,
        '16-QAM': 4.0,
        '64-QAM': 6.0,
        '256-QAM': 8.0,
    }
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
    
    # 左图:Shannon容量 vs SNR
    ax1.plot(snr_db, capacity, 'c-', linewidth=2, label='Shannon极限')
    colors = ['#f59e0b', '#ef4444', '#10b981', '#8b5cf6', '#ec4899']
    for (name, eta), color in zip(modulations.items(), colors):
        ax1.axhline(y=eta, color=color, linestyle='--', alpha=0.7, label=f'{name} ({eta} bps/Hz)')
    
    ax1.set_xlabel('SNR (dB)', fontsize=12)
    ax1.set_ylabel('频谱效率 (bps/Hz)', fontsize=12)
    ax1.set_title('Shannon信道容量', fontsize=14)
    ax1.legend(loc='upper left', fontsize=9)
    ax1.grid(True, alpha=0.3)
    ax1.set_xlim(-5, 30)
    ax1.set_ylim(0, 10)
    
    # 右图:各调制方式到Shannon极限的距离
    snr_for_eta = {}
    for name, eta in modulations.items():
        # 找到达到该频谱效率所需的最小SNR
        required_snr = 2**eta - 1  # Shannon下界
        required_snr_db = 10 * np.log10(required_snr) if required_snr > 0 else -999
        snr_for_eta[name] = required_snr_db
        
        # 实际所需SNR(近似,考虑实现损耗~3-6dB)
        actual_snr_db = required_snr_db + 6  # 约6dB实现损耗
        
        ax2.barh(name, actual_snr_db - required_snr_db, left=required_snr_db,
                color=color, alpha=0.7, edgecolor='white')
        ax2.plot(required_snr_db, name, 'c|', markersize=15, markeredgewidth=2)
    
    ax2.set_xlabel('SNR (dB)', fontsize=12)
    ax2.set_title('Shannon极限 vs 实际SNR需求', fontsize=14)
    ax2.grid(True, alpha=0.3, axis='x')
    
    plt.tight_layout()
    plt.savefig('/var/www/ttl/digital-comm/shannon_capacity.png', dpi=100, 
                facecolor='#0f172a', edgecolor='none')
    print("Shannon容量图已保存")
    return capacity, snr_db

def simulate_ber_vs_snr():
    """仿真BPSK在AWGN信道下的BER"""
    np.random.seed(42)
    num_bits = 100000
    snr_db_range = np.linspace(-5, 15, 21)
    ber_sim = []
    ber_theory = []
    
    for snr_db in snr_db_range:
        snr_lin = snr_db_to_linear(snr_db)
        noise_std = 1.0 / np.sqrt(2 * snr_lin) if snr_lin > 0 else float('inf')
        
        # BPSK: 0→+1, 1→-1
        bits = np.random.randint(0, 2, num_bits)
        symbols = 1 - 2 * bits  # BPSK映射
        
        # AWGN信道
        noise = noise_std * np.random.randn(num_bits)
        rx = symbols + noise
        
        # 判决
        rx_bits = (rx < 0).astype(int)
        
        # BER
        errors = np.sum(bits != rx_bits)
        ber = errors / num_bits
        ber_sim.append(max(ber, 1e-6))
        
        # 理论值 Q(sqrt(2*SNR))
        from scipy.special import erfc
        ber_th = 0.5 * erfc(np.sqrt(snr_lin))
        ber_theory.append(max(ber_th, 1e-6))
    
    # 绘制BER曲线
    plt.figure(figsize=(10, 6))
    plt.semilogy(snr_db_range, ber_theory, 'c-', linewidth=2, label='理论值')
    plt.semilogy(snr_db_range, ber_sim, 'ro', markersize=5, label='仿真值')
    plt.xlabel('Eb/N0 (dB)', fontsize=12)
    plt.ylabel('误码率 (BER)', fontsize=12)
    plt.title('BPSK在AWGN信道下的误码率', fontsize=14)
    plt.legend(fontsize=11)
    plt.grid(True, alpha=0.3, which='both')
    plt.ylim(1e-6, 1)
    plt.savefig('/var/www/ttl/digital-comm/bpsk_ber.png', dpi=100,
                facecolor='#0f172a', edgecolor='none')
    print("BPSK BER曲线已保存")
    return ber_sim, ber_theory

def simulate_link_budget():
    """链路预算仿真"""
    # 参数
    tx_power_dbm = 20       # 发射功率 100mW
    tx_gain_dbi  = 2        # 发射天线增益
    freq_mhz     = 2400     # 2.4GHz (WiFi)
    rx_gain_dbi  = 2        # 接收天线增益
    noise_figure_db = 6     # 接收机噪声系数
    bandwidth_hz = 20e6     # 20MHz带宽
    required_snr_db = 10    # 所需SNR
    
    # 热噪声
    k_boltzmann = 1.38e-23
    temperature = 290       # 室温
    noise_power_dbm = 10 * np.log10(k_boltzmann * temperature * bandwidth_hz * 1000)
    
    distances = np.linspace(1, 500, 1000)  # 1-500米
    
    # 自由空间路径损耗
    path_loss_db = (20 * np.log10(distances) + 
                    20 * np.log10(freq_mhz) + 
                    32.44)  # FSPL公式
    
    # 接收功率
    rx_power_dbm = tx_power_dbm + tx_gain_dbi - path_loss_db + rx_gain_dbi
    
    # SNR
    snr_db = rx_power_dbm - (noise_power_dbm + noise_figure_db)
    
    # 最大通信距离
    max_dist_idx = np.where(snr_db >= required_snr_db)[0]
    max_distance = distances[max_dist_idx[-1]] if len(max_dist_idx) > 0 else 0
    
    print(f"链路预算分析:")
    print(f"  发射功率: {tx_power_dbm} dBm ({10**(tx_power_dbm/10)} mW)")
    print(f"  噪声功率: {noise_power_dbm:.1f} dBm")
    print(f"  所需SNR: {required_snr_db} dB")
    print(f"  最大通信距离: {max_distance:.0f} 米")
    
    return max_distance, distances, snr_db

if __name__ == '__main__':
    print("=" * 60)
    print("数字通信概述 - Shannon容量仿真")
    print("=" * 60)
    
    # Shannon容量
    capacity, snr = plot_shannon_limit()
    
    # BPSK BER仿真
    ber_sim, ber_th = simulate_ber_vs_snr()
    print(f"\nBPSK BER @ 10dB: 仿真={ber_sim[15]:.2e}, 理论={ber_th[15]:.2e}")
    
    # 链路预算
    max_dist, _, _ = simulate_link_budget()
    
    print("\n✅ 所有仿真完成!")
✅ Python仿真验证通过:Shannon容量计算正确,BPSK BER与理论值吻合,链路预算分析合理

📖 通信发展简史

年代里程碑意义
1837Morse电报人类第一份数字通信
1876Bell电话模拟语音通信开始
1948Shannon论文信息论奠基,数字通信理论基础
1962PCM商用数字电话传输
1973Ethernet有线数据通信标准
1991GSM第二代移动通信(数字)
1999WiFi 802.11b无线局域网
2010LTE4G移动通信
20205G NR新空口,毫米波,大规模MIMO

💡 本课核心概念

要点回顾:
  1. 数字通信系统由信源编码、信道编码、调制、信道、解调、解码六大部分组成
  2. Shannon公式 C = B×log₂(1+S/N) 给出信道容量理论上限
  3. Eb/N0是归一化信噪比,用于公平比较不同系统
  4. 频谱效率 = 比特率/带宽,单位 bps/Hz
  5. Verilog实现采用AXI-Stream接口连接各模块

📝 课后练习

练习1:计算一个带宽为10MHz、SNR为20dB的信道的Shannon容量。

练习2:BPSK和QPSK在相同符号率下,比特率相差多少?在相同比特率下,带宽效率如何?

练习3:修改Verilog顶层模块,添加一个loopback模式,将TX输出直接连到RX输入用于测试。

练习4:用Python仿真:当SNR从0dB增加到30dB时,16-QAM的理论BER如何变化?与BPSK对比。

练习5:链路预算:WiFi 6 (1024-QAM, 160MHz带宽) 在自由空间中的最大通信距离是多少?

📡

🏆 成就解锁:通信先驱

你已经理解了数字通信系统的整体架构!从Shannon极限到BPSK误码率,从链路预算到Verilog顶层框架,这是你通信之旅的第一步。

下一课预告:第02课将深入采样与量化的世界,理解连续信号如何变成数字比特流。