第三章 太阳矢量确定:从理论到工程实现

各位同学,今天我们来聊聊卫星太阳翼对日定向中最核心的一环——怎么确定太阳在哪儿。

说白了,你要让太阳翼对准太阳,首先得知道太阳在哪个方向。这个看似简单的问题,在航天工程里其实有不少门道。我当年做第一个型号的时候,就因为在太阳矢量计算上栽了个跟头,导致整星在轨测试多花了两周时间。嗯,从那以后我对这块就特别上心。

3.1 太阳在惯性系下的位置计算

先说说最基础的问题:怎么知道太阳在惯性坐标系里的位置?

你可能会想,太阳不是基本不动吗?其实不是。地球绕着太阳转,卫星绕着地球转,这个相对运动必须算清楚。

工程上常用的方法是查表加插值。NASA 提供的 DE 历表(比如 DE405)精度很高,但星上计算机资源有限,不可能实时算那么复杂的模型。我个人习惯的做法是:

  • 轨道预报阶段:用高精度模型算好太阳位置,做成查找表
  • 在轨运行阶段:用简化解析公式实时计算

这里给出一套工程上常用的简化算法:

/* 太阳位置简化计算(基于J2000.0惯性系) */
/* 输入:MJD(简化儒略日) */
/* 输出:太阳单位方向向量 */

void sun_vector_calc(double mjd, double sun_vec[3])
{
    double T = (mjd - 51544.5) / 36525.0;  // 从J2000.0起算的儒略世纪数
    
    double M = 357.5291 + 35999.0503 * T;   // 太阳平近点角(度)
    double lambda = 280.4665 + 36000.7698 * T; // 太阳平黄经
    
    /* 中心差修正 */
    double C = (1.9146 - 0.0048 * T) * sin(M * DEG2RAD) 
             + 0.0200 * sin(2 * M * DEG2RAD);
    
    double true_lambda = lambda + C;  // 太阳真黄经
    
    /* 计算黄道坐标系下的位置 */
    double r = 1.000001 - 0.01671 * cos(M * DEG2RAD) 
             - 0.00014 * cos(2 * M * DEG2RAD);  // 日地距离(AU)
    
    double x = r * cos(true_lambda * DEG2RAD);
    double y = r * sin(true_lambda * DEG2RAD);
    
    /* 转换到J2000.0惯性系(考虑黄赤交角) */
    double eps = 23.4393 - 0.0130 * T;  // 黄赤交角
    
    sun_vec[0] = x;
    sun_vec[1] = y * cos(eps * DEG2RAD);
    sun_vec[2] = y * sin(eps * DEG2RAD);
    
    /* 归一化 */
    double norm = sqrt(sun_vec[0]*sun_vec[0] + 
                      sun_vec[1]*sun_vec[1] + 
                      sun_vec[2]*sun_vec[2]);
    sun_vec[0] /= norm;
    sun_vec[1] /= norm;
    sun_vec[2] /= norm;
}
工程小贴士: 这个简化算法的精度大约在0.01度左右,对太阳翼对日定向来说完全够用。如果你需要更高精度,可以用DE405查表,但要注意星上存储空间。

3.2 太阳敏感器测量模型

理论计算是一回事,实际测量是另一回事。卫星上装什么传感器来测太阳方向?

常用的太阳敏感器分两类:

  • 模拟式太阳敏感器:输出太阳角的正弦/余弦值,精度一般,但简单可靠
  • 数字式太阳敏感器:用APS/CCD成像,直接输出太阳中心在像平面上的坐标,精度高

我做过一个项目,用的是数字式太阳敏感器。它的测量模型长这样:

/* 数字太阳敏感器测量模型 */
/* 输入:太阳在敏感器坐标系下的方向向量 s_sensor[3] */
/* 输出:像平面坐标 (u, v) 像素 */

void sun_sensor_model(double s_sensor[3], double *u, double *v)
{
    double f = 12.5e-3;  // 焦距(米)
    double pixel_size = 5.5e-6;  // 像元尺寸(米)
    
    /* 针孔相机模型 */
    double u_m = f * s_sensor[0] / s_sensor[2];  // 米
    double v_m = f * s_sensor[1] / s_sensor[2];
    
    /* 转换到像素坐标 */
    *u = u_m / pixel_size + 512;  // 假设1024x1024像元,中心在(512,512)
    *v = v_m / pixel_size + 512;
    
    /* 别忘了加噪声! */
    /* 实际工程中还要考虑畸变、温度漂移等 */
}
注意: 太阳敏感器最怕的是太阳光被遮挡。我曾经遇到过卫星在特定姿态下,太阳翼刚好挡住太阳敏感器视场的情况。结果就是太阳矢量测量值跳变,导致控制系统震荡。所以布局阶段一定要做视场分析。

