第1章:太阳矢量确定

各位同学,咱们今天开始聊太阳翼对日定向跟踪的核心问题——太阳矢量怎么确定。

说白了,就是卫星得知道太阳在哪儿。你想想看,如果连太阳在哪个方向都不知道,那太阳翼往哪儿转?对吧?

我刚开始做GNC的时候,总觉得这事儿挺简单——装几个太阳敏感器不就行了?后来发现,这里面的门道还真不少。今天咱们就把这块掰开了揉碎了讲清楚。

1.1 太阳敏感器原理

太阳敏感器,说白了就是卫星的"眼睛",专门用来感知太阳的方向。市面上的太阳敏感器种类不少,但咱们做工程最常用的就两种:模拟式太阳敏感器和数字式太阳敏感器。

模拟式太阳敏感器,原理其实挺朴素的——利用太阳电池片,太阳照在上面会产生电流。电流大小跟入射角有关系。我当年在项目中用过一种四象限模拟敏感器,四个象限的电流比值就能算出太阳方向。

它的输出公式大致是这样的:

tan(α) = (I_A - I_B) / (I_A + I_B)
tan(β) = (I_C - I_D) / (I_C + I_D)

其中α和β就是太阳矢量在敏感器坐标系下的两个角度。I_A到I_D是四个象限的电流值。

我的经验:模拟式敏感器便宜、可靠,但精度一般。如果你做低成本小卫星,这是个不错的选择。我曾经在一个微纳卫星项目里用过,效果还行,就是标定的时候费了点功夫。

数字式太阳敏感器就不一样了。它用的是CMOS或CCD图像传感器,直接拍太阳的图像,然后通过质心算法算出太阳中心在像平面上的位置。

它的精度比模拟式高一个数量级,但代价是功耗大、成本高。嗯,这里要注意——数字式敏感器对光照强度很敏感,太强的阳光反而会让图像饱和。

类型 精度 功耗 成本 典型应用
模拟式 0.5°~1° <0.5W 微纳卫星、应急模式
数字式 0.01°~0.1° 1~3W 高精度对日定向

1.2 太阳矢量在惯性系下的计算

好,敏感器装上了,但敏感器测的是"相对自身"的方向。咱们做对日定向,需要知道太阳在惯性系下的位置。这怎么算?

其实有现成的天文算法。最常用的是低精度太阳位置模型,精度大约0.01°,对于太阳翼跟踪来说完全够用。

我习惯用下面的简化公式:

// 输入:儒略日 JD
// 输出:太阳在J2000惯性系下的单位矢量

double n = JD - 2451545.0;  // 从J2000起算的天数

double L = 280.460 + 0.9856474 * n;  // 太阳平黄经(度)
double g = 357.528 + 0.9856003 * n;  // 平近点角(度)

// 太阳黄经
double lambda = L + 1.915 * sin(g * DEG2RAD) + 0.020 * sin(2 * g * DEG2RAD);

// 黄赤交角
double epsilon = 23.439 - 0.0000004 * n;

// 转成赤经赤纬
double ra = atan2(cos(epsilon * DEG2RAD) * sin(lambda * DEG2RAD), cos(lambda * DEG2RAD));
double dec = asin(sin(epsilon * DEG2RAD) * sin(lambda * DEG2RAD));

// 转成笛卡尔坐标
double r_sun[3];
r_sun[0] = cos(dec) * cos(ra);
r_sun[1] = cos(dec) * sin(ra);
r_sun[2] = sin(dec);
关键点:这个模型假设地球轨道是圆轨道,实际上有偏心率的修正。但0.01°的误差对于太阳翼控制来说,已经绰绰有余了。我做过仿真,0.01°的角度误差导致的功率损失不到0.01%,完全可以忽略。

你可能会问:为什么不用更高精度的模型?

嗯,原因很简单——星上计算机的资源有限。你算得再精确,控制执行机构(比如步进电机)的精度也就0.1°左右。算得太精细反而是浪费。

1.3 太阳矢量在本体系下的测量

惯性系下的太阳矢量算出来了,但卫星本体在转啊。我们需要知道太阳相对于卫星本体的方向,才能控制太阳翼转动。

这里就涉及到坐标变换了。

假设卫星的姿态用四元数 q_body2inertial 表示,那么:

// 太阳矢量在惯性系:S_inertial
// 姿态四元数:q_body2inertial(从本体系到惯性系)
// 求太阳矢量在本体系:S_body

// 方法一:用四元数旋转
// 先把S_inertial转成四元数形式(标量部分为0)
Quat q_sun_inertial(0, S_inertial.x, S_inertial.y, S_inertial.z);

// 用共轭四元数旋转
Quat q_body2inertial_conj = q_body2inertial.conjugate();
Quat q_sun_body = q_body2inertial_conj * q_sun_inertial * q_body2inertial;

// 提取矢量部分
S_body = q_sun_body.vector();

当然,如果你用的是方向余弦矩阵(DCM),那就更直接了:

// C_body2inertial 是3x3的方向余弦矩阵
// S_body = C_body2inertial^T * S_inertial

double C_body2inertial[3][3];  // 从姿态确定系统获得
double S_body[3];

for(int i=0; i<3; i++) {
    S_body[i] = 0;
    for(int j=0; j<3; j++) {
        S_body[i] += C_body2inertial[j][i] * S_inertial[j];
    }
}
避坑指南:我曾经在一个项目里犯过错误——把坐标变换的方向搞反了。结果太阳翼朝着完全相反的方向转,功率不升反降。后来排查了半天才发现是符号问题。所以,一定要搞清楚你的四元数或DCM的定义方向。我建议你在代码里加个注释,写上"从哪到哪"。

有了本体系下的太阳矢量,再结合太阳敏感器的实际测量值,就可以做数据融合了。通常的做法是:

  1. 用星上轨道模型算出惯性系下的太阳矢量(理论值)
  2. 用姿态确定系统算出本体系到惯性系的转换
  3. 把理论值转到本体系,得到预测值
  4. 用太阳敏感器实测值做校正

这样即使某个环节有误差,也能通过融合得到更可靠的结果。

我的习惯:在实际工程中,我一般会保留两种模式:正常模式下用"轨道模型+姿态"算太阳矢量,应急模式下直接用太阳敏感器原始数据。万一星上计算机死机重启,至少还能保证太阳翼能工作。

好了,这一章的内容就到这儿。太阳矢量的确定是后续所有跟踪算法的基础。下一章咱们聊太阳翼的驱动机构和控制策略,到时候会用到今天讲的这些内容。

有什么问题,欢迎在课程群里讨论。咱们下节课见。