How can I get the vessel's velocity in the ECEF reference frame?
How can I get the vessel's velocity in the ECEF reference frame?
vessel->GetGlobalPos( G_pos );
oapiGlobalToLocal( hEarth, &G_pos, &ECEF_pos );
Remember, Orbiters coordinate systems are left-handed...
ECEF_pos = _V( ECEF_pos.x, ECEF_pos.z, ECEF_pos.y );
Yes, and in the ECEF_pos calculation above, this is missing:
But the issue seems to be me not understanding what frame is the "local frame".Code:ECEF_pos = _V( ECEF_pos.x, ECEF_pos.z, ECEF_pos.y );
Depends... local to what? Didn't I post you a link to a NASA document with all different coordinate definitions some months ago?
The local frame mentioned in Orbiter's API.... in this case it would be local to Earth, but that apparently only refers to the center of the frame, leaving the orientation to make me confused... :facepalm:
Maybe VESSEL::GetGroundspeedVector using the FRAME_REFLOCAL frame of reference is doing what you want?
Noo... Local coordinates are VESSEL-local coordinates. Body coordinates would be a more suitable term.
OAPIFUNC void oapiGlobalToLocal (OBJHANDLE hObj, const VECTOR3 *glob, VECTOR3 *loc);
* \brief Maps a point from the global frame to a [B]local object frame[/B]......
Global coordinates and relative coordinates share the same axis vectors, but have a different origins.
//// position in ECEF ////
VECTOR3 G_pos;// "global position", ecliptic, J2000
VECTOR3 ECEF_pos;// position in ECEF
vessel->GetGlobalPos( G_pos );
oapiGlobalToLocal( hEarth, &G_pos, &ECEF_pos );
ECEF_pos = _V( ECEF_pos.x, ECEF_pos.z, ECEF_pos.y );
//// position in ECI ////
VECTOR3 ECEJ_pos;// position in "ECEJ", a.k.a., Earth-centered, ecliptic, J2000
VECTOR3 ECI_pos;// position in ECI
MATRIX3 Ro;// rotation matrix from "Earth-centered"-to-global coordinates
vessel->GetRelativePos( hEarth, ECEJ_pos );
oapiGetPlanetObliquityMatrix( hEarth, &Ro );
ECI_pos = mul( Inverse( Ro ), ECEJ_pos );
ECI_pos = _V( ECI_pos.x, /*not sure if should change this signal*/ECI_pos.z, ECI_pos.y );
writeCode:ECI_pos = mul( Inverse( Ro ), ECEJ_pos );
ECI_pos = tmul( Ro, ECEJ_pos );
Back to topic: expressing the velocity in the planet-relative frame (ECEF) requires two steps:
- rotating the velocity vector from the global to planet-local frame (this is the second term in MontBlanc's equation above)
- subtracting the planet's rotation component (this is the first term)
To get the planet's rotation matrix R(t), use oapiGetRotationMatrix. Note that Orbiter's definition of R is the inverse of MontBlanc's definition (rotation from local to global), so you need to use the tmul trick as discussed above for implementing the transformation.
To get the planet's rotation velocity [math]V_p[/math] at the vessel position, you need the magnitude [math]v_P = |V_p|[/math] and direction [math]\hat{V}_P = V_p/v_p[/math].
The magnitude is given by [math]v_P = \omega_P r[/math], where [math]\omega_P = 2\pi/T_P[/math] is the angular velocity (get T_P with oapiGetPlanetPeriod) and r is the distance of the vessel from the rotation axis, which, with your code above, is given by hypot(ECEF_pos.x, ECEF_pos.z).
The direction is given by rotating the the unit vector (0,0,1) from position (1,0,0) (i.e. lat=0, lon=0 on the unit sphere) to the current planet rotation:
[math]\hat{V}_P = \tilde{R}_\mathrm{rot}(t) [0,0,1]^T = [-\sin(s), 0, \cos(s)]^T[/math]
where [math]\tilde{R}_\mathrm{rot}(t)[/math] is given by Eq. 17 of Technotes\precession.pdf, and s is the current planet rotation angle, obtained by oapiGetPlanetCurrentRotation.
So putting everything together,
[math]V_\mathrm{ECEF} = R^T(t)V_\mathrm{glob} - v_P \hat{V}_P[/math]
Let me know if this works.
// DEBUG
VECTOR3 v, r;
MATRIX3 R;
OBJHANDLE hVessel = this->GetHandle();
OBJHANDLE hPlanet = this->GetSurfaceRef();
oapiGetRelativeVel(hVessel, hPlanet, &v);
oapiGetRelativePos(hVessel, hPlanet, &r);
oapiGetRotationMatrix(hPlanet, &R);
double T = oapiGetPlanetPeriod(hPlanet);
VECTOR3 vloc = tmul(R, v);
VECTOR3 rloc = tmul(R, r);
double s = atan2(rloc.z, rloc.x);
VECTOR3 vsurf = _V(-sin(s), 0, cos(s)) * PI2 / T*hypot(rloc.x, rloc.z);
VECTOR3 V = vloc - vsurf;
char cbuf[256];
sprintf(cbuf, "V.x=%+0.4lf, V.y=%+0.4lf, V.z=%+0.4lf", V.x, V.y, V.z);
skp->Text(0, cy + 20, cbuf, strlen(cbuf));
It should be giving 0,0,0 (or something very very small) when landed and it isn't... :uhh:
Rotating frame or non-rotating frame? And if rotating frame - proper axis and rotation rate?
AFAIK, when landed (and stopped) on the surface:
- ECEF velocity = 0
- ECI velocity = rotation of the planet at that latitude (Z component = 0), so 0 at the poles and maximum at the equator
- ECEF position = constant
- ECI position = non-constant (matches ECEF position once a day)
Yes, that is correct.
But if you have for example different rotation frames between your model and Orbiter, you should get ECEF velocity >> 0
Especially, if you have for example right-handed vs left-handed coordinate systems - then you might even get ECEF velocity (wrong) = 2 x ECI velocity (correct).
My bad. In my musings above "s" should not have been the planet rotation angle, but the vessel's longitude in the local planet frame, so s = atan2(ECEF_pos.z, ECEF_pos.x)
Just to make sure I didn't have another bug in that algorithm, I implemented it and it seems to work. Put the following into DeltaGlider::clbkDrawHUD:
Code:// DEBUG VECTOR3 v, r; MATRIX3 R; OBJHANDLE hVessel = this->GetHandle(); OBJHANDLE hPlanet = this->GetSurfaceRef(); oapiGetRelativeVel(hVessel, hPlanet, &v); oapiGetRelativePos(hVessel, hPlanet, &r); oapiGetRotationMatrix(hPlanet, &R); double T = oapiGetPlanetPeriod(hPlanet); VECTOR3 vloc = tmul(R, v); VECTOR3 rloc = tmul(R, r); double s = atan2(rloc.z, rloc.x); VECTOR3 vsurf = _V(-sin(s), 0, cos(s)) * PI2 / T*hypot(rloc.x, rloc.z); VECTOR3 V = vloc - vsurf; char cbuf[256]; sprintf(cbuf, "V.x=%+0.4lf, V.y=%+0.4lf, V.z=%+0.4lf", V.x, V.y, V.z); skp->Text(0, cy + 20, cbuf, strlen(cbuf));
VECTOR3 v;
vessel->GetRelativeVel( hEarth, v );
MATRIX3 Ro;
oapiGetPlanetObliquityMatrix( hEarth, &Ro );
ECI_vel = tmul( Ro, v );