ModelSpace
All Classes Namespaces Functions Variables Enumerations Pages
MRP.hpp
1/******************************************************************************
2* Copyright (c) ATTX LLC 2024. All Rights Reserved.
3*
4* This software and associated documentation (the "Software") are the
5* proprietary and confidential information of ATTX, LLC. The Software is
6* furnished under a license agreement between ATTX and the user organization
7* and may be used or copied only in accordance with the terms of the agreement.
8* Refer to 'license/attx_license.adoc' for standard license terms.
9*
10* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
11* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION
12* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or
13* transmitted in any form or by any means, for any purpose, without the express
14* written permission of ATTX, LLC.
15******************************************************************************/
16/*
17MRP header file
18
19Author: Alex Reynolds
20*/
21#ifndef MRP_HPP
22#define MRP_HPP
23
24#include <cmath>
25
26#include "core/Matrix.hpp"
27#include "core/CartesianVector.hpp"
28#include "core/safemath.hpp"
29#include "core/matrixmath.hpp"
30
31#include "DCM.hpp"
32#include "Quaternion.hpp"
33
34namespace clockwerk {
35
36 /// @brief Modified Rodrigues Parameter class definiton
37 ///
38 /// This file defines a simple Modified Rodrigues Parameter attitude representation for cartesian
39 /// coordinate systems. It is largely the same as the base vector,
40 /// with the following exceptions:
41 /// - Set to be 3 elements
42 /// - Functions defined to convert to other attitude representations
43 /// - Function defined to calculate rate of change as a function of omega
44 /// - Function defined to convert to shadow set of MRPs
45 ///
46 /// Naming conventions
47 /// ------------------
48 /// - All naming conventions and equations are per Analytical Mechanics of
49 /// Space Systems by Schaub and Junkins
50 /// - The omega vector is sometimes denoted by w and assumed frame consistent with
51 /// the attitude representation. For example, if a DCM represents the
52 /// relative orientation between two frames [BN] the omega vector is
53 /// assumed to be w_(B/N)
54 /// - The naming convention for all vectors is:
55 /// variablename_obj1_obj2__frameN (note the double underscore preceding frame)
56 /// and reads back as:
57 /// "variable variablename representing the relationship between obj1 and obj2
58 /// represented in frameN"
59 /// - Unless otherwise noted angles are in RADIANS
60 ///
61 /// NOTE: All attitude representations, including DCMs, are assumed to represent a
62 /// three dimensional, cartesian coordinate system because that is what they
63 /// are used, and in many cases defined, for.
64 template<typename T>
65 class MRP : public CartesianVector<T, 3> {
66 public:
67 /// @brief Default constructor initializes to all zeroes
68 MRP<T>();
69
70 /// Constructor for MRP class with initialization.
71 /// Initializes MRP to values passed in via array
72 MRP<T>(const T(&initial)[3]);
73
74 /// Copy constructor for MRP class. Copies data from MRP
75 /// object to the current instance
76 MRP<T>(const MRP<T> &initial);
77
78 /// Constructor for MRP class with initialization.
79 /// Initializes MRP to values passed in via array
80 MRP<T>(const std::array<T, 3> &initial);
81
82 /// Destructor -- doesn't do anything because we don't dynamically
83 /// allocate
84 ~MRP<T>() {}
85
86 /// @brief Function to convert current MRP to its shadow set
87 void shadow();
88
89 /// ---------------------------------------------------------------------------
90 /// Dynamics and kinematics functions
91 /// ---------------------------------------------------------------------------
92 /// @brief Function to calculate the rate of change in the current
93 /// representation based on the omega vector
94 /// @param omega_f1_f2__f1 Angular velocity vector for the attitude
95 /// representation - omega of frame 1 wrt frame 2
96 /// expressed in frame 1
97 /// @param mrpdot_f1_f2 Rate of change in the current Quaternion
98 void rate(const CartesianVector<T, 3> &omega_f1_f2__f1, Matrix<T, 3, 1> &mrpdot_f1_f2);
99
100 /// ---------------------------------------------------------------------------
101 /// Conversions to other attitude representations
102 /// ---------------------------------------------------------------------------
103 /// @brief Function to convert current attitude to DCM
104 /// @param PBR return of DCM in PBR case
105 /// @return Integer error code corresponding to errors in clockwerkerrors.h
106 int toDCM(DCM<T> &dcm_f1_f2) const;
107 DCM<T> toDCM() const;
108
109 /// @brief Function to convert current attitude to Quaternion
110 /// @param PBR return of Quaternion in PBR case
111 /// @return Integer error code corresponding to errors in clockwerkerrors.h
112 int toQuaternion(Quaternion<T> &quat_f1_f2) const;
113 Quaternion<T> toQuaternion() const;
114 };
115
116 template <typename T>
117 MRP<T>::MRP() :
118 CartesianVector<T, 3>() {}
119
120 template <typename T>
121 MRP<T>::MRP(const T(&initial)[3]) :
122 CartesianVector<T, 3>(initial) {}
123
124 template <typename T>
125 MRP<T>::MRP(const MRP<T> &initial) :
126 CartesianVector<T, 3>(initial) {}
127
128 template <typename T>
129 MRP<T>::MRP(const std::array<T, 3> &initial) :
130 CartesianVector<T, 3>(initial) {}
131
132 template <typename T>
133 void MRP<T>::shadow() {
134 /// Calculate intermediate parameter
135 T divisor;
136 dot(*this, *this, divisor);
137
138 /// Set shadow values
139 CartesianVector<T, 3>::values[0][0] = -CartesianVector<T, 3>::values[0][0]/divisor;
140 CartesianVector<T, 3>::values[1][0] = -CartesianVector<T, 3>::values[1][0]/divisor;
141 CartesianVector<T, 3>::values[2][0] = -CartesianVector<T, 3>::values[2][0]/divisor;
142 }
143
144 template <typename T>
145 void MRP<T>::rate(const CartesianVector<T, 3> &omega_f1_f2__f1, Matrix<T, 3, 1> &mrpdot_f1_f2) {
146 /// Pre-calculate parameters used multiple times for speed
147 T s1Squared, s2Squared, s3Squared, s1s2, s1s3, s2s3;
148 T sigSquared = T();
149 CartesianVector<T, 3>::normSquared(sigSquared);
150 s1Squared = CartesianVector<T, 3>::values[0][0]*CartesianVector<T, 3>::values[0][0];
151 s2Squared = CartesianVector<T, 3>::values[1][0]*CartesianVector<T, 3>::values[1][0];
152 s3Squared = CartesianVector<T, 3>::values[2][0]*CartesianVector<T, 3>::values[2][0];
153 s1s2 = CartesianVector<T, 3>::values[0][0]*CartesianVector<T, 3>::values[1][0];
154 s1s3 = CartesianVector<T, 3>::values[0][0]*CartesianVector<T, 3>::values[2][0];
155 s2s3 = CartesianVector<T, 3>::values[1][0]*CartesianVector<T, 3>::values[2][0];
156
157 /// Calculate MRP rate of change
158 mrpdot_f1_f2.values[0][0] = 0.25*(1 - sigSquared + 2.0*s1Squared)*omega_f1_f2__f1.values[0][0] +
159 0.5*((s1s2 - CartesianVector<T, 3>::values[2][0])*omega_f1_f2__f1.values[1][0] + (s1s3 + CartesianVector<T, 3>::values[1][0])*omega_f1_f2__f1.values[2][0]);
160 mrpdot_f1_f2.values[1][0] = 0.25*(1 - sigSquared + 2.0*s2Squared)*omega_f1_f2__f1.values[1][0] +
161 0.5*((s1s2 + CartesianVector<T, 3>::values[2][0])*omega_f1_f2__f1.values[0][0] + (s2s3 - CartesianVector<T, 3>::values[0][0])*omega_f1_f2__f1.values[2][0]);
162 mrpdot_f1_f2.values[2][0] = 0.25*(1 - sigSquared + 2.0*s3Squared)*omega_f1_f2__f1.values[2][0] +
163 0.5*((s1s3 - CartesianVector<T, 3>::values[1][0])*omega_f1_f2__f1.values[0][0] + (s2s3 + CartesianVector<T, 3>::values[0][0])*omega_f1_f2__f1.values[1][0]);
164 }
165
166 template <typename T>
167 int MRP<T>::toDCM(DCM<T> &dcm_f1_f2) const {
168 /// Pre-calculate parameters used multiple times for speed
169 T s1Squared, s2Squared, s3Squared, s1s2, s1s3, s2s3,
170 onePlusSigSquared, oneMinusSigSquared, oneMinusSigSquaredSquared,
171 multiplier;
172 T sigSquared = T();
173 CartesianVector<T, 3>::normSquared(sigSquared);
174 s1Squared = CartesianVector<T, 3>::values[0][0]*CartesianVector<T, 3>::values[0][0];
175 s2Squared = CartesianVector<T, 3>::values[1][0]*CartesianVector<T, 3>::values[1][0];
176 s3Squared = CartesianVector<T, 3>::values[2][0]*CartesianVector<T, 3>::values[2][0];
177 s1s2 = CartesianVector<T, 3>::values[0][0]*CartesianVector<T, 3>::values[1][0];
178 s1s3 = CartesianVector<T, 3>::values[0][0]*CartesianVector<T, 3>::values[2][0];
179 s2s3 = CartesianVector<T, 3>::values[1][0]*CartesianVector<T, 3>::values[2][0];
180 onePlusSigSquared = 1 + sigSquared;
181 oneMinusSigSquared = 1 - sigSquared;
182 oneMinusSigSquaredSquared = oneMinusSigSquared*oneMinusSigSquared;
183
184 /// Now calculate our DCM
185 dcm_f1_f2.values[0][0] = 4*(s1Squared - s2Squared - s3Squared) + oneMinusSigSquaredSquared;
186 dcm_f1_f2.values[0][1] = 8*s1s2 + 4*CartesianVector<T, 3>::values[2][0]*oneMinusSigSquared;
187 dcm_f1_f2.values[0][2] = 8*s1s3 - 4*CartesianVector<T, 3>::values[1][0]*oneMinusSigSquared;
188 dcm_f1_f2.values[1][0] = 8*s1s2 - 4*CartesianVector<T, 3>::values[2][0]*oneMinusSigSquared;
189 dcm_f1_f2.values[1][1] = 4*(s2Squared - s1Squared - s3Squared) + oneMinusSigSquaredSquared;
190 dcm_f1_f2.values[1][2] = 8*s2s3 + 4*CartesianVector<T, 3>::values[0][0]*oneMinusSigSquared;
191 dcm_f1_f2.values[2][0] = 8*s1s3 + 4*CartesianVector<T, 3>::values[1][0]*oneMinusSigSquared;
192 dcm_f1_f2.values[2][1] = 8*s2s3 - 4*CartesianVector<T, 3>::values[0][0]*oneMinusSigSquared;
193 dcm_f1_f2.values[2][2] = 4*(s3Squared - s1Squared - s2Squared) + oneMinusSigSquaredSquared;
194
195 /// Multiply our DCM by our multiplication factor
196 int err = safeDivide(1, onePlusSigSquared*onePlusSigSquared, multiplier);
197 if(err) {return err;}
198 multiply(multiplier, dcm_f1_f2, dcm_f1_f2);
199
200 return NO_ERROR;
201 }
202 template <typename T>
203 DCM<T> MRP<T>::toDCM() const {
204 DCM<T> tmp;
205 toDCM(tmp);
206 return tmp;
207 }
208
209 template <typename T>
210 int MRP<T>::toQuaternion(Quaternion<T> &quat_f1_f2) const {
211 /// Intermediate parameters
212 T divisor;
213 T sigSquared = T();
214 CartesianVector<T, 3>::normSquared(sigSquared);
215 divisor = 1 + sigSquared;
216 int err;
217
218 /// Now get our beta values
219 err = safeDivide(1 - sigSquared, divisor, quat_f1_f2.values[0][0]);
220 if(err) {return err;}
221 err = safeDivide(2*CartesianVector<T, 3>::values[0][0], divisor, quat_f1_f2.values[1][0]);
222 if(err) {return err;}
223 err = safeDivide(2*CartesianVector<T, 3>::values[1][0], divisor, quat_f1_f2.values[2][0]);
224 if(err) {return err;}
225 err = safeDivide(2*CartesianVector<T, 3>::values[2][0], divisor, quat_f1_f2.values[3][0]);
226 if(err) {return err;}
227
228 return NO_ERROR;
229 }
230 template <typename T>
231 Quaternion<T> MRP<T>::toQuaternion() const {
232 Quaternion<T> tmp;
233 toQuaternion(tmp);
234 return tmp;
235 }
236
237}
238
239#endif
Standard vector class derived from Matrix.
Definition CartesianVector.hpp:39
Class defining a direction cosine matrix inherited from Matrix.
Definition DCM.hpp:71
void shadow()
Function to convert current MRP to its shadow set.
Definition MRP.hpp:133
int toDCM(DCM< T > &dcm_f1_f2) const
Function to convert current attitude to DCM.
Definition MRP.hpp:167
int toQuaternion(Quaternion< T > &quat_f1_f2) const
Function to convert current attitude to Quaternion.
Definition MRP.hpp:210
void rate(const CartesianVector< T, 3 > &omega_f1_f2__f1, Matrix< T, 3, 1 > &mrpdot_f1_f2)
Function to calculate the rate of change in the current representation based on the omega vector.
Definition MRP.hpp:145
Matrix math implementation.
Definition Matrix.hpp:54
#define NO_ERROR
Definition clockwerkerrors.h:31