宽带矢量信号MQAM同步分析算法【附代码】
✨ 长期致力于宽带矢量信号分析、MQAM、重采样、定时同步、载波同步研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。
✅ 专业定制毕设、代码
✅如需沟通交流,点击《获取方式》
(1)并行Farrow结构分数延迟重采样器:
针对符号率各异的MQAM信号,设计一种基于Farrow结构的三阶Lagrange插值重采样器,将采样率转换为符号率的8倍整数倍。Farrow结构包含4个固定系数滤波器分支,系数为[-1/6, 1/2, -1/3, 1/6]等组合。重采样过程中的基点索引和小数间隔通过数控振荡器计算,NCO相位累加字长为32位,频率控制字与重采样比直接相关。为满足高吞吐率要求,将重采样器并行化为8路,每路处理连续8个输入样点,输出对应的重采样样点。在符号率范围为10M至200Msps时,重采样后的定时误差小于0.01符号周期,幅度失真小于0.05dB。该模块在FPGA上实现消耗56个DSP单元和约1800个逻辑单元。
(2)改进Gardner定时误差检测与预滤波:
针对高阶MQAM(M>4)信号星座图存在多幅度导致传统Gardner算法失效的问题,提出一种经过修正的定时误差检测公式:e(n)=y_I(n-0.5)[y_I(n)-y_I(n-1)] + y_Q(n-0.5)[y_Q(n)-y_Q(n-1)],其中y_I和y_Q为经过平方根升余弦滤波后的信号。为降低误差抖动,在定时检测前增加一个预滤波器,滤波器系数采用三阶插值型,提升幅度检测的稳定性。对64QAM和256QAM信号进行仿真,信噪比25dB时,定时抖动方差从传统方法的0.032符号^2降低至0.009符号^2。环路滤波器采用二阶比例积分结构,自然频率设为符号率的1/200,阻尼系数0.707。
(3)联合PFD-DD载波同步算法与EVM测试:
设计一个两阶段载波同步算法,第一阶段采用PFD相位频率检测器实现大频偏捕获,频偏捕获范围达到符号率的18%,捕获后剩余频偏小于0.5%符号率;第二阶段切换为DD判决导向算法进行精细跟踪,环路带宽收窄到0.001,相位噪声抑制能力提升。在FPGA中实现时,使用CORDIC计算相位误差和NCO累加。采用Verilog实现后,在信号源+分析仪平台上测试,对于16QAM,符号率100Msps,频偏100kHz时,EVM从30%降低至2.3%;对于256QAM,EVM从35%降低至2.9%。所有测试结果均满足小于3%的项目指标,证明算法对高阶调制具有很强的鲁棒性。
import numpy as np from scipy.signal import lfilter class FarrowResampler: def __init__(self, rate_ratio): self.ratio = rate_ratio self.nco_phase = 0.0 self.buffer = np.zeros(4, dtype=complex) self.coeff = np.array([[-1/6., 1/2., -1/3., 1/6.], [ 0., 0., 1., 0. ], [ 0., 1/2., 1/2., 0. ], [ 1/6., -1/2., 1/3., -1/6.]]) def farrow_interp(self, mu): y = np.zeros(2, dtype=complex) for i in range(4): mu_pow = [mu**3, mu**2, mu, 1] h = np.sum(self.coeff * np.array(mu_pow)[:, None], axis=0) y += self.buffer[i] * h[i] return y def resample(self, x_in): x_out = [] x_ext = np.concatenate((np.zeros(2, dtype=complex), x_in, np.zeros(2, dtype=complex))) idx = 0 while idx < len(x_in): self.buffer = x_ext[idx:idx+4] while self.nco_phase < 1.0: mu = self.nco_phase y = self.farrow_interp(mu) x_out.append(y) self.nco_phase += 1.0 / self.ratio self.nco_phase -= 1.0 idx += 1 return np.array(x_out) class CarrierSyncPFD_DD: def __init__(self, loop_bw=0.01, zeta=0.707): self.phase = 0.0 self.freq = 0.0 self.Kp = 2 * zeta * loop_bw self.Ki = loop_bw**2 def pfd_detector(self, y, dec_prev, dec_curr): # phase frequency detector based on decision phase_err = np.angle(y * np.conj(dec_curr)) freq_err = np.angle(dec_curr * np.conj(dec_prev)) return phase_err + 0.5 * freq_err def update(self, err): self.freq += self.Ki * err self.phase += self.Kp * err + self.freq return self.phase def correct(self, y): return y * np.exp(-1j * self.phase) class TimingGardnerModified: def __init__(self, alpha=0.01, beta=0.002): self.strobe_phase = 0.0 self.loop_filter = (alpha, beta) self.tau = 0.0 def error_detector(self, y_mid, y_prev, y_curr): # y_mid is sample at half symbol offset err = np.real(y_mid) * (np.real(y_curr) - np.real(y_prev)) err += np.imag(y_mid) * (np.imag(y_curr) - np.imag(y_prev)) return err def update_tau(self, err): self.tau += self.loop_filter[1] * err self.strobe_phase += self.loop_filter[0] * err + self.tau return self.strobe_phase