Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ venv/
.pytest_cache/
.pylint.d/
.DS_Store
results/*.png
# results/*.png
results/*.csv
results/*.json
!results/.gitkeep
Expand Down
78 changes: 78 additions & 0 deletions REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# 无线通信技术实验报告:信道编码与信道均衡

## 1. 实验目的

本实验旨在掌握信道编码与信道均衡的基本原理与实现方法,包括:

- 理解 Hamming(7,4) 线性分组码的编码规则与单比特纠错能力。
- 实现伴随式计算并完成 Hamming 译码。
- 理解多径信道导致的符号间干扰(ISI)。
- 实现迫零(ZF)均衡器和 LMS 自适应均衡器,并观察均衡效果。
- 练习在 GitHub 环境中运行实验脚本、生成结果图像和通过自动测试。

## 2. 实验原理

### 2.1 信道编码

Hamming(7,4) 是一种线性分组码,将 4 个信息比特映射为 7 个码字比特。编码过程使用生成矩阵 $G$,在 GF(2) 上进行矩阵乘法,生成 3 个校验位。接收端通过伴随式 $s = r H^T$ 计算校验结果,其中 $H$ 为校验矩阵。若伴随式为零,则码字无错误;若非零,则伴随式等于某一列,表示错误位位置,从而可纠正单比特错误。

### 2.2 信道均衡

在多径传输中,接收信号是发送符号与信道冲激响应的卷积,产生前向和后向 ISI。ZF 均衡器通过求解线性方程,使复合脉冲响应在目标采样点处对齐为单位冲激,从而抑制 ISI。LMS 自适应均衡器通过训练序列迭代更新系数,最小化瞬时误差,实现在未知或变化信道下的自适应补偿。

## 3. 实验环境

- Python 版本:3.12.12
- 主要依赖:NumPy、Matplotlib、pytest
- 运行工具:Visual Studio Code、Python 解释器
- AI 助手使用情况:本实验报告、核心算法实现与调试过程中参考了 AI 助手提供的代码结构建议,并在生成后确认逻辑正确,保证所有关键函数已测试通过。

## 4. 实验方法与步骤

### 4.1 Part 1:信道编码

1. 使用 `hamming74_encode(bits)` 实现 Hamming(7,4) 编码,将 4 比特数据块映射为 7 比特码字。
2. 使用 `hamming74_syndrome(codewords)` 计算伴随式,验证正确码字的伴随式为零。
3. 使用 `hamming74_decode(received)` 对接收码字进行单比特纠错:若伴随式非零,则与 $H$ 的列匹配,定位错误位置并翻转错误比特。
4. 运行 `src/part1_channel_coding.py`,在不同信道错误概率下比较未编码与 Hamming 编码的 BER,并生成 `results/coding_ber_curve.png`。

### 4.2 Part 2:信道均衡

1. 生成 BPSK 模拟符号序列,并通过多径信道 `multipath_channel` 产生接收信号。
2. 实现 `estimate_zf_equalizer(channel, num_taps)`,构造卷积矩阵并使用最小二乘法求解 ZF 均衡器系数。
3. 实现 `apply_fir_filter(signal, taps)`,对接收信号进行 FIR 滤波。
4. 实现 `lms_equalizer(rx_train, tx_train, num_taps, step_size)`,使用训练序列迭代更新均衡器参数,记录每次误差。
5. 运行 `src/part2_equalization.py`,生成 `results/equalization_eye_comparison.png` 和 `results/equalization_mse_curve.png`,并比较均衡前后 BER。

## 5. 实验结果

### 图像结果

![编码BER曲线](results/coding_ber_curve.png)

![均衡眼图对比](results/equalization_eye_comparison.png)

![LMS误差曲线](results/equalization_mse_curve.png)

### 运行结果

- Part 1: 成功生成 BER 曲线。
- Part 2: 均衡前 BER = 0.0010,LMS 均衡后 BER = 0.0000。
- 自动测试结果:`16 passed`。

## 6. 结果分析与讨论

1. Hamming(7,4) 能纠正单比特错误,因为每个单比特错误导致的伴随式不同,对应于校验矩阵 $H$ 的唯一列,从而可定位单比特错误位置。
2. 信道编码引入冗余比特(从 4 比特增加到 7 比特),降低了有效码率,但通过增加冗余提高了对错误的检测与纠正能力,提升了可靠性。
3. ZF 均衡器在抑制 ISI 时会放大某些频率成分,因此在存在噪声时可能引入噪声增强现象,尤其是在信道频率响应接近零点附近。
4. LMS 步长过大会导致收敛不稳定、误差波动较大;步长过小则收敛速度慢,训练时间变长。本实验中选择 `step_size=0.01` 达到较稳定的收敛效果。
5. 均衡前后 ISI 明显减弱。原始多径接收信号存在严重符号混叠,经过 LMS 均衡后输出波形更接近原始 BPSK 符号,误差曲线逐步下降。

## 7. 实验心得

本次实验加深了对 Hamming 码与均衡器原理的理解。实际编程过程中,注意矩阵运算的 GF(2) 处理与 FIR 卷积边界对齐非常关键。AI 助手在实现思路和调试上提供了参考,但最终代码已根据测试结果进行了验证,确保可运行且符合实验要求。

## 8. 参考资料

- 课程课件:第6章 信道编码
- 课程课件:第7章 均衡
Binary file added results/coding_ber_curve.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added results/equalization_eye_comparison.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added results/equalization_mse_curve.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 16 additions & 6 deletions src/part1_channel_coding.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ def hamming74_encode(bits):
if not np.all((bits == 0) | (bits == 1)):
raise ValueError('bits 只能包含 0 或 1')

# TODO: 将 bits reshape 为 (-1, 4),再与 HAMMING_G 相乘并对 2 取模。
raise NotImplementedError('请实现 Hamming(7,4) 编码')
blocks = bits.reshape(-1, 4)
encoded = np.mod(blocks.dot(HAMMING_G), 2).astype(int)
return encoded.reshape(-1)


def hamming74_syndrome(codewords):
Expand All @@ -70,8 +71,8 @@ def hamming74_syndrome(codewords):
if codewords.shape[1] != 7:
raise ValueError('每个 Hamming(7,4) 码字长度必须为 7')

# TODO: 计算 s = r H^T mod 2。
raise NotImplementedError('请实现伴随式计算')
syndromes = np.mod(codewords.dot(HAMMING_H.T), 2).astype(int)
return syndromes


def hamming74_decode(received):
Expand All @@ -94,8 +95,17 @@ def hamming74_decode(received):
if received.ndim != 1 or len(received) % 7 != 0:
raise ValueError('received 必须是一维数组,长度为 7 的倍数')

# TODO: 使用 hamming74_syndrome 完成单比特纠错,并返回前 4 个信息位。
raise NotImplementedError('请实现 Hamming(7,4) 译码')
codewords = received.reshape(-1, 7)
corrected = codewords.copy()
syndromes = hamming74_syndrome(codewords)
h_columns = HAMMING_H.T
for idx, syndrome in enumerate(syndromes):
if np.any(syndrome):
matches = np.all(h_columns == syndrome, axis=1)
if np.any(matches):
error_pos = int(np.argmax(matches))
corrected[idx, error_pos] ^= 1
return corrected[:, :4].reshape(-1)


def convolutional_encode(bits):
Expand Down
36 changes: 30 additions & 6 deletions src/part2_equalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,19 @@ def estimate_zf_equalizer(channel, num_taps):
if num_taps < 1:
raise ValueError('num_taps 必须为正整数')

# TODO: 构造卷积矩阵并求解 ZF 均衡器抽头。
raise NotImplementedError('请实现 ZF 均衡器估计')
channel_len = len(channel)
num_rows = channel_len + num_taps - 1
matrix = np.zeros((num_rows, num_taps), dtype=float)
for row in range(num_rows):
for col in range(num_taps):
idx = row - col
if 0 <= idx < channel_len:
matrix[row, col] = channel[idx]
desired = np.zeros(num_rows, dtype=float)
center = num_taps // 2
desired[center] = 1.0
taps, *_ = np.linalg.lstsq(matrix, desired, rcond=None)
return taps


def apply_fir_filter(signal, taps):
Expand All @@ -58,8 +69,8 @@ def apply_fir_filter(signal, taps):
if signal.ndim != 1 or taps.ndim != 1:
raise ValueError('signal 和 taps 必须是一维数组')

# TODO: 使用 np.convolve,并截取与 signal 等长的输出。
raise NotImplementedError('请实现 FIR 滤波')
filtered = np.convolve(signal, taps, mode='full')[: len(signal)]
return filtered


def lms_equalizer(rx_train, tx_train, num_taps, step_size=0.01):
Expand Down Expand Up @@ -89,8 +100,21 @@ def lms_equalizer(rx_train, tx_train, num_taps, step_size=0.01):
if num_taps < 1:
raise ValueError('num_taps 必须为正整数')

# TODO: 实现 LMS 自适应均衡训练。
raise NotImplementedError('请实现 LMS 均衡器')
rx_train = np.asarray(rx_train, dtype=float)
tx_train = np.asarray(tx_train, dtype=float)
num_samples = len(rx_train)
padded_rx = np.concatenate([np.zeros(num_taps - 1, dtype=float), rx_train])
taps = np.zeros(num_taps, dtype=float)
center = num_taps // 2
taps[center] = 1.0
errors = []
for n in range(num_samples):
window = padded_rx[n:n + num_taps][::-1]
y = np.dot(taps, window)
e = tx_train[n] - y
errors.append(e)
taps = taps + step_size * e * window
return taps, np.asarray(errors, dtype=float)


def run_equalization_demo():
Expand Down
Loading