PUSCH 发送端模拟
PUSCH发送端模拟了:PUSCH DMRS生成、数据生成及16QAM调制、多径信道生成、OFDM调制过程。
PUSCH 16QAM调制数据的生成
根据协议规定3GPP TS 38.211 5.1.4规定,对于16QAM,每4bits 映射为一个复数调制符号,即:
可以通过公式计算出不同bits组合到星座点的映射数据,定义
QAM16_CONSTELLATION_3GPP = np.array([1+1j, 1+3j, 3+1j, 3+3j, # 0000,0001,0010,00111-1j, 1-3j, 3-1j, 3-3j, # 0100,0101,0110,0111-1+1j, -1+3j, -3+1j, -3+3j, # 1000,1001,1010,1011-1-1j, -1-3j, -3-1j, -3-3j# 1100,1101,1110,1111]) / np.sqrt(10)
每个符号除以是为了功率归一化,目的在于使得不同调制方式都能够取得相同的平均功率。功率归一化有助于比较不同信号的性能。
通过numpy中的random.randint()函数生成0到16的随机整数,作为PUSCH随机发送的数据,并将其转换为复数符号数据。
defgenerate_16qam_data(size):"""生成16QAM符号和对应的比特""" indices = np.random.randint(0, 16, size=size) symbols = QAM16_CONSTELLATION_3GPP[indices]# 将每个索引转换为4比特(高位在前) bits = np.unpackbits(indices.astype(np.uint8)[:, None], axis=1, bitorder='big')[:, -4:].flatten()return symbols, bits
OFDM调制
defofdm_modulate(grid): n_sc, n_sym = grid.shape time_signal = np.zeros((n_sym, N_FFT + CP_LENGTH), dtype=complex) active_sc_indices = np.arange(N_FFT // 2 - n_sc // 2, N_FFT // 2 + n_sc // 2)for sym in range(n_sym): fd_symbol = np.zeros(N_FFT, dtype=complex) fd_symbol[active_sc_indices] = grid[:, sym] td_symbol = np.fft.ifft(np.fft.fftshift(fd_symbol), n=N_FFT) td_symbol_with_cp = np.concatenate([td_symbol[-CP_LENGTH:], td_symbol]) time_signal[sym, :] = td_symbol_with_cpreturn time_signal.flatten()
多径信道模型
# ==================== 信道模型 ====================defgenerate_multipath_channel(num_taps=4, max_delay=500e-9): delays = np.sort(np.random.uniform(0, max_delay, num_taps)) print(f'delays[0]: {delays[0]}s about {delays[0]*sampleRate} samples') gains = np.random.randn(num_taps) + 1j * np.random.randn(num_taps) gains /= np.sqrt(np.sum(np.abs(gains)**2))return delays, gains
发送信号应用多径信道模型
defapply_multipath_channel(signal, taps, delays, sample_rate): sample_delays = np.round(delays * sample_rate).astype(int) max_delay = np.max(sample_delays) h = np.zeros(max_delay + 1, dtype=complex)for i, d in enumerate(sample_delays):if d < len(h): h[d] = taps[i]return np.convolve(signal, h, mode='full')[:len(signal)], h
添加awgn信道
def add_awgn(signal, snr_db): signal_power = np.mean(np.abs(signal)**2) noise_power = signal_power / (10 ** (snr_db / 10)) noise = np.sqrt(noise_power/2) * (np.random.randn(len(signal)) + 1j * np.random.randn(len(signal)))return signal + noise