30
30
from Basilisk import __path__
31
31
from Basilisk .architecture import messaging
32
32
from Basilisk .fswAlgorithms import flybyPoint
33
- from Basilisk .utilities import SimulationBaseClass , macros , unitTestSupport
34
33
from Basilisk .utilities import RigidBodyKinematics as rbk
34
+ from Basilisk .utilities import SimulationBaseClass , macros , unitTestSupport
35
35
36
36
bskPath = __path__ [0 ]
37
37
fileName = os .path .basename (os .path .splitext (__file__ )[0 ])
38
38
39
39
40
- @pytest .mark .parametrize ("initPos" , [[- 5e7 , 7.5e6 , 5e5 ]]) # m - r_CN_N
41
- @pytest .mark .parametrize ("initVel" , [[2e4 , 0 , 0 ]]) # m/s - v_CN_N
42
- @pytest .mark .parametrize ("dTsim" , [10 , 100 ]) # s
43
- @pytest .mark .parametrize ("dTfilter" , [0 , 60 , 600 ]) # s
44
- @pytest .mark .parametrize ("signOrbitNormal" , [1 , - 1 ])
45
- @pytest .mark .parametrize ("accuracy" , [1e-12 ])
46
- def test_flybyPoint (show_plots , initPos , initVel , dTsim , dTfilter , signOrbitNormal , accuracy ):
40
+ @pytest .mark .parametrize ("initial_position" , [[- 5e7 , 7.5e6 , 5e5 ]]) # m - r_CN_N
41
+ @pytest .mark .parametrize ("initial_velocity" , [[2e4 , 0 , 0 ]]) # m/s - v_CN_N
42
+ @pytest .mark .parametrize ("filter_dt" , [1 , 60 ]) # s
43
+ @pytest .mark .parametrize ("orbit_normal_sign" , [1 , - 1 ])
44
+ @pytest .mark .parametrize ("max_rate" , [0 , 0.01 ])
45
+ @pytest .mark .parametrize ("max_acceleration" , [0 , 1E-7 ])
46
+ def test_flybyPoint (show_plots , initial_position , initial_velocity , filter_dt , orbit_normal_sign , max_rate ,
47
+ max_acceleration ):
47
48
r"""
48
49
**Validation Test Description**
49
50
@@ -59,219 +60,186 @@ def test_flybyPoint(show_plots, initPos, initVel, dTsim, dTfilter, signOrbitNorm
59
60
Correctness is tested assessing whether the computed hill frame moves according to the motion of the spacecraft.
60
61
61
62
Args:
62
- initPos[3] (m): initial position of the spacecraft w.r.t. the body/origin
63
- initVel[3] (m): initial velocity of the spacecraft w.r.t. the body/origin
64
- dTsim (s): simulation time step
65
- dTfilter (s): time between two consecutive reads of the input message
66
- signOrbitNormal (-): sign of the reference frame "out of plane" vector (orbit normal or anti orbit normal)
67
- accuracy: tolerance on the result.
63
+ initial_position[3] (m): initial position of the spacecraft w.r.t. the body/origin
64
+ initial_velocity[3] (m): initial velocity of the spacecraft w.r.t. the body/origin
65
+ filter_dt (s): time between two consecutive reads of the input message
66
+ orbit_normal_sign (-): sign of the reference frame "out of plane" vector (orbit normal or anti orbit normal)
68
67
69
68
**Description of Variables Being Tested**
70
69
71
- The referene attitude :math:`\sigma_\mathcal{R/N}`, reference angular rates :math:`\omega_\mathcal{R/N}` and
70
+ The reference attitude :math:`\sigma_\mathcal{R/N}`, reference angular rates :math:`\omega_\mathcal{R/N}` and
72
71
angular accelerations :math:`\dot{\omega}_\mathcal{R/N}` are tested. These are compared to the analytical results
73
72
expected from the rectilinear motion described in the documentation of :ref:`flybyPoint`.
74
73
The reference attitude is mapped to the corresponding reference frame, and each axis of the reference frame is
75
74
tested for correctness. The angular rate and acceleration vectors are tested against the analytical result,
76
75
expressed in R-frame coordinates.
77
76
"""
78
77
# each test method requires a single assert method to be called
79
- flybyPointTestFunction (show_plots , initPos , initVel , dTsim , dTfilter , signOrbitNormal , accuracy )
80
-
81
-
82
- def flybyPointTestFunction (show_plots , initPos , initVel , dTsim , dTfilter , signOrbitNormal , accuracy ):
83
- testFailCount = 0 # zero unit test result counter
84
- testMessages = [] # create empty array to store test log messages
85
- unitTaskName = "unitTask" # arbitrary name (don't change)
86
- unitProcessName = "TestProcess" # arbitrary name (don't change)
87
-
88
- # Create a sim module as an empty container
89
- unitTestSim = SimulationBaseClass .SimBaseClass ()
90
-
91
- # Create test thread
92
- testProcessRate = macros .sec2nano (dTsim ) # update process rate update time
93
- testProc = unitTestSim .CreateNewProcess (unitProcessName )
94
- testProc .addTask (unitTestSim .CreateNewTask (unitTaskName , testProcessRate ))
95
-
96
- # Create simulation variable names
97
- unitTaskName = "unitTask"
98
- unitProcessName = "unitProcess"
78
+ flybyPointTestFunction (show_plots , initial_position , initial_velocity , filter_dt , orbit_normal_sign ,
79
+ max_rate , max_acceleration )
99
80
100
- # Create a sim module as an empty container
101
- unitTestSim = SimulationBaseClass .SimBaseClass ()
102
81
103
- # create the simulation process
104
- testProcess = unitTestSim .CreateNewProcess (unitProcessName )
105
-
106
- # create the dynamics task and specify the integration update time
107
- simulationTimeStep = macros .sec2nano (dTsim )
108
- testProcess .addTask (unitTestSim .CreateNewTask (unitTaskName , simulationTimeStep ))
82
+ def flybyPointTestFunction (show_plots , initial_position , initial_velocity , filter_dt , orbit_normal_sign ,
83
+ max_rate , max_acceleration ):
84
+ # setup simulation environment
85
+ sim_dt = 10
86
+ unit_test_sim = SimulationBaseClass .SimBaseClass ()
87
+ process_rate = macros .sec2nano (sim_dt )
88
+ test_process = unit_test_sim .CreateNewProcess ("unit_process" )
89
+ test_process .addTask (unit_test_sim .CreateNewTask ("unit_task" , process_rate ))
109
90
110
91
# setup flybyPoint guidance module
111
- flybyGuid = flybyPoint .FlybyPoint ()
112
- flybyGuid .ModelTag = "flybyPoint"
113
- flybyGuid .setTimeBetweenFilterData (dTfilter )
114
- flybyGuid .setToleranceForCollinearity (1E-5 )
115
- flybyGuid .setSignOfOrbitNormalFrameVector (signOrbitNormal )
116
- unitTestSim . AddModelToTask ( unitTaskName , flybyGuid )
117
-
118
- inputData = messaging . NavTransMsgPayload ( )
119
- inputData . v_BN_N = np . array ( initVel )
120
- filterInMsg = messaging .NavTransMsg ()
121
- flybyGuid . filterInMsg . subscribeTo ( filterInMsg )
122
-
123
- #
124
- # Setup data logging before the simulation is initialized
125
- #
126
- attRefLog = flybyGuid .attRefOutMsg .recorder ()
127
- unitTestSim .AddModelToTask (unitTaskName , attRefLog )
128
-
129
- unitTestSim .InitializeSimulation ()
130
- dataPos = []
131
- dataVel = []
132
- for i in range (round (9 * 600 / dTsim )):
133
- dataPos .append (np .array (initPos ) + np .array (initVel ) * (i * dTsim ))
134
- dataVel .append (np .array (initVel ))
135
- inputData .timeTag = macros .sec2nano (i * dTsim )
136
- inputData .r_BN_N = dataPos [i ]
137
- filterInMsg .write (inputData , unitTestSim .TotalSim .getCurrentNanos ())
138
- unitTestSim .ConfigureStopTime (macros .sec2nano ((i + 1 ) * dTsim ) - 1 )
139
- unitTestSim .ExecuteSimulation ()
140
-
141
- # retrieve the logged data
142
- refAtt = attRefLog .sigma_RN
143
- refRate = attRefLog .omega_RN_N
144
- refAcc = attRefLog .domega_RN_N
145
- timeData = attRefLog .times () * macros .NANO2MIN
92
+ flyby_guidance = flybyPoint .FlybyPoint ()
93
+ flyby_guidance .ModelTag = "flybyPoint"
94
+ flyby_guidance .setTimeBetweenFilterData (filter_dt )
95
+ flyby_guidance .setToleranceForCollinearity (1E-5 )
96
+ flyby_guidance .setSignOfOrbitNormalFrameVector (orbit_normal_sign )
97
+ flyby_guidance . setMaximumRateThreshold ( max_rate )
98
+ flyby_guidance . setMaximumAccelerationThreshold ( max_acceleration )
99
+ unit_test_sim . AddModelToTask ( "unit_task" , flyby_guidance )
100
+
101
+ input_data = messaging .NavTransMsgPayload ()
102
+ input_data . v_BN_N = np . array ( initial_velocity )
103
+ filter_msg = messaging . NavTransMsg ()
104
+ flyby_guidance . filterInMsg . subscribeTo ( filter_msg )
105
+
106
+ # Setup data logging before the simulation is initialized
107
+ attitude_reference_log = flyby_guidance .attRefOutMsg .recorder ()
108
+ unit_test_sim .AddModelToTask ("unit_task" , attitude_reference_log )
109
+
110
+ unit_test_sim .InitializeSimulation ()
111
+ position_data = []
112
+ velocity_data = []
113
+ for i in range (round (9 * 600 / sim_dt )):
114
+ position_data .append (np .array (initial_position ) + np .array (initial_velocity ) * (i * sim_dt ))
115
+ velocity_data .append (np .array (initial_velocity ))
116
+ input_data .timeTag = macros .sec2nano (i * sim_dt )
117
+ input_data .r_BN_N = position_data [i ]
118
+ filter_msg .write (input_data , unit_test_sim .TotalSim .getCurrentNanos ())
119
+ unit_test_sim .ConfigureStopTime (macros .sec2nano ((i + 1 ) * sim_dt ) - 1 )
120
+ unit_test_sim .ExecuteSimulation ()
121
+
122
+ # retrieve the logged data
123
+ reference_attitude = attitude_reference_log .sigma_RN
124
+ reference_rate = attitude_reference_log .omega_RN_N
125
+ reference_acceleration = attitude_reference_log .domega_RN_N
126
+ time_data = attitude_reference_log .times () * macros .NANO2MIN
146
127
147
128
ur_output = []
148
129
ut_output = []
149
130
uh_output = []
150
- for i in range (len (refAtt )):
151
- RN = rbk .MRP2C (refAtt [i ])
131
+ for i in range (len (reference_attitude )):
132
+ RN = rbk .MRP2C (reference_attitude [i ])
152
133
ur_output .append (np .matmul (RN .transpose (), [1 , 0 , 0 ]))
153
134
ut_output .append (np .matmul (RN .transpose (), [0 , 1 , 0 ]))
154
135
uh_output .append (np .matmul (RN .transpose (), [0 , 0 , 1 ]))
155
136
156
- ur = initPos / np .linalg .norm (initPos )
157
- uh = np .cross (initPos , initVel ) / np .linalg .norm (np .cross (initPos , initVel ))
137
+ ur = initial_position / np .linalg .norm (initial_position )
138
+ uh = np .cross (initial_position , initial_velocity ) / np .linalg .norm (np .cross (initial_position , initial_velocity ))
158
139
ut = np .cross (uh , ur )
159
- f0 = np .linalg .norm (initVel ) / np .linalg .norm (initPos )
160
- gamma0 = np .arctan (np .dot (initVel , ur ) / np .dot (initVel , ut ))
140
+ f0 = np .linalg .norm (initial_velocity ) / np .linalg .norm (initial_position )
141
+ gamma0 = np .arctan (np .dot (initial_velocity , ur ) / np .dot (initial_velocity , ut ))
161
142
162
- for i in range (len (refAtt )):
163
- # check a vector values
164
- ur = dataPos [i ] / np .linalg .norm (dataPos [i ])
165
- uh = np .cross (dataPos [i ], dataVel [i ]) / np .linalg .norm (np .cross (dataPos [i ], dataVel [i ]))
143
+ for i in range (len (reference_attitude )):
144
+ ur = position_data [i ] / np .linalg .norm (position_data [i ])
145
+ uh = np .cross (position_data [i ], velocity_data [i ]) / np .linalg .norm (np .cross (position_data [i ], velocity_data [i ]))
166
146
ut = np .cross (uh , ur )
167
- dt = timeData [i ]* 60
168
- den = ((f0 * dt )** 2 + 2 * f0 * np .sin (gamma0 )* dt + 1 )
147
+ dt = time_data [i ] * 60
148
+ den = ((f0 * dt ) ** 2 + 2 * f0 * np .sin (gamma0 ) * dt + 1 )
169
149
omega = uh * f0 * np .cos (gamma0 ) / den
170
- omegaDot = uh * (- 2 * f0 * f0 * np .cos (gamma0 )) * (f0 * dt + np .sin (gamma0 )) / den / den
171
- if signOrbitNormal == - 1 :
150
+ omegaDot = uh * (- 2 * f0 * f0 * np .cos (gamma0 )) * (f0 * dt + np .sin (gamma0 )) / den / den
151
+ if orbit_normal_sign == - 1 :
172
152
ut = np .cross (ur , uh )
173
153
uh = np .cross (ur , ut )
174
154
175
155
# test correctness of frame, angular rate and acceleration
176
- np .testing .assert_allclose (ur_output [i ], ur , rtol = 0 , atol = accuracy , verbose = True )
177
- np .testing .assert_allclose (ut_output [i ], ut , rtol = 0 , atol = accuracy , verbose = True )
178
- np .testing .assert_allclose (uh_output [i ], uh , rtol = 0 , atol = accuracy , verbose = True )
179
- np .testing .assert_allclose (refRate [i ], omega , rtol = 0 , atol = accuracy , verbose = True )
180
- np .testing .assert_allclose (refAcc [i ], omegaDot , rtol = 0 , atol = accuracy , verbose = True )
181
-
182
- # plot the results
183
- plt .close ("all" ) # clears out plots from earlier test runs
184
- dataPos = np .array (dataPos )
185
- dataVel = np .array (dataVel )
186
- plot_position (timeData , dataPos )
187
- plot_velocity (timeData , dataVel )
188
- plot_ref_attitude (timeData , refAtt )
189
- plot_ref_rates (timeData , refRate )
190
- plot_ref_accelerations (timeData , refAcc )
156
+ np .testing .assert_allclose (ur_output [i ], ur , rtol = 0 , atol = 1E-12 , verbose = True )
157
+ np .testing .assert_allclose (ut_output [i ], ut , rtol = 0 , atol = 1E-12 , verbose = True )
158
+ np .testing .assert_allclose (uh_output [i ], uh , rtol = 0 , atol = 1E-12 , verbose = True )
159
+ np .testing .assert_allclose (reference_rate [i ], omega , rtol = 0 , atol = 1E-12 , verbose = True )
160
+ np .testing .assert_allclose (reference_acceleration [i ], omegaDot , rtol = 0 , atol = 1E-12 , verbose = True )
161
+
162
+ plt .close ("all" )
163
+ position_data = np .array (position_data )
164
+ velocity_data = np .array (velocity_data )
165
+ plot_position (time_data , position_data )
166
+ plot_velocity (time_data , velocity_data )
167
+ plot_ref_attitude (time_data , reference_attitude )
168
+ plot_ref_rates (time_data , reference_rate )
169
+ plot_ref_accelerations (time_data , reference_acceleration )
191
170
192
171
if show_plots :
193
172
plt .show ()
194
173
195
- # close the plots being saved off to avoid over-writing old and new figures
196
174
plt .close ("all" )
197
175
198
- # each test method requires a single assert method to be called
199
- # this check below just makes sure no sub-test failures were found
200
- # return [testFailCount, ''.join(testMessages)]
201
- return
202
176
203
-
204
- def plot_position (timeData , dataPos ):
177
+ def plot_position (time_data , position_data ):
205
178
"""Plot the attitude errors."""
206
179
plt .figure (1 )
207
180
for idx in range (3 ):
208
- plt .plot (timeData , dataPos [:, idx ],
181
+ plt .plot (time_data , position_data [:, idx ],
209
182
color = unitTestSupport .getLineColor (idx , 3 ),
210
- label = r'$r_{BN,' + str (idx + 1 ) + '}$' )
183
+ label = r'$r_{BN,' + str (idx + 1 ) + '}$' )
211
184
plt .legend (loc = 'lower right' )
212
185
plt .xlabel ('Time [min]' )
213
186
plt .ylabel (r'Inertial Position [m]' )
214
187
215
188
216
- def plot_velocity (timeData , dataVel ):
189
+ def plot_velocity (time_data , velocity_data ):
217
190
"""Plot the attitude errors."""
218
191
plt .figure (2 )
219
192
for idx in range (3 ):
220
- plt .plot (timeData , dataVel [:, idx ],
193
+ plt .plot (time_data , velocity_data [:, idx ],
221
194
color = unitTestSupport .getLineColor (idx , 3 ),
222
- label = r'$v_{BN,' + str (idx + 1 ) + '}$' )
195
+ label = r'$v_{BN,' + str (idx + 1 ) + '}$' )
223
196
plt .legend (loc = 'lower right' )
224
197
plt .xlabel ('Time [min]' )
225
198
plt .ylabel (r'Inertial Velocity [m/s]' )
226
199
227
200
228
- def plot_ref_attitude (timeData , sigma_RN ):
201
+ def plot_ref_attitude (time_data , sigma_RN ):
229
202
"""Plot the attitude errors."""
230
203
plt .figure (3 )
231
204
for idx in range (3 ):
232
- plt .plot (timeData , sigma_RN [:, idx ],
205
+ plt .plot (time_data , sigma_RN [:, idx ],
233
206
color = unitTestSupport .getLineColor (idx , 3 ),
234
- label = r'$\sigma_{RN,' + str (idx + 1 ) + '}$' )
207
+ label = r'$\sigma_{RN,' + str (idx + 1 ) + '}$' )
235
208
plt .legend (loc = 'lower right' )
236
209
plt .xlabel ('Time [min]' )
237
210
plt .ylabel (r'Reference attitude' )
238
211
239
212
240
- def plot_ref_rates (timeData , omega_RN ):
213
+ def plot_ref_rates (time_data , omega_RN ):
241
214
"""Plot the attitude errors."""
242
215
plt .figure (4 )
243
216
for idx in range (3 ):
244
- plt .plot (timeData , omega_RN [:, idx ],
217
+ plt .plot (time_data , omega_RN [:, idx ],
245
218
color = unitTestSupport .getLineColor (idx , 3 ),
246
- label = r'$\omega_{RN,' + str (idx + 1 ) + '}$' )
219
+ label = r'$\omega_{RN,' + str (idx + 1 ) + '}$' )
247
220
plt .legend (loc = 'lower right' )
248
221
plt .xlabel ('Time [min]' )
249
222
plt .ylabel (r'Reference rates' )
250
223
251
224
252
- def plot_ref_accelerations (timeData , omegaDot_RN ):
225
+ def plot_ref_accelerations (time_data , omegaDot_RN ):
253
226
"""Plot the attitude errors."""
254
227
plt .figure (5 )
255
228
for idx in range (3 ):
256
- plt .plot (timeData , omegaDot_RN [:, idx ],
229
+ plt .plot (time_data , omegaDot_RN [:, idx ],
257
230
color = unitTestSupport .getLineColor (idx , 3 ),
258
- label = r'$\dot{\omega}_{RN,' + str (idx + 1 ) + '}$' )
231
+ label = r'$\dot{\omega}_{RN,' + str (idx + 1 ) + '}$' )
259
232
plt .legend (loc = 'lower right' )
260
233
plt .xlabel ('Time [min]' )
261
234
plt .ylabel (r'Reference accelerations' )
262
235
263
236
264
- #
265
- # This statement below ensures that the unit test scrip can be run as a
266
- # stand-along python script
267
- #
268
237
if __name__ == "__main__" :
269
- test_flybyPoint (
270
- True , # show_plots
271
- [- 5e7 , 7.5e6 , 5e5 ], # initPos
272
- [2e4 , 0 , 0 ], # initVel
273
- 100 , # dTsim
274
- 600 , # dTfilter
275
- 1 , # sign Orbit Normal
276
- 1e-12 # accuracy
277
- )
238
+ test_flybyPoint (True , # show_plots
239
+ [- 5e7 , 7.5e6 , 5e5 ], # initial_position
240
+ [2e4 , 0 , 0 ], # initial_velocity
241
+ 1 , # filter_dt
242
+ 1 , # sign Orbit Normal
243
+ 0.01 , # max rate
244
+ 0 # max acceleration
245
+ )
0 commit comments