0.2.0
Loading...
Searching...
No Matches
CoordinateFrames.hpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
40
41#pragma once
42
43#include <cmath>
44#include "util/Eigen.hpp"
45#include "util/Logger.hpp"
46
49#include "Navigation/Transformations/Units.hpp"
50
51namespace NAV::trafo
52{
53namespace internal
54{
61template<typename Derived>
62Eigen::Vector3<typename Derived::Scalar> lla2ecef(const Eigen::MatrixBase<Derived>& lla_position, typename Derived::Scalar a, typename Derived::Scalar e_squared)
63{
64 const auto& latitude = lla_position(0); // 𝜙 Geodetic latitude
65 const auto& longitude = lla_position(1); // λ Geodetic longitude
66 const auto& altitude = lla_position(2); // Altitude (Height above ground)
67
68 // Radius of curvature of the ellipsoid in the prime vertical plane,
69 // i.e., the plane containing the normal at P and perpendicular to the meridian (eq. 1.81)
70 auto R_E = calcEarthRadius_E(latitude, a, e_squared);
71
72 // Jekeli, 2001 (eq. 1.80) (see Torge, 1991, for further details)
73 return { (R_E + altitude) * std::cos(latitude) * std::cos(longitude),
74 (R_E + altitude) * std::cos(latitude) * std::sin(longitude),
75 (R_E * (1 - e_squared) + altitude) * std::sin(latitude) };
76}
77
85template<typename Derived>
86Eigen::Vector3<typename Derived::Scalar> ecef2lla(const Eigen::MatrixBase<Derived>& e_position,
87 typename Derived::Scalar a, typename Derived::Scalar b, typename Derived::Scalar e_squared)
88{
89 if (e_position.isZero()) { return { 0, 0, -a }; }
90
91 auto x = e_position(0);
92 auto y = e_position(1);
93 auto z = e_position(2);
94
95 // Calculate longitude
96
97 auto lon = std::atan2(y, x);
98
99 // Start computing intermediate variables needed to compute altitude
100
101 auto p = e_position.head(2).norm();
102 auto E = std::sqrt(a * a - b * b);
103 auto F = 54 * std::pow(b * z, 2);
104 auto G = p * p + (1 - e_squared) * z * z - e_squared * E * E;
105 auto c = e_squared * e_squared * F * p * p / std::pow(G, 3);
106 auto s = std::pow(1 + c + std::sqrt(c * c + 2 * c), 1.0 / 3.0);
107 auto P = (F / (3 * G * G)) / std::pow(s + (1.0 / s) + 1, 2);
108 auto Q = std::sqrt(1 + 2 * e_squared * e_squared * P);
109 auto k_1 = -P * e_squared * p / (1 + Q);
110 auto k_2 = 0.5 * a * a * (1 + 1 / Q);
111 auto k_3 = -P * (1 - e_squared) * z * z / (Q * (1 + Q));
112 auto k_4 = -0.5 * P * p * p;
113 auto r_0 = k_1 + std::sqrt(k_2 + k_3 + k_4);
114 auto k_5 = (p - e_squared * r_0);
115 auto U = std::sqrt(k_5 * k_5 + z * z);
116 auto V = std::sqrt(k_5 * k_5 + (1 - e_squared) * z * z);
117
118 auto alt = U * (1 - (b * b / (a * V)));
119
120 // Compute additional values required for computing latitude
121
122 auto z_0 = (b * b * z) / (a * V);
123 auto e_p = (a / b) * std::sqrt(e_squared);
124
125 auto lat = std::atan((z + z_0 * (e_p * e_p)) / p);
126
127 return { lat, lon, alt };
128}
129} // namespace internal
130
134template<typename Derived>
135[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> quat2eulerZYX(const Eigen::QuaternionBase<Derived>& q)
136{
137 // Given range [-pi:pi] x [-pi:pi] x [0:pi]
138 Eigen::Vector3<typename Derived::Scalar> XYZ = q.toRotationMatrix().eulerAngles(2, 1, 0).reverse();
139
140 // Wanted range (-pi:pi] x (-pi/2:pi/2] x (-pi:pi]
141 if (XYZ.y() >= M_PI / 2.0 || XYZ.y() <= -M_PI / 2.0)
142 {
143 typename Derived::Scalar x = XYZ.x() > 0 ? XYZ.x() - M_PI : XYZ.x() + M_PI;
144 typename Derived::Scalar y = XYZ.y() >= M_PI / 2.0 ? -(XYZ.y() - M_PI) : -(XYZ.y() + M_PI);
145 typename Derived::Scalar z = XYZ.z() - M_PI;
146
147 XYZ = { x, y, z };
148 }
149
150 return XYZ;
151}
152
157template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
158[[nodiscard]] Eigen::Quaternion<Scalar> e_Quat_i(Scalar time, Scalar omega_ie = InsConst<Scalar>::omega_ie)
159{
160 // Initialize angle-axis rotation from an angle in radian and an axis which must be normalized.
161 Eigen::AngleAxis<Scalar> zAngle(-omega_ie * time, Eigen::Vector3<Scalar>::UnitZ());
162
163 return Eigen::Quaternion<Scalar>(zAngle).normalized();
164}
165
170template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
171[[nodiscard]] Eigen::Quaternion<Scalar> i_Quat_e(Scalar time, Scalar omega_ie = InsConst<Scalar>::omega_ie)
172{
173 return e_Quat_i(time, omega_ie).conjugate();
174}
175
180template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
181[[nodiscard]] Eigen::Quaternion<Scalar> e_Quat_n(Scalar latitude, Scalar longitude)
182{
183 // Initialize angle-axis rotation from an angle in radian and an axis which must be normalized.
184 // Eigen uses here a different sign convention as the physical system.
185 Eigen::AngleAxis<Scalar> longitudeAngle(longitude, Eigen::Vector3<Scalar>::UnitZ());
186 Eigen::AngleAxis<Scalar> latitudeAngle(-M_PI_2 - latitude, Eigen::Vector3<Scalar>::UnitY());
187
188 return (longitudeAngle * latitudeAngle).normalized();
189}
190
195template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
196[[nodiscard]] Eigen::Quaternion<Scalar> n_Quat_e(Scalar latitude, Scalar longitude)
197{
198 return e_Quat_n(latitude, longitude).conjugate();
199}
200
206template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
207[[nodiscard]] Eigen::Quaternion<Scalar> b_Quat_n(Scalar roll, Scalar pitch, Scalar yaw)
208{
209 // Initialize angle-axis rotation from an angle in radian and an axis which must be normalized.
210 // Eigen uses here a different sign convention as the physical system.
211 Eigen::AngleAxis<Scalar> rollAngle(-roll, Eigen::Vector3<Scalar>::UnitX());
212 Eigen::AngleAxis<Scalar> pitchAngle(-pitch, Eigen::Vector3<Scalar>::UnitY());
213 Eigen::AngleAxis<Scalar> yawAngle(-yaw, Eigen::Vector3<Scalar>::UnitZ());
214
215 return (rollAngle * pitchAngle * yawAngle).normalized();
216}
217
221template<typename Derived>
222[[nodiscard]] Eigen::Quaternion<typename Derived::Scalar> b_Quat_n(const Eigen::MatrixBase<Derived>& rollPitchYaw)
223{
224 return b_Quat_n(rollPitchYaw(0), rollPitchYaw(1), rollPitchYaw(2));
225}
226
232template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
233[[nodiscard]] Eigen::Quaternion<Scalar> n_Quat_b(Scalar roll, Scalar pitch, Scalar yaw)
234{
235 return b_Quat_n(roll, pitch, yaw).conjugate();
236}
237
241template<typename Derived>
242[[nodiscard]] Eigen::Quaternion<typename Derived::Scalar> n_Quat_b(const Eigen::MatrixBase<Derived>& rollPitchYaw)
243{
244 return n_Quat_b(rollPitchYaw(0), rollPitchYaw(1), rollPitchYaw(2));
245}
246
252template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
253[[nodiscard]] Eigen::Quaternion<Scalar> b_Quat_p(Scalar mountingAngleX, Scalar mountingAngleY, Scalar mountingAngleZ)
254{
255 // Initialize angle-axis rotation from an angle in radian and an axis which must be normalized.
256 Eigen::AngleAxis<Scalar> xAngle(-mountingAngleX, Eigen::Vector3<Scalar>::UnitX());
257 Eigen::AngleAxis<Scalar> yAngle(-mountingAngleY, Eigen::Vector3<Scalar>::UnitY());
258 Eigen::AngleAxis<Scalar> zAngle(-mountingAngleZ, Eigen::Vector3<Scalar>::UnitZ());
259
260 return (xAngle * yAngle * zAngle).normalized();
261}
262
268template<typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
269[[nodiscard]] Eigen::Quaternion<Scalar> p_Quat_b(Scalar mountingAngleX, Scalar mountingAngleY, Scalar mountingAngleZ)
270{
271 return b_Quat_p(mountingAngleX, mountingAngleY, mountingAngleZ).conjugate();
272}
273
277template<typename Derived>
278[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> lla2ecef_WGS84(const Eigen::MatrixBase<Derived>& lla_position)
279{
281}
282
286template<typename Derived>
287[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> lla2ecef_GRS80(const Eigen::MatrixBase<Derived>& lla_position)
288{
290}
291
295template<typename Derived>
296[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> ecef2lla_WGS84(const Eigen::MatrixBase<Derived>& e_position)
297{
298 return internal::ecef2lla(e_position,
302}
303
307template<typename Derived>
308[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> ecef2lla_GRS80(const Eigen::MatrixBase<Derived>& e_position)
309{
310 return internal::ecef2lla(e_position,
314}
315
322template<typename DerivedA, typename DerivedB>
323[[nodiscard]] Eigen::Vector3<typename DerivedA::Scalar> ecef2ned(const Eigen::MatrixBase<DerivedA>& e_position, const Eigen::MatrixBase<DerivedB>& lla_position_ref)
324{
325 const auto& latitude_ref = lla_position_ref(0); // 𝜙 Geodetic latitude
326 const auto& longitude_ref = lla_position_ref(1); // λ Geodetic longitude
327
328 auto e_position_ref = lla2ecef_WGS84(lla_position_ref);
329
330 Eigen::Matrix3<typename DerivedA::Scalar> R_ne;
331 // clang-format off
332 R_ne << -std::sin(latitude_ref) * std::cos(longitude_ref), -std::sin(latitude_ref) * std::sin(longitude_ref), std::cos(latitude_ref),
333 -std::sin(longitude_ref) , std::cos(longitude_ref) , 0 ,
334 -std::cos(latitude_ref) * std::cos(longitude_ref), -std::cos(latitude_ref) * std::sin(longitude_ref), -std::sin(latitude_ref);
335 // clang-format on
336
337 return R_ne * (e_position - e_position_ref);
338}
339
346template<typename DerivedA, typename DerivedB>
347[[nodiscard]] Eigen::Vector3<typename DerivedA::Scalar> ned2ecef(const Eigen::MatrixBase<DerivedA>& n_position, const Eigen::MatrixBase<DerivedB>& lla_position_ref)
348{
349 const auto& latitude_ref = lla_position_ref(0); // 𝜙 Geodetic latitude
350 const auto& longitude_ref = lla_position_ref(1); // λ Geodetic longitude
351
352 auto e_position_ref = lla2ecef_WGS84(lla_position_ref);
353
354 Eigen::Matrix3<typename DerivedA::Scalar> R_en;
355 // clang-format off
356 R_en << -std::sin(latitude_ref) * std::cos(longitude_ref), -std::sin(longitude_ref), -std::cos(latitude_ref) * std::cos(longitude_ref),
357 -std::sin(latitude_ref) * std::sin(longitude_ref), std::cos(longitude_ref), -std::cos(latitude_ref) * std::sin(longitude_ref),
358 std::cos(latitude_ref) , 0 , -std::sin(latitude_ref) ;
359 // clang-format on
360
361 return e_position_ref + R_en * n_position;
362}
363
368template<typename Derived>
369[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> pz90toWGS84_pos(const Eigen::MatrixBase<Derived>& pz90_pos)
370{
371 typename Derived::Scalar m = -0.008e-6;
372 auto omega_x = static_cast<typename Derived::Scalar>(-2.3_mas);
373 auto omega_y = static_cast<typename Derived::Scalar>(3.54_mas);
374 auto omega_z = static_cast<typename Derived::Scalar>(-4.21_mas);
375 Eigen::Vector3<typename Derived::Scalar> dX{ -0.013, 0.106, 0.022 };
376
377 Eigen::Matrix3<typename Derived::Scalar> T;
378 T << 1, -omega_z, omega_y,
379 omega_z, 1, -omega_x,
380 -omega_y, omega_x, 1;
381
382 return 1.0 / (1.0 + m) * T * (pz90_pos - dX);
383}
384
389template<typename DerivedA, typename DerivedB>
390[[nodiscard]] Eigen::Vector3<typename DerivedA::Scalar> pz90toWGS84(const Eigen::MatrixBase<DerivedA>& pz90, const Eigen::MatrixBase<DerivedB>& pz90_pos)
391{
392 return pz90toWGS84_pos(pz90_pos + pz90) - pz90toWGS84_pos(pz90_pos);
393}
394
400template<typename Derived>
401[[nodiscard]] Eigen::Vector3<typename Derived::Scalar> sph2ecef(const Eigen::MatrixBase<Derived>& position_s,
402 const typename Derived::Scalar& elevation,
403 const typename Derived::Scalar& azimuth)
404{
405 Eigen::Matrix3<typename Derived::Scalar> R_se;
406 R_se << std::sin(elevation) * std::cos(azimuth), std::cos(elevation) * std::cos(azimuth), -std::sin(azimuth),
407 std::sin(elevation) * std::sin(azimuth), std::cos(elevation) * std::sin(azimuth), std::cos(azimuth),
408 std::cos(elevation), -std::sin(elevation), 0.0;
409
410 return R_se * position_s;
411}
412
413} // namespace NAV::trafo
Holds all Constants.
Eigen::Vector3< typename Derived::Scalar > ecef2lla_WGS84(const Eigen::MatrixBase< Derived > &e_position)
Converts Earth-centered-Earth-fixed coordinates into latitude, longitude and altitude using WGS84.
Definition CoordinateFrames.hpp:296
Eigen::Vector3< typename Derived::Scalar > lla2ecef(const Eigen::MatrixBase< Derived > &lla_position, typename Derived::Scalar a, typename Derived::Scalar e_squared)
Converts latitude, longitude and altitude into Earth-centered-Earth-fixed coordinates.
Definition CoordinateFrames.hpp:62
Eigen::Quaternion< Scalar > i_Quat_e(Scalar time, Scalar omega_ie=InsConst< Scalar >::omega_ie)
Quaternion for rotations from Earth-centered-Earth-fixed to inertial frame.
Definition CoordinateFrames.hpp:171
Eigen::Quaternion< Scalar > e_Quat_i(Scalar time, Scalar omega_ie=InsConst< Scalar >::omega_ie)
Quaternion for rotations from inertial to Earth-centered-Earth-fixed frame.
Definition CoordinateFrames.hpp:158
Eigen::Quaternion< Scalar > b_Quat_p(Scalar mountingAngleX, Scalar mountingAngleY, Scalar mountingAngleZ)
Quaternion for rotations from platform to body frame.
Definition CoordinateFrames.hpp:253
Eigen::Vector3< typename DerivedA::Scalar > ecef2ned(const Eigen::MatrixBase< DerivedA > &e_position, const Eigen::MatrixBase< DerivedB > &lla_position_ref)
Converts ECEF coordinates into local NED coordinates.
Definition CoordinateFrames.hpp:323
Eigen::Quaternion< Scalar > n_Quat_b(Scalar roll, Scalar pitch, Scalar yaw)
Quaternion for rotations from body to navigation frame.
Definition CoordinateFrames.hpp:233
Eigen::Vector3< typename Derived::Scalar > pz90toWGS84_pos(const Eigen::MatrixBase< Derived > &pz90_pos)
Converts PZ-90.11 coordinates to WGS84 coordinates.
Definition CoordinateFrames.hpp:369
Eigen::Vector3< typename DerivedA::Scalar > pz90toWGS84(const Eigen::MatrixBase< DerivedA > &pz90, const Eigen::MatrixBase< DerivedB > &pz90_pos)
Converts PZ-90.11 vectors to WGS84 frame.
Definition CoordinateFrames.hpp:390
Eigen::Vector3< typename Derived::Scalar > sph2ecef(const Eigen::MatrixBase< Derived > &position_s, const typename Derived::Scalar &elevation, const typename Derived::Scalar &azimuth)
Converts spherical Earth-centered-Earth-fixed coordinates into cartesian coordinates.
Definition CoordinateFrames.hpp:401
Eigen::Quaternion< Scalar > b_Quat_n(Scalar roll, Scalar pitch, Scalar yaw)
Quaternion for rotations from navigation to body frame.
Definition CoordinateFrames.hpp:207
Eigen::Quaternion< Scalar > p_Quat_b(Scalar mountingAngleX, Scalar mountingAngleY, Scalar mountingAngleZ)
Quaternion for rotations from body to platform frame.
Definition CoordinateFrames.hpp:269
Eigen::Quaternion< Scalar > n_Quat_e(Scalar latitude, Scalar longitude)
Quaternion for rotations from Earth-fixed to navigation frame.
Definition CoordinateFrames.hpp:196
Eigen::Vector3< typename Derived::Scalar > ecef2lla(const Eigen::MatrixBase< Derived > &e_position, typename Derived::Scalar a, typename Derived::Scalar b, typename Derived::Scalar e_squared)
Converts Earth-centered-Earth-fixed coordinates into latitude, longitude and altitude.
Definition CoordinateFrames.hpp:86
Eigen::Vector3< typename Derived::Scalar > quat2eulerZYX(const Eigen::QuaternionBase< Derived > &q)
Converts the quaternion to Euler rotation angles with rotation sequence ZYX.
Definition CoordinateFrames.hpp:135
Eigen::Vector3< typename Derived::Scalar > lla2ecef_GRS80(const Eigen::MatrixBase< Derived > &lla_position)
Converts latitude, longitude and altitude into Earth-centered-Earth-fixed coordinates using GRS90.
Definition CoordinateFrames.hpp:287
Eigen::Vector3< typename DerivedA::Scalar > ned2ecef(const Eigen::MatrixBase< DerivedA > &n_position, const Eigen::MatrixBase< DerivedB > &lla_position_ref)
Converts local NED coordinates into ECEF coordinates.
Definition CoordinateFrames.hpp:347
Eigen::Quaternion< Scalar > e_Quat_n(Scalar latitude, Scalar longitude)
Quaternion for rotations from navigation to Earth-fixed frame.
Definition CoordinateFrames.hpp:181
Eigen::Vector3< typename Derived::Scalar > lla2ecef_WGS84(const Eigen::MatrixBase< Derived > &lla_position)
Converts latitude, longitude and altitude into Earth-centered-Earth-fixed coordinates using WGS84.
Definition CoordinateFrames.hpp:278
Eigen::Vector3< typename Derived::Scalar > ecef2lla_GRS80(const Eigen::MatrixBase< Derived > &e_position)
Converts Earth-centered-Earth-fixed coordinates into latitude, longitude and altitude using GRS90.
Definition CoordinateFrames.hpp:308
Vector space operations.
Functions concerning the ellipsoid model.
Scalar calcEarthRadius_E(const Scalar &latitude, const Scalar &a=InsConst< Scalar >::WGS84::a, const Scalar &e_squared=InsConst<>::WGS84::e_squared)
Calculates the East/West (prime vertical) earth radius.
Definition Ellipsoid.hpp:57
Utility class for logging to console and file.
Constants.
Definition Constants.hpp:26