3.3 矢量观测与滤波

有了理论计算的太阳位置,又有了太阳敏感器的实测数据,接下来要做的就是融合它们。

你想想看,理论计算值很平滑但可能有系统误差,实测值有噪声但能反映真实情况。怎么结合?

常用的方法有两种:

方法 优点 缺点 适用场景
最小二乘拟合 计算简单,适合资源受限 不能处理动态变化 稳态对日定向
扩展卡尔曼滤波(EKF) 能处理非线性,精度高 计算量大,调参麻烦 高精度指向任务
无迹卡尔曼滤波(UKF) 比EKF更稳定 计算量更大 强非线性场景

我个人比较推荐用EKF。为什么?因为它在精度和计算量之间取得了很好的平衡。下面是我在项目中用过的EKF实现框架:

/* 太阳矢量EKF滤波器(简化版) */
/* 状态量:太阳方向向量 (3维) */
/* 观测量:太阳敏感器输出 (2维:u, v) */

typedef struct {
    double x[3];      // 状态:太阳方向向量
    double P[3][3];   // 状态协方差矩阵
    double Q[3][3];   // 过程噪声
    double R[2][2];   // 测量噪声
} sun_ekf_t;

void sun_ekf_predict(sun_ekf_t *ekf, double dt)
{
    /* 预测步:太阳方向变化很慢,用单位矩阵 */
    /* 实际上要考虑卫星轨道运动引起的太阳方向变化 */
    double F[3][3] = {{1,0,0},{0,1,0},{0,0,1}};
    
    /* 状态预测:x = F * x */
    /* 协方差预测:P = F*P*F' + Q */
    /* 具体实现略... */
}

void sun_ekf_update(sun_ekf_t *ekf, double u_meas, double v_meas)
{
    /* 更新步:用太阳敏感器测量值修正 */
    /* 计算卡尔曼增益 */
    /* 更新状态和协方差 */
    /* 具体实现略... */
}

关键经验:EKF调参是个手艺活。我刚开始做的时候,Q矩阵和R矩阵调了一个月才稳定。后来总结出几个要点:

  • 过程噪声Q不要设太大,否则滤波器会太"相信"测量值
  • 测量噪声R要根据太阳敏感器的实际噪声水平来设,可以看标定数据
  • 初始协方差P0设大一点,让滤波器快速收敛

3.4 工程实现中的坑

最后说说我踩过的几个坑,希望对你有帮助:

  • 太阳敏感器安装偏差:装上去之后一定要做地面标定,否则0.1度的安装误差就能让太阳翼效率下降不少
  • 温度影响:太阳敏感器在轨温度变化很大,我见过因为温度导致测量值漂移0.5度的情况。解决办法是加温度补偿模型
  • 地影区处理:卫星进入地影后,太阳敏感器没信号了。这时候要用理论计算值保持,等出影后再切换回测量值。切换时要平滑过渡,不然会有冲击

嗯,关于太阳矢量确定的内容就讲到这里。这部分虽然基础,但直接影响整个对日定向系统的性能。希望你能把这些方法真正用到自己的项目中去。

太阳矢量确定知识体系 太阳位置理论计算 太阳敏感器测量模型 矢量观测与滤波 DE历表查表 + 简化解析公式 黄道坐标系 → J2000.0惯性系 精度约0.01°,满足对日定向需求 模拟式:输出正弦/余弦值 数字式:APS/CCD成像,输出像素坐标 针孔相机模型 + 畸变/温度补偿 最小二乘:简单但无法处理动态 EKF:精度与计算量的平衡 UKF:强非线性场景更稳定 工程实现要点 安装标定 | 温度补偿 | 地影区处理 | 视场分析

这张图把本章的知识体系串起来了。从左到右,从理论到测量再到滤波,最后落到工程实现。建议你把这个框架记在脑子里,做项目时就知道每一步该干什么。

专注资料整理