Coordinate Frames
> Aligned with PCR Master Blueprint v1.0 — see Blueprint §2.1 (frames lib), §2.2 (frame usage in contracts). > C-Distillation note: All Vec3_T<Frame> / Quat_T<From, To> phantom-type wrappers compile to bare Vec3 / Quat (zero runtime cost). When distilling to C, the phantom annotations are stripped and frame correctness is enforced by code review + naming convention (pos_ecf, vel_lic).
1. The Frame Zoo
项目共定义 6 个坐标系,分两类:universal(属于 frame::,所有子域共用)和 FCC-internal(属于 FCC 导航算法私有)。
| 枚举 | 类型 | 物理含义 | 主用途 | 所属层 |
|---|---|---|---|---|
frame::ECF | universal | Earth-Centered Equatorial Fixed (WGS84) | 真值锚定 | foundation |
frame::LIC | universal | Launch Inertial Cartesian (origin = launch point at t=0) | 数值积分 | foundation |
frame::BODY | universal | Body-fixed(沿火箭轴系) | 体坐标力/力矩 | foundation |
frame::AERO | universal | Air-relative wind frame | 气动力计算 | foundation |
frame::NUE | FCC-internal | North-Up-East 局部水平 | SINS 状态空间 | fcc |
frame::LLA | FCC-internal | Latitude/Longitude/Altitude | 测地输出 | fcc |
1.1 ECF:Earth-Centered Equatorial Fixed(真值帧)
这是项目的"物理真相"。 所有 cross-body 的真值(位置、速度、GPS payload)都用 ECF 表达。
- 原点:地心
- Z 轴:地球自转轴
- X 轴:穿过本初子午线与赤道交点
- 与地球共转
> 为什么不是 ECI 或 ECEF? > - ECI(Earth-Centered Inertial)固定于惯性空间,不随地球旋转。优点是 Newton 第二定律直接可用;缺点是 GPS / WGS84 数据天然是 ECEF 坐标,每次插值都要做 J2000 时间相关的旋转,数值上不稳定。 > - ECEF(Earth-Centered Earth-Fixed)通常指 WGS84 椭球地心坐标系,但术语在不同标准里含糊(有时指赤道帧、有时指 ITRF)。 > - ECF = 我们项目内部的明确命名:等同于 WGS84 ECEF 赤道帧,与地球共转,但用了一个项目专有名字以避免 "我说的 ECEF 是不是你说的那个 ECEF" 这种永恒纠纷。
ECI / ECEF 在旧代码中出现的,全部标记为 legacy,迁移到 ECF。
1.2 LIC:Launch Inertial Cartesian(积分帧)
这是 ODE 积分的工作帧。 它是局部惯性,原点固定在 launch point 的 t = 0 时刻位置,三轴方向冻结于发射瞬间的 ECF 朝向。
- 与地球不共转(惯性帧,Newton 第二定律直接成立)
- 数值范围小(典型任务 LIC 坐标 |x| < 1000 km),float64 精度浪费少
- 与 ECF 之间通过一个时变旋转矩阵关联(地球自转贡献)
关键变换:LIC ↔ ECF
pos_ecf = R_e2l(t)^T · pos_lic + origin_ecf
(先旋转,再平移)其中 R_e2l(t) = Rz(ω_e · t) 是地球自转矩阵,origin_ecf 是 launch point 的 ECF 位置。
1.3 BODY:Body-fixed
- 原点:质心(可时变,因为推进剂消耗)
- 标准朝向:
+X = 火箭头部前向,+Z = "上"(射后局部),右手系 - 用途:所有"体坐标力/力矩"(推力、气动力矩、IMU 比力测量、姿态描述目标系)
1.4 AERO:Wind frame
- 原点:质心
+X = 相对气流方向(-V_rel)- 用途:阻力/升力公式的自然坐标系
- AERO ← BODY 经攻角 α、侧滑角 β 旋转
1.5 NUE / LLA(FCC-internal)
FCC 的 SINS(Strap-down Inertial Navigation System)内部使用 NUE(北-天-东)作为局部水平基准;输出层用 LLA(lat/lon/alt)表达给地面站。这两个 frame 仅在 fcc/navigation/ 内出现,对 dynamics_core / plant / avionics 不可见。
GPS payload 进入 FCC 时已经是 ECF(pos_ecf / vel_ecf);FCC 内部自己做 ECF→NUE→LLA 的转换。
2. Phantom-Typed Vectors and Quaternions
2.1 Vec3_T<Frame>
// src/types/Vec3.h
template<typename Frame>
struct Vec3_T {
double x, y, z;
// 同 frame 加减乘
Vec3_T operator+(const Vec3_T&) const;
Vec3_T operator-(const Vec3_T&) const;
Vec3_T operator*(double) const;
// 跨 frame 不允许直接相加(编译错)
template<typename OtherFrame>
Vec3_T operator+(const Vec3_T<OtherFrame>&) const = delete;
};
using Vec3 = Vec3_T<void>; // 仅用于 internal scratch核心保证:pos_ecf + vel_lic 编译报错。pos_ecf - pos_ecf OK 且类型是 Vec3_T<frame::ECF>(位移仍属 ECF)。
2.2 Quat_T<From, To>
template<typename From, typename To>
struct Quat_T {
double w, x, y, z;
Vec3_T<To> rotate(const Vec3_T<From>& v) const;
Quat_T<To, From> inverse() const;
template<typename Mid>
Quat_T<From, Mid> operator*(const Quat_T<Mid, To>&) const;
};核心保证:Quat_T<LIC, BODY>::rotate(Vec3_T<LIC>) 返回 Vec3_T<BODY>,类型安全。Quat_T<LIC, BODY> · Quat_T<ECF, LIC> 编译报错(中间帧不匹配)。
3. Standard Transforms
// src/types/frames/Transforms.h
namespace frame {
// 平移+旋转的复合
struct EcfLicTransform {
Time t0;
Vec3_T<ECF> origin_ecf;
Quat_T<ECF, LIC> R0; // 发射瞬间冻结的旋转
Vec3_T<ECF> lic_to_ecf(const Vec3_T<LIC>& p, Time t) const;
Vec3_T<LIC> ecf_to_lic(const Vec3_T<ECF>& p, Time t) const;
};
// WGS84 椭球:ECF ↔ LLA
struct WGS84 {
static Vec3_T<ECF> lla_to_ecf(double lat, double lon, double alt);
static void ecf_to_lla(Vec3_T<ECF>, double& lat, double& lon, double& alt);
};
} // namespace frameframe::FrameConfig(在 sim::WorldEnv 中持有的字段,见 Blueprint §2.6.2)封装了 EcfLicTransform 与 launch point 的标定。
4. Frame Discipline by Layer
每个子域允许出现的 frame 受限。违反就是 bug:
graph LR
A[dynamics_core] -->|读写| LIC
A -->|读写| BODY
P[plant/physics] -->|读| LIC
P -->|写| BODY
P -->|读| AERO
E[environment] -->|读| ECF
AV[avionics/devices] -->|读| BODY
AV -->|读| ECF
AV -->|写 GPS payload| ECF
FCC[fcc/navigation] -->|读 GPS| ECF
FCC -->|内部| NUE
FCC -->|输出| LLA
SIM[simulation/probe] -.可见所有.- A铁律:
- GPS payload 强制 ECF(
pos_ecf,vel_ecf)。FCC 内部转 NUE / LLA 是 FCC 自己的事。 - 积分器只看 LIC。
SpatialState.pos / vel都是Vec3_T<frame::LIC>。 - 体坐标的物理量只在 BODY(
spec_force_b,omega_b,centroid_b)。 - 大气场以 ECF 为输入(
atmosphere.pressure_at(h_msl)内部从Vec3_T<ECF>算高度)。 - 跨 frame 转换只能通过
frame::EcfLicTransform或frame::WGS84— 不允许就地手写旋转。
5. Common Pitfalls
| 错误 | 正确 |
|---|---|
Vec3 pos_eci | Vec3_T<frame::ECF> pos_ecf |
gps_msg.position = body.pos_lic(隐式赋值) | gps_msg.pos_ecf = transform.lic_to_ecf(body.pos_lic, t) |
auto v = pos_ecf + vel_lic(编译过得了?) | 编译期错误 ✓ |
| 在 dynamics_core 中用 LLA | 编译期错误(dynamics_core 不可 include fcc/) |
| 在 IMU 模型里直接采样大气 | 设计错误:IMU 不感受大气,只感受 body.aux.spec_force_b |
6. Cross References
- 跨域数据包中所有 frame 标注 →
01_Foundation/Contracts_PerBodyFrames.md SpatialState的 frame 字段 →05_Dynamics_Core/SpatialState_and_Frames.md- WorldEnv 持有的
FrameConfig→06_Simulation/WorldEnv_Assembly.md - GPS / IMU 传感器的 frame 协议 →
03_Avionics_and_Bus/Sensor_Modeling.md - FCC 内部的 NUE / LLA 处理 →
04_FCC/Navigation.md