4. 区域法波前重构之Fried模型

任务说明

本案例实现基于Fried模型的区域法波前重构。输入为离散采样点上的波前斜率(x方向与y方向梯度),输出为重构得到的波前相位分布。Fried模型假设斜率采样点位于网格单元中心,而重构相位定义在网格节点上,相邻四个斜率点围成一个相位节点,通过最小二乘拟合建立斜率与相位之间的线性关系。

算法原理

设波前相位定义在(M+1)×(N+1)的网格节点上,斜率测量点位于每个网格单元中心,共M×N个。对于节点(i,j),其周围四个单元中心的x斜率平均值与该节点x方向相位差分相关,y方向同理。构建稀疏矩阵方程Ax = b,其中A为斜率-相位关系矩阵,b为斜率测量值,x为待求相位。由于A秩亏(整体平移不变),需添加约束固定一个参考节点相位为零,再通过稀疏最小二乘求解。

相位节点 φ(i,j) 斜率采样点 (sx, sy) Fried模型:斜率位于单元中心,相位位于网格节点

代码实现


import numpy as np
from scipy.sparse import lil_matrix
from scipy.sparse.linalg import lsqr

def fried_reconstructor(sx, sy, dx=1.0, dy=1.0):
    """
    Fried模型区域法波前重构
    参数:
        sx: 二维数组 (M, N),每个单元中心的x方向斜率
        sy: 二维数组 (M, N),每个单元中心的y方向斜率
        dx, dy: 网格间距
    返回:
        phi: (M+1, N+1) 数组,重构的波前相位
    """
    M, N = sx.shape
    num_nodes = (M + 1) * (N + 1)
    num_slopes = 2 * M * N

    # 构建稀疏矩阵 A (num_slopes+1, num_nodes)
    A = lil_matrix((num_slopes + 1, num_nodes))
    b = np.zeros(num_slopes + 1)

    row = 0
    # x方向斜率方程: 节点(i,j)与(i,j+1)的差分
    for i in range(M):
        for j in range(N):
            n1 = i * (N + 1) + j          # 节点(i,j)
            n2 = i * (N + 1) + j + 1      # 节点(i,j+1)
            A[row, n1] = -1.0 / dx
            A[row, n2] = 1.0 / dx
            b[row] = sx[i, j]
            row += 1

    # y方向斜率方程: 节点(i,j)与(i+1,j)的差分
    for i in range(M):
        for j in range(N):
            n1 = i * (N + 1) + j          # 节点(i,j)
            n2 = (i + 1) * (N + 1) + j    # 节点(i+1,j)
            A[row, n1] = -1.0 / dy
            A[row, n2] = 1.0 / dy
            b[row] = sy[i, j]
            row += 1

    # 固定参考节点: 左上角相位 = 0
    A[row, 0] = 1.0
    b[row] = 0.0

    # 最小二乘求解
    A = A.tocsr()
    phi_flat, _ = lsqr(A, b, iter_lim=1000, atol=1e-10, btol=1e-10)[:2]
    phi = phi_flat.reshape((M + 1, N + 1))
    return phi

# 示例:构造已知相位并生成斜率,验证重构精度
if __name__ == "__main__":
    M, N = 8, 8
    x = np.linspace(0, 1, N + 1)
    y = np.linspace(0, 1, M + 1)
    X, Y = np.meshgrid(x, y)

    # 真实相位(用于生成斜率)
    phi_true = 0.5 * X**2 + 0.3 * Y**2 + 0.2 * X * Y

    # 计算单元中心坐标
    xc = (x[:-1] + x[1:]) / 2
    yc = (y[:-1] + y[1:]) / 2
    Xc, Yc = np.meshgrid(xc, yc)

    # 解析求导得到斜率
    sx_true = Xc + 0.2 * Yc
    sy_true = Yc + 0.2 * Xc

    # 重构
    phi_rec = fried_reconstructor(sx_true, sy_true, dx=x[1]-x[0], dy=y[1]-y[0])

    # 去除整体平移后比较
    phi_rec -= phi_rec[0, 0]
    phi_true_ref = phi_true - phi_true[0, 0]
    error = np.max(np.abs(phi_rec - phi_true_ref))
    print(f"最大重构误差: {error:.2e}")

运行与验证

运行上述代码需要安装numpy和scipy。执行后程序会构造一个二次型相位分布,解析计算其斜率作为输入,调用fried_reconstructor完成重构,并输出最大误差。由于斜率由解析函数精确生成且无噪声,重构结果应接近机器精度(误差在1e-10量级),这验证了重构矩阵构建和求解过程的正确性。若误差显著大于1e-8,说明矩阵构建或约束添加存在错误。

实际使用时,将波前传感器测得的x、y方向斜率分别填入sx和sy二维数组即可。注意斜率数组维度为(M,N),对应M行N列个采样单元;重构相位维度自动为(M+1,N+1)。若斜率存在噪声,重构误差会相应增大,这是最小二乘方法的正常特性。