nearlink_sdr.phy.gfsk 源代码


__all__ = [
    "GFSK_BW_CONFIG",
    "GFSKDemodulator",
    "GFSKModulator",
]


import numpy as np

# TXS-10002-2025 6.2.1.1 GFSK调制
# BT = 0.5, 调制系数 h 在 0.45~0.55 之间

# 标准带宽与符号间隔对应关系
GFSK_BW_CONFIG = {
    0.1:  {"symbol_period_us": 10,  "min_freq_dev_khz": 23.125},
    0.125: {"symbol_period_us": 8,  "min_freq_dev_khz": 46.25},
    0.25: {"symbol_period_us": 4,   "min_freq_dev_khz": 92.5},
    0.5:  {"symbol_period_us": 2,   "min_freq_dev_khz": 185},
    1.0:  {"symbol_period_us": 1,   "min_freq_dev_khz": 185},
    2.0:  {"symbol_period_us": 0.5, "min_freq_dev_khz": 370},
    4.0:  {"symbol_period_us": 0.25, "min_freq_dev_khz": 740},
}


def _gaussian_filter(bt: float, span: int, sps: int) -> np.ndarray:
    """生成高斯滤波器的脉冲响应。"""
    t = np.arange(-span * sps / 2, span * sps / 2 + 1) / sps
    alpha = np.sqrt(np.log(2) / 2) / bt
    h = np.sqrt(2 * np.pi) / alpha * np.exp(-2 * (np.pi * t / alpha) ** 2)
    h = h / np.sum(h)
    return h


[文档] class GFSKModulator: """TXS-10002-2025 6.2.1.1 GFSK调制器。 比特1表示正频偏,比特0表示负频偏。 """ def __init__(self, sps: int = 8, mod_index: float = 0.5, bt: float = 0.5, gauss_span: int = 3): if not 0.45 <= mod_index <= 0.55: raise ValueError( f"mod_index={mod_index} 超出标准范围 [0.45, 0.55] (§6.2.1.1)" ) self.sps = sps self.mod_index = mod_index self.bt = bt self.gauss_span = gauss_span self._gauss_filter = _gaussian_filter(bt, gauss_span, sps)
[文档] def modulate(self, bits: np.ndarray) -> np.ndarray: """GFSK调制。 :param bits: 输入比特序列, shape (N,), 值为 0/1 :returns: 复基带IQ信号, shape (N*sps,) """ # NRZ映射: 0 -> -1, 1 -> +1 nrz = 2.0 * bits.astype(float) - 1.0 # 上采样:使用矩形脉冲(repeat),而非冲激 upsampled = np.repeat(nrz, self.sps) # 高斯滤波平滑频率轨迹 filtered = np.convolve(upsampled, self._gauss_filter, mode='same') # 频率积分得到瞬时相位 # 每个符号的总相位变化应为 h*pi freq_deviation = self.mod_index * np.pi / self.sps phase = np.cumsum(filtered) * freq_deviation # 生成复基带信号 signal = np.exp(1j * phase) return signal
[文档] class GFSKDemodulator: """GFSK非相干解调器(基于频率鉴别器)。""" def __init__(self, sps: int = 8): self.sps = sps
[文档] def demodulate(self, signal: np.ndarray) -> np.ndarray: """GFSK解调。 :param signal: 复基带IQ信号 :returns: 解调后的比特序列, 值为 0/1 """ # 频率鉴别:取相邻采样点的相位差 phase_diff = np.angle(signal[1:] * np.conj(signal[:-1])) # 按符号累积频率 (包含末尾不足一个完整符号的部分) n_symbols = -(-len(phase_diff) // self.sps) # ceiling division bits = np.zeros(n_symbols, dtype=int) for i in range(n_symbols): start = i * self.sps end = min(start + self.sps, len(phase_diff)) segment = phase_diff[start:end] bits[i] = 1 if np.sum(segment) > 0 else 0 return bits