3.5.12Guidance, Navigation & Control (GNC)

Attitude estimation — triad method (two vector measurements)

2,098 words10 min readdifficulty · medium2 backlinks

WHY do we need this?

WHAT is attitude? Attitude = the orientation of a rigid body (spacecraft) relative to a reference frame. Mathematically it is a rotation matrix (or attitude matrix) AA that maps vectors expressed in the reference/inertial frame to the body frame:

vbody=Avref\mathbf{v}_{\text{body}} = A\,\mathbf{v}_{\text{ref}}

WHY two vectors? A single measured direction fixes only 2 of the 3 degrees of freedom — the spacecraft can still spin about that direction and you'd never notice. You need a second independent direction to lock down that last spin angle.

The catch: measurements are noisy, so exactly Ar^i=b^iA\hat{\mathbf r}_i=\hat{\mathbf b}_i for both ii is impossible in general (the angle between b^1,b^2\hat{\mathbf b}_1,\hat{\mathbf b}_2 won't perfectly match the angle between r^1,r^2\hat{\mathbf r}_1,\hat{\mathbf r}_2). TRIAD's trick: trust one vector completely, and use the second only for direction.


HOW to derive TRIAD from scratch

We will construct an orthonormal triad (a right-handed frame) in each set of coordinates, then match them. That's where the name comes from: TRI-Axial Attitude Determination.

Step 1 — Build a right-handed frame from the reference vectors

We have r^1,r^2\hat{\mathbf r}_1,\hat{\mathbf r}_2. We want three orthogonal unit axes.

t^1(r)=r^1\hat{\mathbf t}_1^{(r)} = \hat{\mathbf r}_1

Why this step? We declare r^1\hat{\mathbf r}_1 our most trusted measurement, so we keep it exactly as the first axis.

{\lVert \hat{\mathbf r}_1 \times \hat{\mathbf r}_2 \rVert}$$ *Why this step?* The cross product is **perpendicular to both** input vectors, so it's automatically orthogonal to $\hat{\mathbf t}_1^{(r)}$. Normalizing makes it a unit vector. Crucially, this direction depends on $\hat{\mathbf r}_2$'s *direction* but **not its exact angle** — so the noisy angle of the second vector is thrown away. That's the noise-rejection choice. $$\hat{\mathbf t}_3^{(r)} = \hat{\mathbf t}_1^{(r)} \times \hat{\mathbf t}_2^{(r)}$$ *Why this step?* A third cross product of two orthonormal vectors gives the **remaining orthogonal axis** and guarantees a **right-handed** frame ($\det = +1$, a proper rotation). Stack them as columns: $$M_r = \big[\,\hat{\mathbf t}_1^{(r)}\ \ \hat{\mathbf t}_2^{(r)}\ \ \hat{\mathbf t}_3^{(r)}\,\big]$$ ### Step 2 — Build the SAME frame from the body measurements Identical recipe, with $\hat{\mathbf b}$'s: $$\hat{\mathbf t}_1^{(b)}=\hat{\mathbf b}_1,\quad \hat{\mathbf t}_2^{(b)}=\frac{\hat{\mathbf b}_1\times\hat{\mathbf b}_2} {\lVert \hat{\mathbf b}_1\times\hat{\mathbf b}_2\rVert},\quad \hat{\mathbf t}_3^{(b)}=\hat{\mathbf t}_1^{(b)}\times\hat{\mathbf t}_2^{(b)}$$ $$M_b = \big[\,\hat{\mathbf t}_1^{(b)}\ \ \hat{\mathbf t}_2^{(b)}\ \ \hat{\mathbf t}_3^{(b)}\,\big]$$ ### Step 3 — Match the two frames Both $M_r$ and $M_b$ describe the **same physical triad**, one in reference coordinates, one in body coordinates. The rotation must carry reference-frame columns into body-frame columns: $$A\,M_r = M_b$$ *Why?* Column-by-column this says $A\hat{\mathbf t}_i^{(r)}=\hat{\mathbf t}_i^{(b)}$ — the attitude matrix rotates each reference axis onto the corresponding body axis. Since $M_r$ is orthonormal, its inverse is its transpose ($M_r^{-1}=M_r^{\mathsf T}$). Therefore: > [!formula] TRIAD attitude matrix > $$\boxed{A = M_b\,M_r^{\mathsf T} = \sum_{i=1}^{3}\hat{\mathbf t}_i^{(b)}\,\hat{\mathbf t}_i^{(r)\mathsf T}}$$ > Derived, not dumped: it is the **product of the body triad and the transpose of the reference > triad**, because $A = M_b M_r^{-1}$ and orthonormal $\Rightarrow M_r^{-1}=M_r^{\mathsf T}$. **Check it's a valid rotation:** $M_b, M_r$ are orthonormal with $\det=+1$, so $A A^{\mathsf T}=M_bM_r^{\mathsf T}M_rM_b^{\mathsf T}=M_bM_b^{\mathsf T}=I$ and $\det A = +1$. ✅ ![[3.5.12-Attitude-estimation-—-triad-method-(two-vector-measurements).png]] --- ## Worked Example 1 — clean, exact case Reference vectors (say Sun and mag-field in inertial frame): $$\hat{\mathbf r}_1=(1,0,0),\qquad \hat{\mathbf r}_2=(0,1,0)$$ Suppose the true attitude is a **90° rotation about the z-axis**, so measured body vectors are: $$\hat{\mathbf b}_1=(0,1,0),\qquad \hat{\mathbf b}_2=(-1,0,0)$$ **Reference triad:** - $\hat{\mathbf t}_1^{(r)}=(1,0,0)$ - $\hat{\mathbf r}_1\times\hat{\mathbf r}_2=(0,0,1)\Rightarrow\hat{\mathbf t}_2^{(r)}=(0,0,1)$ *(Why? cross of x̂ and ŷ is ẑ.)* - $\hat{\mathbf t}_3^{(r)}=(1,0,0)\times(0,0,1)=(0,-1,0)$ $$M_r=\begin{bmatrix}1&0&0\\0&0&-1\\0&1&0\end{bmatrix}$$ **Body triad:** - $\hat{\mathbf t}_1^{(b)}=(0,1,0)$ - $\hat{\mathbf b}_1\times\hat{\mathbf b}_2=(0,1,0)\times(-1,0,0)=(0,0,1)\Rightarrow\hat{\mathbf t}_2^{(b)}=(0,0,1)$ - $\hat{\mathbf t}_3^{(b)}=(0,1,0)\times(0,0,1)=(1,0,0)$ $$M_b=\begin{bmatrix}0&0&1\\1&0&0\\0&1&0\end{bmatrix}$$ **Attitude:** $A=M_bM_r^{\mathsf T}$. Compute $M_r^{\mathsf T}$ and multiply: $$A=\begin{bmatrix}0&-1&0\\1&0&0\\0&0&1\end{bmatrix}$$ *Why this is right:* this is exactly the standard $R_z(90^\circ)$ matrix — check $A\hat{\mathbf r}_1 =(0,1,0)=\hat{\mathbf b}_1$ ✅ and $A\hat{\mathbf r}_2=(-1,0,0)=\hat{\mathbf b}_2$ ✅. --- ## Worked Example 2 — noisy case (the whole point) Say the *true* angle between reference vectors is $90^\circ$, but the second body measurement is noisy, giving $\hat{\mathbf b}_2$ at $88^\circ$ from $\hat{\mathbf b}_1$ instead of $90^\circ$. - TRIAD sets $\hat{\mathbf t}_1^{(b)}=\hat{\mathbf b}_1$ **exactly** — so whatever sensor gave $\hat{\mathbf b}_1$ (say the star tracker) is **perfectly honored**. - The $2^\circ$ error in $\hat{\mathbf b}_2$ only tilts the *plane* used for the cross product; its precise angle is **discarded**. So the second sensor contributes only "which side is up." *Why this matters:* If sensor 1 is much more accurate than sensor 2, TRIAD is smart — feed the **accurate sensor as $\hat{\mathbf r}_1/\hat{\mathbf b}_1$**. The estimate error stays first-order in the *accurate* sensor and largely rejects sensor-2 angular noise. --- ## Common Mistakes (Steel-manned) > [!mistake] "TRIAD treats both measurements equally." > **Why it feels right:** the recipe *looks* symmetric — you cross the two vectors either way. > **Why it's wrong:** $\hat{\mathbf b}_1$ becomes an *exact* axis while only the **direction** of the > cross product (not the angle) of $\hat{\mathbf b}_2$ survives. The method is **asymmetric**. > **Fix:** Always assign your **most trusted sensor** to slot 1. Swapping 1↔2 gives a *different* $A$. > [!mistake] "I can just use $A=M_b M_r^{-1}$ without normalizing." > **Why it feels right:** algebraically $A=M_bM_r^{-1}$ is correct. > **Why it's wrong:** If you skip normalizing the cross products, $M_r,M_b$ aren't orthonormal, so > $M_r^{-1}\neq M_r^{\mathsf T}$ and $A$ won't be a proper rotation. > **Fix:** Normalize every triad axis; then $M^{-1}=M^{\mathsf T}$ and $\det A=+1$. > [!mistake] "Use it even when the two vectors are nearly parallel." > **Why it feels right:** two vectors are two vectors. > **Why it's wrong:** $\lVert\hat{\mathbf r}_1\times\hat{\mathbf r}_2\rVert=\sin\theta\to0$; dividing > by a tiny number amplifies noise catastrophically. > **Fix:** Require good angular separation (best near $90^\circ$); if vectors are collinear, attitude > about that axis is undetermined. --- ## Active Recall > [!recall]- Can you rebuild TRIAD blind? > 1. Why do you need **two** vectors, not one? *(one leaves a spin DOF free)* > 2. Write $\hat{\mathbf t}_2$. Why the cross product? *(orthogonal to both, discards sensor-2 angle)* > 3. Why is $A=M_bM_r^{\mathsf T}$ and not $M_bM_r^{-1}$ literally? *(orthonormal ⇒ inverse=transpose)* > 4. Which sensor should be slot 1? *(the more accurate one)* > [!recall]- Feynman: explain to a 12-year-old > Imagine you're spun around blindfolded in a field. If someone tells you "the Sun is over there," > you know a bit — but you could still be tilting your head sideways. If they *also* say "the tall > tower is over there," now you know **exactly** which way you're facing. TRIAD is a robot doing that: > it looks at **two known things in the sky**, compares where they *are* to where they *should be*, > and figures out exactly how it's turned. It trusts the clearer landmark more, and uses the second > one just to know "which way is up." > [!mnemonic] Remember the recipe > **"1 stays, cross gives 2, cross again gives 3; then Body times Ref-transpose."** > Or: **B**ody **M**atches **R**eference → $A=\mathbf{B}\,\mathbf{R}^{\mathsf T}$ ("Boy Rides Transposed"). --- ## Connections - [[Rotation Matrices and SO(3)]] — why orthonormal ⇒ transpose = inverse, $\det=+1$. - [[Wahba's Problem]] — the optimal least-squares generalization (weights **both** vectors). - [[Davenport q-method]] and [[QUEST algorithm]] — solve Wahba efficiently via quaternions. - [[Cross Product and Right-Handed Frames]] — the geometric backbone here. - [[Sun Sensors and Magnetometers]] — the physical sources of $\hat{\mathbf b}_i$. - [[Quaternion Attitude Kinematics]] — how the estimated $A$ feeds the [[Kalman Filter — Attitude]]. --- #flashcards/physics TRIAD stands for what / solves what problem? ::: TRIaxial Attitude Determination; finds the attitude (rotation) matrix from two vector measurements known in both reference and body frames. Why can't a single vector measurement give full attitude? ::: It fixes only 2 DOF; the body can still rotate freely about that vector (1 unresolved spin angle). First TRIAD axis $\hat t_1$ = ? ::: The most-trusted measured unit vector itself ($\hat r_1$ / $\hat b_1$), kept exactly. Second TRIAD axis $\hat t_2$ = ? ::: Normalized cross product $(\hat r_1\times\hat r_2)/\lVert\hat r_1\times\hat r_2\rVert$ — orthogonal to both, discards vector-2's angle. Third TRIAD axis $\hat t_3$ = ? ::: $\hat t_1\times\hat t_2$, giving the remaining orthogonal, right-handed axis. Final TRIAD formula for A ::: $A = M_b M_r^{\mathsf T}$, with $M_r,M_b$ = matrices of triad axes as columns. Why is $M_r^{-1}=M_r^{\mathsf T}$? ::: $M_r$ is orthonormal (columns are unit, mutually orthogonal), a property of proper rotation/frame matrices. Which measurement should be assigned to slot 1? ::: The most accurate sensor, because slot 1 is honored exactly while slot 2's angle is discarded. When does TRIAD fail / degrade? ::: When the two vectors are nearly parallel: $\lVert\hat r_1\times\hat r_2\rVert=\sin\theta\to0$ amplifies noise; attitude about that axis is undetermined. Key limitation vs Wahba/QUEST? ::: TRIAD uses only 2 vectors asymmetrically; Wahba/QUEST optimally weight any number of vectors (least squares). Check that TRIAD's A is a proper rotation ::: $AA^{\mathsf T}=M_bM_r^{\mathsf T}M_rM_b^{\mathsf T}=I$ and $\det A=+1$. ## 🖼️ Concept Map ```mermaid flowchart TD A[Attitude = rotation matrix A] -->|maps ref to body| B[v_body = A v_ref] C[Single vector] -->|fixes only 2 DOF| D[Spin ambiguity] D -->|needs 2nd vector| E[Two non-parallel vectors] E -->|reference frame| F[r1 r2 known] E -->|body frame| G[b1 b2 measured] F -->|build triad| H[Reference frame Mr] G -->|build triad| I[Body frame Mb] H -->|t1 = r1 trusted| J[First axis] H -->|t2 = cross product| K[Rejects noisy angle] H -->|t3 = t1 x t2| L[Right-handed proper rotation] I -->|match triads| M[A = Mb Mr transpose] J --> M K --> M L --> M ``` ## 🔊 Hinglish (regional understanding) > [!intuition]- Hinglish mein samjho > Dekho, TRIAD ka core idea bahut simple hai. Spacecraft ka **attitude** matlab uska orientation — > wo kis taraf tilt/rotate hua hai space mein. Agar tumhare paas sirf **ek** direction hai (jaise Sun > kidhar hai), toh tum us axis ke around abhi bhi ghoom sakte ho aur pata nahi chalega — 1 degree of > freedom bacha reh jaata hai. Isliye humein **do** vectors chahiye: jaise Sun sensor aur magnetometer. > In dono directions ko jab tum "jahan hone chahiye" (reference frame) se compare karte ho, toh pura 3D > orientation nikal aata hai. > > Method ka trick yeh hai: tum dono coordinate systems mein ek **orthonormal triad** (teen perpendicular > axes) banate ho. Pehla axis $\hat t_1=\hat r_1$ — yani sabse trusted sensor ko exactly rakh lo. Doosra > axis $\hat r_1\times\hat r_2$ ka normalized version — cross product dono ke perpendicular hota hai, aur > yahan doosre sensor ka sirf *direction* use hota hai, uska exact angle *discard* ho jaata hai (isliye > noise kam affect karta hai). Teesra axis dono ka cross product. Yehi triad body frame mein bhi banao, > phir **$A = M_b\,M_r^{T}$** — bas ho gaya attitude matrix. > > Yeh kyun matter karta hai? Kyunki spacecraft ko apni antenna Earth ki taraf point karni hai, solar > panels Sun ki taraf — agar attitude galat, mission fail. TRIAD sabse simple, fast, closed-form > method hai (koi iteration nahi). Bas dhyan rakho: **accurate wala sensor slot 1 mein daalo**, aur do > vectors ko kabhi parallel mat hone do (warna cross product zero ke paas jaata hai aur noise blow up > ho jaata hai). Aage chalke Wahba's problem aur QUEST algorithm isi ko optimal bana dete hain jab > zyada sensors ho. ![[audio/3.5.12-Attitude-estimation-—-triad-method-(two-vector-measurements).mp3]]

Go deeper — visual, from zero

Test yourself — Guidance, Navigation & Control (GNC)

Connections