Skip to content

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::ECFuniversalEarth-Centered Equatorial Fixed (WGS84)真值锚定foundation
frame::LICuniversalLaunch Inertial Cartesian (origin = launch point at t=0)数值积分foundation
frame::BODYuniversalBody-fixed(沿火箭轴系)体坐标力/力矩foundation
frame::AEROuniversalAir-relative wind frame气动力计算foundation
frame::NUEFCC-internalNorth-Up-East 局部水平SINS 状态空间fcc
frame::LLAFCC-internalLatitude/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>

cpp
// src/types/Vec3.h
template&lt;typename Frame&gt;
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&lt;typename OtherFrame&gt;
    Vec3_T operator+(const Vec3_T&lt;OtherFrame&gt;&) const = delete;
};

using Vec3 = Vec3_T&lt;void&gt;;  // 仅用于 internal scratch

核心保证pos_ecf + vel_lic 编译报错。pos_ecf - pos_ecf OK 且类型是 Vec3_T&lt;frame::ECF&gt;(位移仍属 ECF)。

2.2 Quat_T<From, To>

cpp
template&lt;typename From, typename To&gt;
struct Quat_T {
    double w, x, y, z;

    Vec3_T&lt;To&gt;   rotate(const Vec3_T&lt;From&gt;& v) const;
    Quat_T&lt;To, From&gt; inverse() const;

    template&lt;typename Mid&gt;
    Quat_T&lt;From, Mid&gt; operator*(const Quat_T&lt;Mid, To&gt;&) const;
};

核心保证Quat_T&lt;LIC, BODY&gt;::rotate(Vec3_T&lt;LIC&gt;) 返回 Vec3_T&lt;BODY&gt;,类型安全。Quat_T&lt;LIC, BODY&gt; · Quat_T&lt;ECF, LIC&gt; 编译报错(中间帧不匹配)。


3. Standard Transforms

cpp
// src/types/frames/Transforms.h
namespace frame {

// 平移+旋转的复合
struct EcfLicTransform {
    Time           t0;
    Vec3_T&lt;ECF&gt;    origin_ecf;
    Quat_T&lt;ECF, LIC&gt; R0;        // 发射瞬间冻结的旋转

    Vec3_T&lt;ECF&gt; lic_to_ecf(const Vec3_T&lt;LIC&gt;& p, Time t) const;
    Vec3_T&lt;LIC&gt; ecf_to_lic(const Vec3_T&lt;ECF&gt;& p, Time t) const;
};

// WGS84 椭球:ECF ↔ LLA
struct WGS84 {
    static Vec3_T&lt;ECF&gt; lla_to_ecf(double lat, double lon, double alt);
    static void        ecf_to_lla(Vec3_T&lt;ECF&gt;, double& lat, double& lon, double& alt);
};

} // namespace frame

frame::FrameConfig(在 sim::WorldEnv 中持有的字段,见 Blueprint §2.6.2)封装了 EcfLicTransform 与 launch point 的标定。


4. Frame Discipline by Layer

每个子域允许出现的 frame 受限。违反就是 bug:

mermaid
graph LR
    A[dynamics_core] --&gt;|读写| LIC
    A --&gt;|读写| BODY
    P[plant/physics] --&gt;|读| LIC
    P --&gt;|写| BODY
    P --&gt;|读| AERO
    E[environment] --&gt;|读| ECF
    AV[avionics/devices] --&gt;|读| BODY
    AV --&gt;|读| ECF
    AV --&gt;|写 GPS payload| ECF
    FCC[fcc/navigation] --&gt;|读 GPS| ECF
    FCC --&gt;|内部| NUE
    FCC --&gt;|输出| LLA
    SIM[simulation/probe] -.可见所有.- A

铁律

  1. GPS payload 强制 ECFpos_ecf, vel_ecf)。FCC 内部转 NUE / LLA 是 FCC 自己的事。
  2. 积分器只看 LICSpatialState.pos / vel 都是 Vec3_T&lt;frame::LIC&gt;
  3. 体坐标的物理量只在 BODYspec_force_b, omega_b, centroid_b)。
  4. 大气场以 ECF 为输入atmosphere.pressure_at(h_msl) 内部从 Vec3_T&lt;ECF&gt; 算高度)。
  5. 跨 frame 转换只能通过 frame::EcfLicTransformframe::WGS84 — 不允许就地手写旋转。

5. Common Pitfalls

错误正确
Vec3 pos_eciVec3_T&lt;frame::ECF&gt; 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 持有的 FrameConfig06_Simulation/WorldEnv_Assembly.md
  • GPS / IMU 传感器的 frame 协议 → 03_Avionics_and_Bus/Sensor_Modeling.md
  • FCC 内部的 NUE / LLA 处理 → 04_FCC/Navigation.md