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
189 changes: 64 additions & 125 deletions src/demodulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,150 +5,94 @@

import numpy as np


def bpsk_demodulate(symbols):
"""
BPSK解调

任务要求:
- 输入:接收到的复数符号序列(可能带噪声)
- 输出:恢复的比特序列
- 判决准则:
实部 > 0 → 比特 0
实部 ≤ 0 → 比特 1

参数:
symbols: 接收到的复数符号数组

返回:
bits: 恢复的比特数组

提示:
- BPSK符号主要在实轴上
- 只需要判断实部的正负即可
- 噪声会使符号偏离理想位置,但判决准则仍然有效

示例:
>>> symbols = np.array([0.9+0.1j, -1.1-0.05j, 0.85+0.2j])
>>> bits = bpsk_demodulate(symbols)
>>> print(bits)
[0 1 0]
"""

# TODO: 实现BPSK解调
# 提示:使用np.real()获取实部,然后判断正负

raise NotImplementedError("请实现BPSK解调函数")
"""BPSK解调"""
# 实部 > 0 → 比特 0;实部 ≤ 0 → 比特 1
return (np.real(symbols) <= 0).astype(int)


def qpsk_demodulate(symbols):
"""
QPSK解调

任务要求:
- 输入:接收到的复数符号序列
- 输出:恢复的比特序列(长度是符号数的2倍)
- 使用最小欧氏距离判决

参数:
symbols: 接收到的复数符号数组

返回:
bits: 恢复的比特数组

提示:
- QPSK有4个参考星座点(理想位置)
- 对每个接收符号,计算它到4个参考点的距离
- 选择距离最小的那个点,输出对应的比特对
- 参考点(格雷码):
(1+1j)/√2 → 00
(-1+1j)/√2 → 01
(-1-1j)/√2 → 11
(1-1j)/√2 → 10

示例:
>>> symbols = np.array([0.6+0.6j, -0.7+0.8j])
>>> bits = qpsk_demodulate(symbols)
>>> print(bits) # 应该是 [0, 0, 0, 1]
"""

# 定义QPSK参考星座点(格雷码)
"""QPSK解调"""
constellation = {
0: (1 + 1j) / np.sqrt(2), # 00
1: (-1 + 1j) / np.sqrt(2), # 01
3: (-1 - 1j) / np.sqrt(2), # 11
2: (1 - 1j) / np.sqrt(2) # 10
(0, 0): (1 + 1j) / np.sqrt(2),
(0, 1): (-1 + 1j) / np.sqrt(2),
(1, 1): (-1 - 1j) / np.sqrt(2),
(1, 0): (1 - 1j) / np.sqrt(2)
}

# TODO: 实现QPSK解调
# 提示步骤:
# 1. 对每个接收符号,计算到4个参考点的欧氏距离
# 2. 找到距离最小的参考点
# 3. 将参考点的索引转换为2个比特

raise NotImplementedError("请实现QPSK解调函数")

bits = np.zeros(len(symbols) * 2, dtype=int)
points = list(constellation.values())
keys = list(constellation.keys())

for i, sym in enumerate(symbols):
# 计算欧氏距离
dists = [np.abs(sym - p) for p in points]
best_idx = np.argmin(dists)
b0, b1 = keys[best_idx]

bits[2*i] = b0
bits[2*i+1] = b1

return bits


def qam16_demodulate(symbols):
"""
16-QAM解调

任务要求:
- 输入:接收到的复数符号序列
- 输出:恢复的比特序列(长度是符号数的4倍)
- 使用最小欧氏距离判决

参数:
symbols: 接收到的复数符号数组

返回:
bits: 恢复的比特数组

提示:
- 16-QAM有16个参考星座点
- 可以分别对I路和Q路进行判决,简化计算
- I/Q分量的判决(格雷码):
> 2/√10 → 00
0 ~ 2/√10 → 01
-2/√10 ~ 0 → 11
< -2/√10 → 10
"""

# TODO: 实现16-QAM解调
# 提示:可以采用两种方法
# 方法1:遍历16个参考点,找最小距离(简单但慢)
# 方法2:分别判决I路和Q路(快速且实用)

raise NotImplementedError("请实现16-QAM解调函数")
"""16-QAM解调"""
bits = np.zeros(len(symbols) * 4, dtype=int)

for i, sym in enumerate(symbols):
# 还原归一化以便于判断边界
sym_unnorm = sym * np.sqrt(10)
I = np.real(sym_unnorm)
Q = np.imag(sym_unnorm)

# 判决 I 路
if I > 2:
b0, b1 = 0, 0
elif I > 0:
b0, b1 = 0, 1
elif I > -2:
b0, b1 = 1, 1
else:
b0, b1 = 1, 0

# 判决 Q 路
if Q > 2:
b2, b3 = 0, 0
elif Q > 0:
b2, b3 = 0, 1
elif Q > -2:
b2, b3 = 1, 1
else:
b2, b3 = 1, 0

bits[4*i:4*i+4] = [b0, b1, b2, b3]

return bits


def test_demodulation():
"""
测试解调函数
需要先完成调制函数才能运行
"""
"""测试解调函数"""
from modulation import bpsk_modulate, qpsk_modulate, qam16_modulate
from utils import add_awgn, calculate_ber

print("=" * 50)
print("解调测试")
print("=" * 50)

# 测试BPSK
print("\n1. 测试BPSK解调...")
try:
bits_tx = np.random.randint(0, 2, 100)
symbols = bpsk_modulate(bits_tx)
symbols_rx = add_awgn(symbols, snr_db=10) # 添加10dB噪声
symbols_rx = add_awgn(symbols, snr_db=10)
bits_rx = bpsk_demodulate(symbols_rx)
ber = calculate_ber(bits_tx, bits_rx)
print(f" BER = {ber:.4f} (SNR=10dB)")
print(" ✅ BPSK解调测试通过")
except NotImplementedError:
print(" ⏸️ BPSK解调尚未实现")
except Exception as e:
print(f" ❌ BPSK解调测试失败: {e}")

# 测试QPSK
print("\n2. 测试QPSK解调...")
try:
Expand All @@ -159,28 +103,23 @@ def test_demodulation():
ber = calculate_ber(bits_tx, bits_rx)
print(f" BER = {ber:.4f} (SNR=10dB)")
print(" ✅ QPSK解调测试通过")
except NotImplementedError:
print(" ⏸️ QPSK解调尚未实现")
except Exception as e:
print(f" ❌ QPSK解调测试失败: {e}")

# 测试16-QAM
print("\n3. 测试16-QAM解调...")
try:
bits_tx = np.random.randint(0, 2, 100)
symbols = qam16_modulate(bits_tx)
symbols_rx = add_awgn(symbols, snr_db=15) # QAM需要更高SNR
symbols_rx = add_awgn(symbols, snr_db=15)
bits_rx = qam16_demodulate(symbols_rx)
ber = calculate_ber(bits_tx, bits_rx)
print(f" BER = {ber:.4f} (SNR=15dB)")
print(" ✅ 16-QAM解调测试通过")
except NotImplementedError:
print(" ⏸️ 16-QAM解调尚未实现")
except Exception as e:
print(f" ❌ 16-QAM解调测试失败: {e}")

print("\n" + "=" * 50)

print("\n" + "=" * 50)

if __name__ == "__main__":
test_demodulation()
test_demodulation()
Loading
Loading