4. 基于二次多项式插值的峰值定位

任务说明

布里渊光时域反射(BOTDR)系统中,通过洛伦兹或高斯拟合可估计布里渊频移,但逐点拟合计算量大。本案例实现基于二次多项式插值的峰值定位方法:先对离散布里渊谱进行粗搜索找到最大幅值点,再利用该点及其左右邻点构造二次多项式,通过解析求导获得亚像素级峰值位置,从而在少量采样点下提高频移分辨率。

核心算法

设离散布里渊谱为 \((x_i, y_i)\),其中 \(x_i\) 为频率,\(y_i\) 为幅值。粗搜索得到最大值点索引 \(k\),取三点 \((x_{k-1}, y_{k-1})\)、\((x_k, y_k)\)、\((x_{k+1}, y_{k+1})\)。构造二次多项式 \(p(x) = a x^2 + b x + c\),其峰值位置为:

\(x_{peak} = x_k + \dfrac{\Delta x}{2} \cdot \dfrac{y_{k-1} - y_{k+1}}{y_{k-1} - 2y_k + y_{k+1}}\)

其中 \(\Delta x = x_{k+1} - x_k\) 为频率采样间隔。该式由三点插值二次函数求导为零直接导出,无需矩阵求逆。

代码实现


import numpy as np

def quadratic_peak_interpolation(freq, amp):
    """
    基于二次多项式插值的峰值定位
    参数:
        freq: 1D array, 频率轴 (GHz)
        amp:  1D array, 对应幅值 (任意线性单位)
    返回:
        peak_freq: float, 亚像素峰值频率 (GHz)
        peak_idx:  int,   粗搜索最大值索引
    """
    if len(freq) != len(amp) or len(freq) < 3:
        raise ValueError("freq 和 amp 长度需相等且至少为3")
    
    # 1. 粗搜索:最大幅值点
    k = int(np.argmax(amp))
    
    # 边界处理:若最大值在端点,无法插值,直接返回该点
    if k == 0 or k == len(freq) - 1:
        return freq[k], k
    
    # 2. 取三点
    x0, x1, x2 = freq[k-1], freq[k], freq[k+1]
    y0, y1, y2 = amp[k-1], amp[k], amp[k+1]
    
    # 3. 二次插值峰值偏移量(以 x1 为参考)
    dx = x2 - x1  # 等间隔采样时 = x1 - x0
    denom = y0 - 2*y1 + y2
    
    if abs(denom) < 1e-12:
        # 退化情况:三点共线或数值噪声,返回粗峰值
        return x1, k
    
    delta = 0.5 * dx * (y0 - y2) / denom
    
    # 4. 亚像素峰值位置
    peak_freq = x1 + delta
    return peak_freq, k

# ========== 示例:构造一个离散布里渊谱并定位 ==========
if __name__ == "__main__":
    # 真实布里渊频移设为 10.850 GHz
    true_peak = 10.850
    # 频率采样:间隔 5 MHz,覆盖 10.82 ~ 10.88 GHz
    freq = np.arange(10.820, 10.881, 0.005)
    
    # 洛伦兹型布里渊谱(线宽 30 MHz),加入少量噪声
    gamma = 0.030  # GHz
    amp = 1.0 / (1.0 + ((freq - true_peak) / gamma)**2)
    rng = np.random.default_rng(42)
    amp += rng.normal(0, 0.005, size=len(freq))
    
    # 粗搜索峰值(直接取最大点)
    coarse_idx = int(np.argmax(amp))
    coarse_freq = freq[coarse_idx]
    
    # 二次插值精定位
    peak_freq, peak_idx = quadratic_peak_interpolation(freq, amp)
    
    print(f"真实峰值:      {true_peak:.6f} GHz")
    print(f"粗搜索峰值:    {coarse_freq:.6f} GHz (索引 {coarse_idx})")
    print(f"插值精定位:    {peak_freq:.6f} GHz (索引 {peak_idx})")
    print(f"粗搜索误差:    {abs(coarse_freq - true_peak)*1e6:.1f} MHz")
    print(f"插值后误差:    {abs(peak_freq - true_peak)*1e6:.1f} MHz")

落地与验证

运行方式:将代码保存为 peak_interp.py,在装有 NumPy 的 Python 环境中执行 python peak_interp.py。

验证方法:观察输出中“插值后误差”是否显著小于“粗搜索误差”。由于频率采样间隔为 5 MHz,粗搜索最大误差理论上可达 ±2.5 MHz;二次插值后误差通常可降至亚 MHz 量级。若代码正确,插值结果应更接近真实值 10.850 GHz。

判定标准:程序无异常退出,且插值后误差小于粗搜索误差即视为通过。注意:由于示例中加入了随机噪声,每次运行的具体误差数值会略有波动,但插值精度提升的趋势应稳定成立。

二次多项式插值峰值定位流程 离散布里渊谱 argmax 粗搜索 找到最大点 k 取 k-1, k, k+1 三点 二次多项式插值 x_peak = x_k + (Δx/2)·(y₋₁−y₊₁)/(y₋₁−2y_k+y₊₁) 解析求导 → 亚像素峰值 精定位频移值 分辨率突破频率采样间隔限制 边界处理 若 k=0 或 k=N-1 直接返回粗峰值 退化:分母≈0时 返回粗峰值 Δx:频率采样间隔(本案例 5 MHz)