数字通信是将信息源产生的模拟或数字信号转换为数字形式,经过编码、调制后在信道上传输,接收端经过解调、解码恢复原始信息的过程。与模拟通信相比,数字通信具有抗干扰能力强、可进行纠错编码、便于加密、易于集成等优势。
| 特性 | 模拟通信 | 数字通信 |
|---|---|---|
| 信号表示 | 连续波形 | 离散符号(0/1) |
| 抗噪声 | 噪声累积 | 可中继再生 |
| 保密性 | 较难加密 | 易于加密 |
| 复用方式 | FDM | TDM/CDM/OFDM |
| 设备复杂度 | 较低 | 较高(但可集成) |
| 典型应用 | 传统FM广播 | 5G/WiFi/蓝牙 |
一个完整的数字通信系统包含以下关键模块:
信源编码(Source Coding):压缩冗余,提高有效性。如Huffman编码、LZ77压缩。
信道编码(Channel Coding):增加冗余,提高可靠性。如汉明码、LDPC码、Polar码。
调制(Modulation):将基带信号搬移到载波频率,适配信道传输特性。
信道(Channel):信号传输的媒介,引入噪声、衰落和干扰。
解调(Demodulation):从接收信号中提取基带信息。
解码(Decoding):纠正传输错误,恢复原始数据。
其中 R_b 为比特率(bps),R_s 为符号率(Baud),M 为调制阶数。例如QPSK(M=4)中,每个符号携带2比特。
数字通信系统的核心质量指标。典型要求:语音 10⁻³,数据 10⁻⁶,视频 10⁻⁹。
Eb/N0 是归一化信噪比,用于公平比较不同速率和带宽的系统。它是数字通信最重要的度量之一。
单位带宽传输的比特率。Shannon极限给出理论上限:C = B × log₂(1 + S/N)。
我们用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
用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✅ 所有仿真完成!")
| 年代 | 里程碑 | 意义 |
|---|---|---|
| 1837 | Morse电报 | 人类第一份数字通信 |
| 1876 | Bell电话 | 模拟语音通信开始 |
| 1948 | Shannon论文 | 信息论奠基,数字通信理论基础 |
| 1962 | PCM商用 | 数字电话传输 |
| 1973 | Ethernet | 有线数据通信标准 |
| 1991 | GSM | 第二代移动通信(数字) |
| 1999 | WiFi 802.11b | 无线局域网 |
| 2010 | LTE | 4G移动通信 |
| 2020 | 5G NR | 新空口,毫米波,大规模MIMO |
C = B×log₂(1+S/N) 给出信道容量理论上限练习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课将深入采样与量化的世界,理解连续信号如何变成数字比特流。