各种光通信方面的耦合算法
By
admin
at 2026-02-24 • 0人收藏 • 129人看过

光纤耦合对准本质是一个无导数的峰值搜索问题
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
光栅扫描(Raster Scan)— 粗对准
扫描路径:
→ → → → → →
← ← ← ← ← ←
→ → → → → →
← ← ← ← ← ←
// 伪代码
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"


主要可以增强的方向是:① 多轴联合优化(梯度法/Simplex);② 多轮步长递减;③ 噪声鲁棒性。GitHub 上搜 "optical alignment" + "hill climbing" 或 "gradient search" 可以找到参考实现。
1 个回复 | 最后更新于 2026-02-25
登录后方可回帖
/// <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); }