1. 项目概述与核心需求解析
1.1 这个标题到底在说什么
先别被这一长串名字吓住,拆开来看其实就三层东西:不完全信息、Epsilon纳什均衡、航天器末端追逃博弈。再加上括号里的两个关键词:EKF参数估计和自适应博弈。这套组合说白了就是——在双方都不完全掌握对方状态信息的条件下,让追捕者和逃逸者各自算出一套“差不多最优”的机动策略,而且这套策略要用Matlab跑出来的仿真去验证。
先说“不完全信息”。真实太空环境里,你不可能拿雷达把对方的速度、加速度、姿态角全部测准,测量噪声、通信延迟、传感器丢包都是常态。所以博弈双方手里的状态估计都是有误差的。传统追逃博弈大多假设完全信息,即我知道你的位置速度你也知道我的,这在工程上不现实。这个项目把信息不完备作为前提,这是它区别于一般追逃博弈复现文章的第一大看点。
然后是“Epsilon纳什均衡”。标准纳什均衡要求每个参与者的策略都是对对手策略的最优响应,但在不完全信息场景下,你连对手的真实类型都不确定,很难保证严格最优。Epsilon纳什均衡退了一步:允许每个参与者的收益与最优收益之差不超过一个很小的正数epsilon。这个概念非常适合工程落地,因为现实控制本身就有容差,没必要追求理论上的绝对最优。
最后“末端追逃”限定了场景。不是远程巡航那种长时间博弈,而是航天器已经接近目标,进入最后几百公里甚至几十公里的博弈段。这个阶段燃料宝贵、时间紧迫、机动能力受限,策略必须在短时间内快速收敛。项目里结合自适应博弈,意思就是随着估计误差的变化,实时调整epsilon阈值或者策略更新步长,让算法在不同阶段都有可接受的性能。
1.2 适合谁看、能解决什么问题
如果你正在做航天器交会对接的对抗场景、或者研究多智能体博弈控制,这个项目能提供一个非常完整的参考闭环。它覆盖了状态估计(EKF)、博弈论建模(Epsilon纳什均衡)、控制策略更新(自适应调节)三个模块,每个模块都有Matlab实现,拼接起来就是一个端到端仿真系统。
如果你是刚接触追逃博弈的学生,这个项目的价值在于让你看到一个“不完全信息 + 博弈均衡”的组合是怎么从理论走向仿真的。严谨点说,这篇博文不是论文讲解,而是一次完整的复现记录:从模型建立、参数设计、EKF融合、迭代求均衡到最终结果分析,全部走一遍。
工程上最头疼的其实是两个问题:EKF发散、均衡迭代不收敛。这两点我在实现过程中都踩过坑,后文会专门展开讲。所以这篇文章适合谁看?适合那些已经读过博弈论入门教材、会用Matlab写基本仿真、但不知道怎么把理论模型落到代码里的同学。零基础也没关系,我会把前置知识打散揉碎讲清楚。
2. 模型构建与核心原理拆解
2.1 末端追逃博弈的空间状态模型
末端追逃段的动力学模型,几乎都建立在C-W方程(Clohessy-Wiltshire)或其改进形式上。C-W方程描述的是追逐航天器相对于目标航天器在近圆轨道上的相对运动:
[ \begin{aligned} \ddot{x} &= 3\omega^2 x + 2\omega \dot{y} + a_x \ \ddot{y} &= -2\omega \dot{x} + a_y \ \ddot{z} &= -\omega^2 z + a_z \end{aligned} ]
其中,(\omega) 是目标轨道角速度,(a_x, a_y, a_z) 分别代表追捕航天器施加的推力加速度,也就是控制量。
在这个模型里,系统的状态向量通常取 (\mathbf{x} = [x, y, z, \dot{x}, \dot{y}, \dot{z}]^T)。相对位置和相对速度共六个状态量。为什么不用绝对轨道根数?因为在末端博弈段,我们关心的是两个航天器的相对位置关系,绝对轨道根数数值很大,直接做差分运算容易产生数值精度问题,仿真里很容易因为浮点误差导致状态跳变。
我复现时用的是离散化后的状态方程:
[ \mathbf{x}_{k+1} = \mathbf{F} \mathbf{x}_k + \mathbf{G} \mathbf{u}_k + \mathbf{w}_k ]
其中 (\mathbf{F}) 是状态转移矩阵,由C-W方程的解析解推导得到,(\mathbf{G}) 是控制输入矩阵,(\mathbf{w}_k) 是过程噪声,模拟未建模扰动。具体推导过程在很多相对导航教材里都有,这里不占用篇幅,只提醒一点:状态转移矩阵的推导一定要保留完整的正弦余弦项,不要做小角度近似。末端博弈阶段相对距离不大,但速度可能不小,小角度近似会在仿真后期累积出明显偏差。
追逃双方各有一套这样的状态方程。追捕者用 (u_p) 表示自己的控制,逃逸者用 (u_e) 表示自己的控制。两者的目标函数同时包含两个指标:末端脱靶量和对冲机动燃料消耗。追捕者希望末端相对距离越小越好,逃逸者希望越大越好,于是构成了零和博弈。
2.2 不完全信息下的EKF状态估计
说到不完全信息,我见过很多模拟方案是这样处理的:在真实状态上直接加一个固定方差的高斯噪声,然后假设双方都能观测到对方的含噪位置。这种做法虽然简单,但等于绕过了状态估计这一核心环节,导致EKF成了一种摆设。既然是复现,就必须把EKF真正用起来。
系统可观测量通常设置为相对位置测量值:
[ \mathbf{z}_k = \mathbf{H} \mathbf{x}_k + \mathbf{v}_k ]
其中 (\mathbf{H} = [\mathbf{I}{3\times3}, \mathbf{0}{3\times3}]),观测矩阵只取了位置分量。(\mathbf{v}_k) 是观测噪声,工程上对应雷达测距测速误差。
EKF的预测步和更新步我就不赘述公式了,重点说两个我实际遇到并且严重影响仿真的问题:
第一个问题是协方差矩阵失去正定性。在长时间迭代仿真中,因为数值误差,状态协方差矩阵 (\mathbf{P}) 可能出现非对称甚至非正定情况,直接导致卡尔曼增益计算异常。解决办法有两个:一种是每个更新步之后手动做对称化处理,即 (\mathbf{P} = (\mathbf{P} + \mathbf{P}^T)/2);另一种是使用Joseph形式的协方差更新公式,数值稳定性更好。我最后用的是后者,实测仿真5000步都没有出现发散。
第二个问题是观测噪声方差与实际不一致。仿真初期我把观测噪声方差设得很小,导致EKF过于信任测量值,状态估计噪声反而变大。这在滤波理论里叫“不一致估计”,简单说就是滤波器自己以为自己很准,实际上误差很大。解决办法是在线实时估计观测噪声方差,一般用创新序列的滑动窗口统计来更新。
EKF输出的是双方各自对对方状态的估计值。注意,这里双方各自对自己状态的估计是精确的(在仿真里相当于已知自己真实状态),但对对手状态的估计是带误差的。这种处理方式符合航天工程实际——每架航天器都能通过惯性导航获得高精度自状态,但对目标只能通过传感器测量估计。
2.3 Epsilon纳什均衡的定义与求解思路
标准纳什均衡在完全信息博弈里定义很清晰:每个参与者的策略都是对手策略下的最优响应。但在不完全信息下,每个人只能基于自己的估计来选策略,估计误差引入的不确定性导致严格最优策略未必存在,或者即使存在也未必稳定。
Epsilon纳什均衡放松了这个条件:假设追捕者采用策略 (s_p^),逃逸者采用策略 (s_e^),如果对任意追捕者策略 (s_p) 都有
[ J_p(s_p^, s_e^) \geq \sup_{s_p} J_p(s_p, s_e^*) - \epsilon ]
且对任意逃逸者策略 (s_e) 都有
[ J_e(s_p^, s_e^) \geq \sup_{s_e} J_e(s_p^*, s_e) - \epsilon ]
那么这个策略组合 ((s_p^, s_e^)) 就是一个epsilon纳什均衡。通俗理解就是:双方都不愿意付出超过epsilon的代价去单方面改变策略。epsilon越小,均衡越接近严格纳什均衡,但计算代价也越大。
实际求解时,我采用的是迭代最优响应法。基本流程是:
- 初始化双方策略(比如初始为直线飞行)
- 给定逃逸者当前策略,求追捕者的最优响应策略
- 固定追捕者的响应策略,再求逃逸者的最优响应策略
- 重复步骤2和3,直到策略变化量小于阈值
这个方法的收敛性在理论上不是绝对保证的,但在末端追逃这种短时域、强对抗场景里,实测收敛效果不错。关键在于要把策略参数化,我这里用多项式参数化控制加速度曲线,即
[ u_p(t) = a_{p0} + a_{p1} t + a_{p2} t^2 ]
把连续控制问题转化为有限维参数寻优问题,然后用粒子群优化算法(PSO)求解。这样大大降低了计算复杂度,也让迭代最优响应变得可行。
2.4 自适应博弈的调节机制
自适应博弈在这个项目里的作用,是让epsilon阈值和策略更新步长随状态估计不确定性动态变化。思路其实很直接:当EKF估计误差协方差较大时,意味着双方对对手状态的判断都不准,此时强行追求小epsilon没有意义,反而容易导致迭代震荡。反之,当估计精度较高时,可以适当缩小epsilon,让策略更接近严格纳什均衡。
我在仿真里设置了一个简单的自适应规则:
[ \epsilon(k) = \epsilon_{\min} + (\epsilon_{\max} - \epsilon_{\min}) \cdot \frac{\text{tr}(\mathbf{P}{k})}{\text{tr}(\mathbf{P}{\max})} ]
其中 (\text{tr}(\mathbf{P}k)) 是当前估计误差协方差的迹,代表总的不确定性大小。(\text{tr}(\mathbf{P}{\max})) 是预设的最大不确定度,用来归一化。这个式子的含义很直观:越不确定,epsilon越大,容许的策略偏差越大,计算越快;越确定,epsilon越小,策略越精细。
另一处自适应是策略更新步长。每次迭代最优响应时,我不直接把新算出的策略替换旧策略,而是做一个凸组合:
[ s_{new} = (1 - \alpha) s_{old} + \alpha s_{candidate} ]
其中 (\alpha) 是学习率。初始阶段为了让策略快速演化,(\alpha) 设得较大,比如0.7;当策略变化率降低时,逐渐减小 (\alpha) 到0.3。这样既保证了前期探索速度,又避免后期在最优策略附近震荡。
3. 仿真流程与Matlab实现细节
3.1 总体仿真架构
整个Matlab工程我按模块划分了四个脚本文件:
main_tracking_evasion.m:主程序,负责初始化参数、调度整个仿真循环ekf_estimator.m:EKF滤波函数,输入测量值和上一时刻状态估计,输出当前状态估计和协方差矩阵cww_models.m:C-W方程的状态转移矩阵和控制矩阵构建函数nash_optimization.m:迭代最优响应求解epsilon纳什均衡的核心函数
主程序仿真流程我用文字描述一下:先设置轨道参数(轨道高度、角速度)、初始相对状态、噪声参数;然后在每个仿真步内,先由真实状态生成测量值;双方分别用EKF对对手状态进行估计;将估计状态传递给博弈策略模块,求解当前时刻的近似最优控制;把控制量施加到真实状态方程上,推进到下一时刻;记录状态和策略数据用于后处理。
这个架构的好处是模块间耦合低。比如你想把EKF换成无迹卡尔曼滤波(UKF),只需要改ekf_estimator.m一个文件,主流程完全不用动。
3.2 关键参数设置与含义
参数设置直接影响仿真结果,我把关键参数按类别整理成表格,方便对照。
| 参数 | 取值 | 含义与说明 |
|---|---|---|
| 轨道角速度 (\omega) | 0.001 rad/s | 对应约500km轨道高度,周期约90分钟 |
| 仿真步长 | 1s | 末端博弈段总时长取300s |
| 初始相对位置 | [10km, 5km, 1km] | 追捕者位于逃逸者后方偏上 |
| 初始相对速度 | [-50m/s, 20m/s, 10m/s] | 追捕者相对速度指向逃逸者方向 |
| 过程噪声标准差 | 0.01 m/s² | 模拟推力误差和空间扰动 |
| 观测噪声标准差 | 20m(位置) | 对应雷达测距精度 |
| 推力加速度上限 | 0.5 m/s² | 以当前推进系统能力估算 |
| epsilon范围 | [0.01, 0.1] | 自适应调节区间 |
| PSO粒子数 | 50 | 每个最优化问题的粒子数 |
| PSO迭代次数 | 30 | 单次策略优化的最大迭代限制 |
轨道角速度0.001 rad/s这个参数很关键,它决定了C-W方程中交叉耦合项的强度。如果设置太小,比如1e-5 rad/s,模型退化成近直线运动,博弈特性就不明显了;如果太大,又不符合近地轨道实际。500km轨道高度是一个很典型的近地轨道场景,既贴近工程应用又能体现相对运动特征。
3.3 EKF实现的核心代码逻辑
EKF的Matlab代码逻辑不复杂,但需要注意几个细节。我在这里给出一个核心片段作为参考:
function [x_est, P_est] = ekf_estimator(x_pred, P_pred, z_meas, F, H, Q, R) % 预测步 % x_pred 和 P_pred 来自上一时刻的状态和协方差 % F 是状态转移矩阵,H 是观测矩阵,Q 是过程噪声协方差,R 是观测噪声协方差 % 先计算预测协方差 P_pred_update = F * P_pred * F' + Q; % 计算卡尔曼增益 S = H * P_pred_update * H' + R; K = P_pred_update * H' / S; % 更新步 innovation = z_meas - H * x_pred; x_est = x_pred + K * innovation; % 使用Joseph形式更新协方差,确保数值稳定性 I_KH = eye(size(K, 1)) - K * H; P_est = I_KH * P_pred_update * I_KH' + K * R * K'; end这里最关键的是最后一行Joseph形式协方差更新。很多教科书用的是简化形式 (\mathbf{P} = (\mathbf{I} - \mathbf{K}\mathbf{H})\mathbf{P}_{pred}),但这在数值上可能出现非对称问题。Joseph形式因为涉及矩阵乘法再相加,能保证结果矩阵一定是对称正定的,代价是计算量稍大。在末端博弈这种步长小、迭代次数多的场景,这点计算量增加完全可以接受。
另一个细节是观测矩阵 (\mathbf{H}) 的构建。由于状态是六维,观测是三维位置,所以 (\mathbf{H} = [\mathbf{I}_3, \mathbf{0}_3])。在Matlab里写:
H = [eye(3), zeros(3)];看起来简单,但要注意状态向量顺序。如果状态排列是[x, y, z, vx, vy, vz],那么H矩阵就是前三维取单位阵。如果状态排列顺序变了,H矩阵也要相应调整,否则滤波结果会完全错乱。
3.4 迭代最优响应的完整实现
迭代最优响应求解是项目的核心,我把它单独拿出来详细说。
function [s_p, s_e, epsilon_seq] = nash_optimization(x_est_p, x_est_e, params) % 输入是追捕者对状态的估计和逃逸者对状态的估计 % 输出是双方策略、以及每轮迭代的epsilon序列 % 初始化策略:全零表示不施加额外推力,即匀速直线运动 s_p = zeros(3, 3); % 每行是[ax, ay, az]多项式系数 s_e = zeros(3, 3); % 计算当前估计不确定度 trace_P = trace(params.P_current); epsilon = params.epsilon_min + (params.epsilon_max - params.epsilon_min) * ... trace_P / params.P_max_trace; % 迭代最优响应 max_iter = 10; for iter = 1:max_iter % 固定逃逸者策略,优化追捕者策略 [s_p_new, value_p] = pso_optimize(@(sp) payoff_pursuer(sp, s_e, x_est_p, x_est_e, params), ... params.pso_particles, params.pso_iters); % 固定追捕者策略,优化逃逸者策略 [s_e_new, value_e] = pso_optimize(@(se) payoff_evader(s_p, se, x_est_p, x_est_e, params), ... params.pso_particles, params.pso_iters); % 检查策略变化量是否小于阈值 if norm(s_p_new - s_p) + norm(s_e_new - s_e) < params.tol s_p = s_p_new; s_e = s_e_new; break; end % 自适应学习率:根据迭代次数调整 alpha = 0.7 - 0.4 * (iter / max_iter); s_p = (1 - alpha) * s_p + alpha * s_p_new; s_e = (1 - alpha) * s_e + alpha * s_e_new; end s_p = s_p_new; s_e = s_e_new; epsilon_seq = epsilon; end这个函数内部调用了PSO优化。PSO的目标函数是设计好的收益函数:追捕者的收益是末端脱靶量的负值加上燃料消耗惩罚,逃逸者收益则相反。
function cost = payoff_pursuer(sp, se, x_est_p, x_est_e, params) % 模拟当前策略下的末端状态 [x_terminal, fuel_p] = simulate_trajectory(x_est_p, sp, x_est_e, se, params); % 脱靶量:末端相对距离 miss_distance = norm(x_terminal(1:3)); % 追捕者希望脱靶量小、燃料少,所以收益取负值 cost = miss_distance / params.scale_miss + params.scale_fuel * fuel_p; end注意这里收益函数的设计是“成本最小化”。追捕者要让末端相对距离和燃料成本尽量小,所以成本函数直接就是两者的加权和。逃逸者的成本函数则是相对距离的负值加燃料成本。本质上这是一个最小化问题,PSO天然适合处理。
我把脱靶量除以一个尺度因子scale_miss,目的是让脱靶量和燃料消耗在数值量级上可比。末端脱靶量可能是几百米甚至几千米,燃料消耗则是米每二次方秒的积分,两个量级差太大会导致优化偏向其中一方。这个尺度因子的设置我建议根据仿真场景先跑一轮粗仿真,看两个指标的大致量级,再设定一个合适的归一化系数。
3.5 主程序的仿真循环组织
主程序结构其实不难,关键是把模块串起来。我把核心循环结构写出来:
for k = 1:total_steps % 1. 真实状态生成测量值 z_p = true_state_e(1:3) + measurement_noise_p; % 追捕者对逃逸者的位置测量 z_e = true_state_p(1:3) + measurement_noise_e; % 逃逸者对追捕者的位置测量 % 2. 双方各自运行EKF估计对手状态 [x_est_p, P_p] = ekf_estimator(x_est_p_pred, P_p_pred, z_p, F, H, Q, R); [x_est_e, P_e] = ekf_estimator(x_est_e_pred, P_e_pred, z_e, F, H, Q, R); % 3. 基于估计状态求解博弈策略 [s_p, s_e] = nash_optimization(x_est_p, x_est_e, params); % 4. 将策略对应的控制量施加到真实状态 u_p = s_p * [1; k*dt; (k*dt)^2]; % 计算当前时刻追捕者控制加速度 u_e = s_e * [1; k*dt; (k*dt)^2]; % 计算当前时刻逃逸者控制加速度 true_state_p = F * true_state_p + G * u_p + process_noise; true_state_e = F * true_state_e + G * u_e + process_noise; % 5. 记录数据 history_pos_p(:, k) = true_state_p(1:3); history_pos_e(:, k) = true_state_e(1:3); history_est_p(:, k) = x_est_p(1:3); history_est_e(:, k) = x_est_e(1:3); end这个循环结构每一步的先后顺序很重要。先测量再估计再博弈最后施加控制,是符合物理直觉的。如果在第3步和第4步之间的顺序颠倒,会导致控制量落后一个仿真步,虽然单步影响不大,但长期累积会造成策略与状态不同步。
另外,我强烈建议把过程噪声和测量噪声的随机种子固定下来,比如rng(42)。这样每次运行结果完全一致,方便调试和对比不同参数的效果。我项目前期没固定随机种子,结果每次运行轨迹都不一样,排查问题非常痛苦。
4. 常见问题与排查技巧实录
4.1 EKF发散问题
这是整个项目里最容易让人崩溃的问题,没有之一。我复现前期,EKF在仿真到第173步时突然发散,状态估计值直接跳到10的8次方量级。排查过程很曲折,最终锁定三个原因:
第一个原因是状态转移矩阵用了近似形式。早期我为了简单,把C-W方程离散化时忽略了部分耦合项,凑合着构建了F矩阵。结果在低轨道角速度下问题不大,但末端博弈段角速度设置到0.001,耦合项开始显著影响状态演化,EKF预测步的误差越积越大,直到发散。解决办法是老老实实推导完整的F矩阵,把哥氏力和离心项全保留。
第二个原因是前面提到的协方差非正定。虽然我在更新步用了Joseph形式,但预测步的 (\mathbf{F}\mathbf{P}\mathbf{F}^T + \mathbf{Q}) 这一步也可能因为数值误差产生非对称矩阵。解决办法是在预测之后、更新之前加一行对称化处理。
第三个原因比较隐蔽:观测噪声方差R设置过小。当EKF认为测量非常精准时,卡尔曼增益会趋向一个很大的值,导致状态估计剧烈跳变。我在仿真里把位置观测噪声标准差设成20m,但实际生成的测量噪声标准差因为随机种子问题变成了5m,滤波器和真实噪声不匹配。解决办法就是前面提到的滑动窗口实时估计R:
window_size = 50; if k > window_size innovations_window = innovations(k-window_size+1:k); R_estimated = var(innovations_window) - H * P_pred * H'; R_estimated = max(R_estimated, params.R_min); % 防止估计值为负 end这一段代码的思路是用近50步的创新序列方差估计当前测量噪声。因为创新序列包含了测量噪声和预测误差两部分,减去预测误差贡献后剩下的就是测量噪声方差。这个技巧在很多自适应滤波文献里有提到,实测非常管用。
4.2 均衡求解不收敛
迭代最优响应在部分初始条件下会出现策略来回跳变的情况。表现为第1轮算出策略A,第2轮算出策略B,第3轮又跳回A,形不成稳定均衡。
我排查后发现两个主要原因。第一个是学习率alpha固定导致。当alpha较大时,新策略对旧策略的替换幅度大,容易在两个候选策略之间来回振荡。解决办法就是自适应调节学习率,随着迭代次数增加逐渐减小alpha。我在代码里用的线性衰减公式,实测效果不错。
第二个原因是PSO优化精度不够。PSO本质上是个随机优化算法,50个粒子30次迭代并不能每次都找到全局最优。当每次调用PSO返回的策略存在随机波动时,迭代最优响应自然难以收敛。解决办法有两种:一是增加粒子数和迭代次数,二是对PSO的结果做平滑处理。我最后采用的是第二种,即把PSO返回的策略先和历史策略做加权平均再作为本轮结果,这样可以有效抑制随机波动。
补充一个判断收敛的实用技巧:不要只看策略参数的变化量,还要看收益值的变化。策略参数可能因为小范围扰动一直在变,但对应的收益值可能在0.1%以内波动,这种情况下其实已经可以认为收敛。所以我的收敛准则改成了收益变化小于阈值,而不是策略参数变化小于阈值。
4.3 脱靶量异常大
有一次仿真跑完,末端相对距离竟然有120km,比初始距离还大,显然是逃逸者占优太多。检查后发现,问题出在逃逸者的收益函数设计上。
逃逸者希望末端脱靶量大,但如果不加燃料约束,它的最优策略是全程满推力加速逃跑。这在实际工程中不合理,燃料总有耗尽的时候。我最初设计的逃逸者成本函数是:
cost_e = -miss_distance / params.scale_miss + params.scale_fuel * fuel_e;注意脱靶量前面带了负号,因为逃逸者要让脱靶量大,但成本函数是往小优化的。这个设计没问题,问题在scale_fuel设置太小,导致燃料消耗的惩罚权重远小于脱靶量收益,逃逸者相当于不心疼燃料。
解决办法是把燃料权重调高,同时增加一个约束:逃逸者整个博弈过程的累计控制冲量不能超过预设上限。在PSO里实现约束条件比较麻烦,我采取的做法是在收益函数里加一个惩罚项:
if fuel_e > params.fuel_limit cost_e = cost_e + 1e6 * (fuel_e - params.fuel_limit)^2; end用惩罚项处理约束是工程上常用做法。只要惩罚系数足够大,PSO自然会避开超出燃料限制的策略区域。
4.4 常见问题速查表
我把复现过程中遇到的高频问题整理成一张速查表,方便大家对照排查。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| EKF状态估计发散 | 状态转移矩阵省略耦合项 | 使用完整C-W方程解析解 |
| EKF估计噪声异常 | 观测噪声方差R不匹配 | 滑动窗口在线估计R |
| 协方差矩阵非正定 | 数值误差累积 | Joseph形式更新 + 对称化 |
| 迭代均衡不收敛 | 学习率固定过大 | 线性衰减学习率 |
| 脱靶量异常大 | 燃料惩罚权重过小 | 增大燃料权重 + 增加惩罚项 |
| 仿真轨迹跳动 | 随机种子未固定 | 设置rng固定种子 |
| 策略优化时间过长 | PSO粒子数和迭代数过大 | 在精度和时间间折中 |
| 博弈策略趋于一致 | epsilon范围过窄 | 放宽epsilon调节范围 |
5. 结果分析与扩展思考
5.1 仿真结果的关键观察点
仿真完成后,重点看三类图:相对轨迹图、状态估计误差曲线、策略演化曲线。
相对轨迹图是最直观的结果。一个典型的收敛场景是:追踪者的轨迹呈现螺旋逼近趋势,逃逸者则做反向机动拉开距离。但由于存在估计误差,两者的轨迹都带有一定随机抖动。如果只跑一次仿真,抖动看起来可能很混乱。我做分析时通常跑20次蒙特卡洛,取末端脱靶量的均值和标准差作为评价指标。
状态估计误差曲线能看出EKF性能。重点关注误差是否收敛、收敛后是否有偏置。我复现时发现,因为测量噪声是高斯噪声且EKF本身是线性最优滤波器,位置估计误差很快收敛到零均值附近,但速度估计误差收敛速度相对慢,需要大约50步左右才能稳定下来。
策略演化曲线反映自适应博弈的过程。通常在博弈初期策略变化剧烈,因为双方都在试探;接近末端时策略趋于稳定,因为剩余时间不足、机动空间变小。观察epsilon曲线可以看到自适应调节的效果:估计误差大的阶段,epsilon较大,策略相对粗糙但不至于震荡;估计误差收敛后,epsilon减小,策略精细化。
5.2 对比完全信息博弈的差异
为了突出不完全信息的影响,我在复现时额外做了一组对照实验:假设双方拥有完全真实的相手状态信息,直接用相同参数的C-W方程和收益函数求解epsilon纳什均衡。对比结果非常清晰:完全信息下的脱靶量显著优于不完全信息场景,但策略更敏感,微小参数变化容易导致均衡跳变;不完全信息场景下,脱靶量虽然偏大,但策略平滑、鲁棒性好。
这引出一个重要结论:不完全信息博弈的直接均衡不一定是工程上最优的,但它给出了一个更现实的下界。实际飞行控制设计中,你可以先算完全信息博弈的脱靶量作为理想值,再算不完全信息博弈的脱靶量作为保守估计,两者结合作为控制系统设计的指标范围。
5.3 可扩展方向
这个项目的框架具有很强的扩展性。我列几个我在复现后想到的改进方向:
第一,把C-W方程换成更精细的轨道动力学模型,比如包含J2摄动的高阶模型。J2摄动在几百公里高度的影响不能完全忽略,会让轨道角速度随时间缓慢漂移,对长时间博弈的影响更显著。
第二,将EKF换成无迹卡尔曼滤波(UKF)或粒子滤波。EKF的一阶线性化在强非线性场景下误差较大,UKF对非线性处理更好,代价是计算量增加。如果博弈段持续时间不长、计算资源充足,UKF可能带来更稳定的估计。
第三,把策略参数化的阶数从二次多项式提升到更高阶或者采用分段常数控制。多项式阶数越高,策略表达能力越强,但优化复杂度也上升。分段常数控制更贴近工程实现——实际航天器推力器不是连续可调的,而是脉冲式开关控制。
第四,将Epsilon纳什均衡拓展为鲁棒博弈。不完全信息场景下,可以对不确定性集合内的最坏情况做鲁棒优化。这种思路能让策略对极端测量误差也有一定抵御能力,但计算复杂度会明显增加。
最后分享一点我的实操体会
我把这套系统前前后后跑了大半个月,最大的感受是:理论博弈模型和仿真实现之间的鸿沟,往往不在公式推导,而在数值细节。EKF那几个数值稳定性问题,教科书上一笔带过,真正实现时却能卡你一整天。我建议复现这个项目的人,第一遍不要急着加自适应和复杂模块,先把完全信息版本跑通,确认博弈均衡能平滑收敛,再加上EKF估计,最后才引入自适应机制。循序渐进地加复杂度,出问题时才能定位到具体模块。
另外一个小技巧:在仿真循环里定期打印关键指标,比如当前步数、双方估计误差、epsilon值、策略变化量。不要只在最后画图,因为运行中途发现异常时,这些打印信息能帮你快速定位是哪一步开始出问题的。我最后跑的版本里,每50步打一次日志,格式很简单:
Step 150: est_err_p=12.3m, est_err_e=15.7m, eps=0.043, delta_s=0.021这行日志包含的信息足够你在运行中途判断系统是否健康。我这个项目从一开始的频繁炸掉,到最终稳定跑完300步仿真,这个日志习惯帮了大忙。希望这些经验和细节能让你少走一些我走过的弯路。