各种光通信方面的耦合算法

By admin at 2026-02-24 • 0人收藏 • 129人看过

image.png

光纤耦合对准本质是一个无导数的峰值搜索问题

github搜索关键词:

fiber alignment algorithm
optical coupling alignment
photonic alignment hill climbing
active alignment optical
fiber optic peak search
optical power optimization
gradient search fiber coupling
  1. 光栅扫描(Raster Scan)— 粗对准

扫描路径:

  1. → → → → → →

  2. ← ← ← ← ← ←

  3. → → → → → →

  4. ← ← ← ← ← ←

// 伪代码
for (y = yMin; y <= yMax; y += stepY)
{
    for (x = xMin; x <= xMax; x += stepX)
    {
        MoveTo(x, y);
        power = ReadPower();
        if (power > maxPower)
        {
            maxPower = power;
            bestX = x; bestY = y;
        }
    }
}
MoveTo(bestX, bestY);
2. 螺旋扫描(Spiral Scan)— 粗对准
用途:从中心向外搜索,比光栅更高效
特点:中心区域密集,越远越稀疏

// GitHub 搜索: "spiral scan alignment"
for (int ring = 0; ring < maxRings; ring++)
{
    double radius = ring * step;
    int pointsInRing = Math.Max(1, (int)(2 * Math.PI * radius / step));
    for (int p = 0; p < pointsInRing; p++)
    {
        double angle = 2.0 * Math.PI * p / pointsInRing;
        double x = centerX + radius * Math.Cos(angle);
        double y = centerY + radius * Math.Sin(angle);
        MoveTo(x, y);
        power = ReadPower();
        if (power > maxPower) { /* 更新最大值 */ }
    }
}
3.梯度搜索(Gradient Search)— 细对准 ⭐推荐
用途:多轴同时优化,收敛快
原理:通过小扰动估计梯度方向,沿梯度上升

这是业界最常用的细对准算法
// GitHub 搜索: "gradient search optical alignment"
// 核心思想:
public static void GradientSearch(UInt16[] axes, int channel, double step)
{
    while (!converged)
    {
        double basePower = PM.getPowerEx(channel);
        double[] gradient = new double[axes.Length];

        // 估计各轴梯度
        for (int i = 0; i < axes.Length; i++)
        {
            USBMove.pMoveRef(axes[i], +step);  // 正扰动
            WaitAndSettle(axes[i]);
            double pPlus = PM.getPowerEx(channel);

            USBMove.pMoveRef(axes[i], -2 * step);  // 负扰动
            WaitAndSettle(axes[i]);
            double pMinus = PM.getPowerEx(channel);

            USBMove.pMoveRef(axes[i], +step);  // 回原点
            WaitAndSettle(axes[i]);

            gradient[i] = (pPlus - pMinus) / (2 * step);
        }

        // 沿梯度方向移动
        double norm = Math.Sqrt(gradient.Sum(g => g * g));
        if (norm < threshold) break;  // 收敛

        for (int i = 0; i < axes.Length; i++)
        {
            double move = learningRate * gradient[i] / norm * step;
            USBMove.pMoveRef(axes[i], move);
        }
        WaitAll(axes);
    }
}
4. Nelder-Mead 单纯形法 — 细对准 ⭐⭐工业常用
用途:多轴无导数优化,对噪声有一定鲁棒性
特点:不需要计算梯度,用N+1个点构成单纯形

GitHub 搜索: "nelder mead optimization" (通用库很多)
5.高斯拟合法 — 细对准
原理:利用光耦合效率通常呈高斯分布的特点
步骤:
  1. 扫描若干点
  2. 拟合高斯曲线
  3. 直接移动到拟合的峰值位置

优势:理论上只需要少量采样点即可定位峰值
// 采集数据后拟合
// P(x) = A * exp(-(x-μ)² / (2σ²))
// 取对数线性化:ln(P) = ln(A) - (x-μ)²/(2σ²)
// 最少3个点即可求解
6. 抖动锁定(Dither Alignment)— 实时追踪
原理:在最优位置附加微小正弦抖动,
     通过锁相检测判断偏移方向

类似PID控制,用于长期稳定保持

GitHub 搜索: "dither alignment lock-in"

image.png

image.png

主要可以增强的方向是:① 多轴联合优化(梯度法/Simplex);② 多轮步长递减;③ 噪声鲁棒性。GitHub 上搜 "optical alignment" + "hill climbing" 或 "gradient search" 可以找到参考实现。

1 个回复 | 最后更新于 2026-02-25
2026-02-25   #1
/// <summary>
/// Nelder-Mead 单纯形法 - 光耦合对准专用
/// 目标:最大化光功率(注意:标准NM是求最小,这里取反)
/// </summary>
public class NelderMeadAligner
{
    // ========== 标准 NM 系数 ==========
    private const double Alpha = 1.0;   // 反射系数
    private const double Gamma = 2.0;   // 扩展系数
    private const double Rho   = 0.5;   // 收缩系数
    private const double Sigma = 0.5;   // 缩小系数

    // ========== 收敛判据 ==========
    private const double PowerTolerance = 0.01;    // 功率收敛阈值 (dB)
    private const double PositionTolerance = 0.01; // 位置收敛阈值 (μm)
    private const int    MaxIterations = 200;

    /// <summary>
    /// 单纯形顶点:位置 + 对应的功率值
    /// </summary>
    private class Vertex
    {
        public double[] Position;  // 各轴位置
        public double Power;       // 该位置的光功率

        public Vertex(int dims)
        {
            Position = new double[dims];
            Power = double.MinValue;
        }

        public Vertex Clone()
        {
            var v = new Vertex(Position.Length);
            Array.Copy(Position, v.Position, Position.Length);
            v.Power = Power;
            return v;
        }
    }

    private readonly UInt16[] _axes;
    private readonly int _channel;
    private readonly int _dims;        // 维度数 = 轴数

    public NelderMeadAligner(UInt16[] axes, int channel)
    {
        _axes = axes;
        _channel = channel;
        _dims = axes.Length;
    }

    /// <summary>
    /// 执行 Nelder-Mead 对准
    /// </summary>
    /// <param name="initialStep">初始单纯形大小(各轴步长)</param>
    /// <returns>最优位置的功率值</returns>
    public double Align(double initialStep = 1.0)
    {
        // ======== ① 初始化单纯形 ========
        var simplex = InitializeSimplex(initialStep);

        // ======== 主循环 ========
        for (int iter = 0; iter < MaxIterations; iter++)
        {
            // ② 按功率降序排列(我们要最大化)
            Array.Sort(simplex, (a, b) => b.Power.CompareTo(a.Power));
            // simplex[0] = 最好, simplex[N] = 最差

            Vertex best   = simplex[0];
            Vertex worst  = simplex[_dims];
            Vertex secWorst = simplex[_dims - 1];

            // 检查收敛
            if (CheckConvergence(simplex))
            {
                Console.WriteLine($"NM 收敛于第 {iter} 次迭代, 功率={best.Power:F3} dBm");
                break;
            }

            // ③ 计算质心(排除最差点)
            double[] centroid = CalcCentroid(simplex);

            // ④ 反射
            Vertex reflected = CreateVertex(centroid, worst.Position, Alpha);
            MoveAndMeasure(reflected);

            if (reflected.Power > best.Power)
            {
                // 反射点是新的最好 → 尝试扩展
                Vertex expanded = CreateVertex(centroid, reflected.Position, Gamma, isMirror: false);
                MoveAndMeasure(expanded);

                simplex[_dims] = (expanded.Power > reflected.Power) ? expanded : reflected;
            }
            else if (reflected.Power > secWorst.Power)
            {
                // 反射点比次差好 → 接受反射
                simplex[_dims] = reflected;
            }
            else
            {
                // 反射点不够好 → 收缩
                bool useOutside = reflected.Power > worst.Power;
                Vertex target = useOutside ? reflected : worst;

                Vertex contracted = new Vertex(_dims);
                for (int i = 0; i < _dims; i++)
                {
                    contracted.Position[i] = centroid[i] + Rho * (target.Position[i] - centroid[i]);
                }
                MoveAndMeasure(contracted);

                if (contracted.Power > target.Power)
                {
                    simplex[_dims] = contracted;
                }
                else
                {
                    // ⑦ 收缩无效 → 整体缩小向最好点
                    ShrinkSimplex(simplex);
                }
            }
        }

        // 移动到最优位置
        Array.Sort(simplex, (a, b) => b.Power.CompareTo(a.Power));
        MoveToPosition(simplex[0].Position);

        return simplex[0].Power;
    }

    /// <summary>
    /// 初始化单纯形:当前位置 + 各轴偏移一步的位置
    /// </summary>
    private Vertex[] InitializeSimplex(double step)
    {
        var simplex = new Vertex[_dims + 1];

        // 第一个顶点 = 当前位置
        simplex[0] = new Vertex(_dims);
        for (int i = 0; i < _dims; i++)
        {
            simplex[0].Position[i] = USBMove.getPos(_axes[i]);
        }
        simplex[0].Power = PM.getPowerEx(_channel);

        // 其余顶点 = 在各轴方向偏移 step
        for (int j = 0; j < _dims; j++)
        {
            simplex[j + 1] = simplex[0].Clone();
            simplex[j + 1].Position[j] += step;
            MoveAndMeasure(simplex[j + 1]);
        }

        return simplex;
    }

    /// <summary>
    /// 创建新顶点(反射/扩展操作)
    /// </summary>
    /// <param name="centroid">质心</param>
    /// <param name="target">目标点(最差点 或 反射点)</param>
    /// <param name="coeff">系数(α 或 γ)</param>
    /// <param name="isMirror">true=反射(从target反向), false=延伸(从质心向target)</param>
    private Vertex CreateVertex(double[] centroid, double[] target, double coeff, bool isMirror = true)
    {
        var v = new Vertex(_dims);
        for (int i = 0; i < _dims; i++)
        {
            if (isMirror)
                v.Position[i] = centroid[i] + coeff * (centroid[i] - target[i]);
            else
                v.Position[i] = centroid[i] + coeff * (target[i] - centroid[i]);
        }
        return v;
    }

    /// <summary>
    /// 计算质心(排除最后一个最差点)
    /// </summary>
    private double[] CalcCentroid(Vertex[] simplex)
    {
        double[] centroid = new double[_dims];
        for (int i = 0; i < _dims; i++) // 遍历各轴
        {
            double sum = 0;
            for (int j = 0; j < _dims; j++) // 遍历除最差外的顶点
            {
                sum += simplex[j].Position[i];
            }
            centroid[i] = sum / _dims;
        }
        return centroid;
    }

    /// <summary>
    /// 整体向最好点缩小
    /// </summary>
    private void ShrinkSimplex(Vertex[] simplex)
    {
        Vertex best = simplex[0];
        for (int i = 1; i <= _dims; i++)
        {
            for (int j = 0; j < _dims; j++)
            {
                simplex[i].Position[j] = best.Position[j] 
                    + Sigma * (simplex[i].Position[j] - best.Position[j]);
            }
            MoveAndMeasure(simplex[i]);
        }
    }

    /// <summary>
    /// 检查收敛:所有顶点的功率和位置差异都很小
    /// </summary>
    private bool CheckConvergence(Vertex[] simplex)
    {
        // 功率收敛
        double maxP = simplex[0].Power;
        double minP = simplex[_dims].Power;
        if (maxP - minP > PowerTolerance)
            return false;

        // 位置收敛
        for (int j = 0; j < _dims; j++)
        {
            double maxPos = double.MinValue, minPos = double.MaxValue;
            for (int i = 0; i <= _dims; i++)
            {
                maxPos = Math.Max(maxPos, simplex[i].Position[j]);
                minPos = Math.Min(minPos, simplex[i].Position[j]);
            }
            if (maxPos - minPos > PositionTolerance)
                return false;
        }

        return true;
    }

    /// <summary>
    /// 移动到指定位置并测量功率
    /// </summary>
    private void MoveAndMeasure(Vertex v)
    {
        MoveToPosition(v.Position);
        Thread.Sleep(5); // 稳定等待
        v.Power = PM.getPowerEx(_channel);
    }

    /// <summary>
    /// 多轴同时移动到目标位置
    /// </summary>
    private void MoveToPosition(double[] position)
    {
        for (int i = 0; i < _dims; i++)
        {
            USBMove.pMoveAbs(_axes[i], position[i]);
        }
        // 等待所有轴停止
        for (int i = 0; i < _dims; i++)
        {
            USBMove.waitStop(_axes[i]);
        }
    }
}



调回用示例
// ========== 实际使用 ==========

// 2轴对准(X + Y)
var aligner2D = new NelderMeadAligner(
    axes: new UInt16[] { 0, 1 },    // X轴=0, Y轴=1
    channel: 1
);
double bestPower2D = aligner2D.Align(initialStep: 1.0);

// 3轴对准(X + Y + Z)
var aligner3D = new NelderMeadAligner(
    axes: new UInt16[] { 0, 1, 2 }, // X=0, Y=1, Z=2
    channel: 1
);
double bestPower3D = aligner3D.Align(initialStep: 2.0);

// 多阶段组合
double[] steps = { 5.0, 1.0, 0.2 };
foreach (var step in steps)
{
    var aligner = new NelderMeadAligner(axes, channel);
    aligner.Align(initialStep: step);
}


登录后方可回帖

登 录
信息栏
本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...