class AccuratePredictorCalculationErrorTests(TestCase): """Check that we can learn from calculation errors and provide patches for corner cases""" def setUp(self): # Source self.db = MemoryTLESource() self.db.add_tle(BUGSAT_SATE_ID, BUGSAT1_TLE_LINES, datetime.now()) # Predictor self.predictor = HighAccuracyTLEPredictor(BUGSAT_SATE_ID, self.db) self.is_ascending_mock = self._patch( 'orbit_predictor.accuratepredictor.LocationPredictor.is_ascending') self.start = datetime(2017, 3, 6, 7, 51) logassert.setup(self, 'orbit_predictor.accuratepredictor') def _patch(self, *args, **kwargs): patcher = mock.patch(*args, **kwargs) self.addCleanup(patcher.stop) return patcher.start() def test_ascending_failure(self): self.is_ascending_mock.return_value = False with self.assertRaises(PropagationError): self.predictor.get_next_pass(svalbard, self.start) self.assertLoggedError(str(svalbard), str(self.start), *BUGSAT1_TLE_LINES) def test_descending_failure(self): self.is_ascending_mock.return_value = True with self.assertRaises(PropagationError): self.predictor.get_next_pass(svalbard, self.start) self.assertLoggedError(str(svalbard), str(self.start), *BUGSAT1_TLE_LINES)
def setUp(self): # Source self.db = MemoryTLESource() self.start = datetime(2017, 3, 6, 7, 51) self.db.add_tle(SATE_ID, LINES, self.start) # Predictor self.predictor = HighAccuracyTLEPredictor(SATE_ID, self.db) self.end = self.start + timedelta(days=5)
def setUp(self): # Source self.db = MemoryTLESource() self.db.add_tle(BUGSAT_SATE_ID, BUGSAT1_TLE_LINES, datetime.now()) # Predictor self.predictor = HighAccuracyTLEPredictor(BUGSAT_SATE_ID, self.db) self.is_ascending_mock = self._patch( 'orbit_predictor.accuratepredictor.LocationPredictor.is_ascending') self.start = datetime(2017, 3, 6, 7, 51) logassert.setup(self, 'orbit_predictor.accuratepredictor')
class AccurateVsGpredictTests(TestCase): def setUp(self): # Source self.db = MemoryTLESource() self.db.add_tle(BUGSAT_SATE_ID, BUGSAT1_TLE_LINES, datetime.now()) # Predictor self.predictor = HighAccuracyTLEPredictor(BUGSAT_SATE_ID, self.db) def test_get_next_pass_with_gpredict_data(self): GPREDICT_DATA = """ ------------------------------------------------------------------------------------------------- AOS TCA LOS Duration Max El AOS Az LOS Az ------------------------------------------------------------------------------------------------- 2014/10/23 01:27:09 2014/10/23 01:33:03 2014/10/23 01:38:57 00:11:47 25.85 40.28 177.59 2014/10/23 03:02:44 2014/10/23 03:08:31 2014/10/23 03:14:17 00:11:32 20.55 341.35 209.65 2014/10/23 14:48:23 2014/10/23 14:54:39 2014/10/23 15:00:55 00:12:31 75.31 166.30 350.27 2014/10/23 16:25:19 2014/10/23 16:29:32 2014/10/23 16:33:46 00:08:27 7.14 200.60 287.00 2014/10/24 01:35:34 2014/10/24 01:41:37 2014/10/24 01:47:39 00:12:05 32.20 34.97 180.38 2014/10/24 03:11:40 2014/10/24 03:17:11 2014/10/24 03:22:42 00:11:02 16.30 335.44 213.21 2014/10/24 14:57:00 2014/10/24 15:03:16 2014/10/24 15:09:32 00:12:32 84.30 169.06 345.11 2014/10/24 16:34:18 2014/10/24 16:38:02 2014/10/24 16:41:45 00:07:27 5.09 205.18 279.57 2014/10/25 01:44:01 2014/10/25 01:50:11 2014/10/25 01:56:20 00:12:19 40.61 29.75 183.12 2014/10/25 03:20:39 2014/10/25 03:25:51 2014/10/25 03:31:04 00:10:25 12.78 329.21 217.10""" # NOQA for line in GPREDICT_DATA.splitlines()[4:]: line_parts = line.split() aos = datetime.strptime(" ".join(line_parts[:2]), '%Y/%m/%d %H:%M:%S') max_elevation_date = datetime.strptime(" ".join(line_parts[2:4]), '%Y/%m/%d %H:%M:%S') los = datetime.strptime(" ".join(line_parts[4:6]), '%Y/%m/%d %H:%M:%S') duration = datetime.strptime(line_parts[6], '%H:%M:%S') duration_s = timedelta(minutes=duration.minute, seconds=duration.second).total_seconds() max_elev_deg = float(line_parts[7]) try: date = pass_.los # NOQA except UnboundLocalError: date = datetime.strptime("2014-10-22 20:18:11.921921", '%Y-%m-%d %H:%M:%S.%f') pass_ = self.predictor.get_next_pass(tortu1, date) self.assertAlmostEqual(pass_.aos, aos, delta=ONE_SECOND) self.assertAlmostEqual(pass_.los, los, delta=ONE_SECOND) self.assertAlmostEqual(pass_.max_elevation_date, max_elevation_date, delta=ONE_SECOND) self.assertAlmostEqual(pass_.duration_s, duration_s, delta=1) self.assertAlmostEqual(pass_.max_elevation_deg, max_elev_deg, delta=0.05)
class AccurateVsGpredictTests(TestCase): def setUp(self): # Source self.db = MemoryTLESource() self.db.add_tle(BUGSAT_SATE_ID, BUGSAT1_TLE_LINES, datetime.now()) # Predictor self.predictor = HighAccuracyTLEPredictor(BUGSAT_SATE_ID, self.db) def test_get_next_pass_with_stk_data(self): STK_DATA = """ ------------------------------------------------------------------------------------------------ AOS TCA LOS Duration Max El ------------------------------------------------------------------------------------------------ 2014/10/23 01:27:33.224 2014/10/23 01:32:41.074 2014/10/23 01:37:47.944 00:10:14.720 12.76 2014/10/23 03:01:37.007 2014/10/23 03:07:48.890 2014/10/23 03:14:01.451 00:12:24.000 39.32 2014/10/23 14:49:34.783 2014/10/23 14:55:44.394 2014/10/23 15:01:51.154 00:12:16.000 41.75 2014/10/23 16:25:54.939 2014/10/23 16:30:50.152 2014/10/23 16:35:44.984 00:09:50.000 11.45 2014/10/24 01:35:47.889 2014/10/24 01:41:13.181 2014/10/24 01:46:37.548 00:10:50.000 16.07 2014/10/24 03:10:23.486 2014/10/24 03:16:27.230 2014/10/24 03:22:31.865 00:12:08.000 30.62 2014/10/24 14:58:07.378 2014/10/24 15:04:21.721 2014/10/24 15:10:33.546 00:12:26.000 54.83 2014/10/24 16:34:48.635 2014/10/24 16:39:20.960 2014/10/24 16:43:53.204 00:09:04.000 8.78 2014/10/25 01:44:05.771 2014/10/25 01:49:45.487 2014/10/25 01:55:24.414 00:11:18.000 20.07 2014/10/25 03:19:12.611 2014/10/25 03:25:05.674 2014/10/25 03:30:59.815 00:11:47.000 24.09""" # NOQA for line in STK_DATA.splitlines()[4:]: line_parts = line.split() aos = datetime.strptime(" ".join(line_parts[:2]), '%Y/%m/%d %H:%M:%S.%f') max_elevation_date = datetime.strptime(" ".join(line_parts[2:4]), '%Y/%m/%d %H:%M:%S.%f') los = datetime.strptime(" ".join(line_parts[4:6]), '%Y/%m/%d %H:%M:%S.%f') duration = datetime.strptime(line_parts[6], '%H:%M:%S.%f') duration_s = timedelta(minutes=duration.minute, seconds=duration.second).total_seconds() max_elev_deg = float(line_parts[7]) try: date = pass_.los # NOQA except UnboundLocalError: date = datetime.strptime("2014-10-22 20:18:11.921921", '%Y-%m-%d %H:%M:%S.%f') pass_ = self.predictor.get_next_pass(ARG, date) self.assertAlmostEqual(pass_.aos, aos, delta=ONE_SECOND) self.assertAlmostEqual(pass_.los, los, delta=ONE_SECOND) self.assertAlmostEqual(pass_.max_elevation_date, max_elevation_date, delta=ONE_SECOND) self.assertAlmostEqual(pass_.duration_s, duration_s, delta=2 * 1) self.assertAlmostEqual(pass_.max_elevation_deg, max_elev_deg, delta=0.05)
class AccuratePredictorTests(TestCase): def setUp(self): # Source self.db = MemoryTLESource() self.start = datetime(2017, 3, 6, 7, 51) self.db.add_tle(SATE_ID, LINES, self.start) # Predictor self.predictor = HighAccuracyTLEPredictor(SATE_ID, self.db) self.old_predictor = TLEPredictor(SATE_ID, self.db) self.end = self.start + timedelta(days=5) def all_passes_old_predictor(self, location, start, end): while True: try: pass_ = self.old_predictor.get_next_pass(location, when_utc=start, limit_date=end) start = pass_.los yield pass_ except Exception: break def assertEqualOrGreaterPassesAmount(self, location): """Compare propagators and check no passes lost and no performance degradation""" t0 = time.time() old_passes = list( self.all_passes_old_predictor(location, self.start, self.end)) t1 = time.time() predicted_passes = list( self.predictor.passes_over(location, self.start, self.end)) t2 = time.time() self.assertGreaterEqual(len(predicted_passes), len(old_passes), 'We are loosing passes') self.assertLessEqual(t2 - t1, t1 - t0, 'Performance is degraded') def test_accurate_predictor_find_more_or_equal_passes_amount(self): self.assertEqualOrGreaterPassesAmount( Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666)) self.assertEqualOrGreaterPassesAmount(tortu1) self.assertEqualOrGreaterPassesAmount(svalbard) self.assertEqualOrGreaterPassesAmount( Location('bad-case-2', -11.011509137116818, 123.29554733688798, 1451.5695915302097)) self.assertEqualOrGreaterPassesAmount( Location('bad-case-3', 10.20803236163988, 138.01236517021056, 4967.661890730469)) self.assertEqualOrGreaterPassesAmount( Location('less passes', -82.41515032683046, -33.712555446065664, 4417.427841452149)) def test_predicted_passes_are_equal_between_executions(self): location = Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666) first_set = list( self.predictor.passes_over(location, self.start, self.end)) second_set = list( self.predictor.passes_over(location, self.start + timedelta(seconds=3), self.end)) self.assertEqual(first_set, second_set) def test_predicted_passes_have_elevation_positive_and_visible_on_date( self): end = self.start + timedelta(days=60) for pass_ in self.predictor.passes_over(svalbard, self.start, end): self.assertGreater(pass_.max_elevation_deg, 0) position = self.old_predictor.get_position( pass_.max_elevation_date) svalbard.is_visible(position) self.assertGreaterEqual(pass_.off_nadir_deg, -90) self.assertLessEqual(pass_.off_nadir_deg, 90) def test_predicted_passes_off_nadir_angle_works(self): start = datetime(2017, 3, 6, 13, 30) end = start + timedelta(hours=1) location = Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666) pass_ = self.predictor.get_next_pass(location, when_utc=start, limit_date=end) self.assertGreaterEqual(0, pass_.off_nadir_deg) @given(start=datetimes( min_value=datetime(2017, 1, 1), max_value=datetime(2020, 12, 31), ), location=tuples(floats(min_value=-90, max_value=90), floats(min_value=0, max_value=180), floats(min_value=-200, max_value=9000))) @settings(max_examples=10000, deadline=None) @example(start=datetime(2017, 1, 26, 11, 51, 51), location=(-37.69358328273305, 153.96875, 0.0)) def test_pass_is_always_returned(self, start, location): location = Location('bad-case-1', *location) pass_ = self.predictor.get_next_pass(location, start) self.assertGreater(pass_.max_elevation_deg, 0) def test_aos_deg_can_be_used_in_get_next_pass(self): start = datetime(2017, 3, 6, 13, 30) end = start + timedelta(hours=1) location = Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666) complete_pass = self.predictor.get_next_pass(location, when_utc=start, limit_date=end) pass_with_aos = self.predictor.get_next_pass(location, when_utc=start, limit_date=end, aos_at_dg=5) self.assertGreater(pass_with_aos.aos, complete_pass.aos) self.assertLess(pass_with_aos.aos, complete_pass.max_elevation_date) self.assertAlmostEqual(pass_with_aos.max_elevation_date, complete_pass.max_elevation_date, delta=timedelta(seconds=1)) self.assertGreater(pass_with_aos.los, complete_pass.max_elevation_date) self.assertLess(pass_with_aos.los, complete_pass.los) position = self.old_predictor.get_position(pass_with_aos.aos) _, elev = location.get_azimuth_elev_deg(position) self.assertAlmostEqual(elev, 5, delta=0.1) position = self.old_predictor.get_position(pass_with_aos.los) _, elev = location.get_azimuth_elev_deg(position) self.assertAlmostEqual(elev, 5, delta=0.1) def test_predicted_passes_whit_aos(self): end = self.start + timedelta(days=60) for pass_ in self.predictor.passes_over(svalbard, self.start, end, aos_at_dg=5): self.assertGreater(pass_.max_elevation_deg, 5) position = self.old_predictor.get_position(pass_.aos) _, elev = svalbard.get_azimuth_elev_deg(position) self.assertAlmostEqual(elev, 5, delta=0.1)
def setUp(self): # Source self.db = MemoryTLESource() self.db.add_tle(BUGSAT_SATE_ID, BUGSAT1_TLE_LINES, datetime.now()) # Predictor self.predictor = HighAccuracyTLEPredictor(BUGSAT_SATE_ID, self.db)
def get_predictor(self, sate_id, precise=False): """Return a Predictor instance using the current storage.""" if precise: return HighAccuracyTLEPredictor(sate_id, self) return TLEPredictor(sate_id, self)
class AccuratePredictorTests(TestCase): def setUp(self): # Source self.db = MemoryTLESource() self.start = datetime(2017, 3, 6, 7, 51) self.db.add_tle(SATE_ID, LINES, self.start) # Predictor self.predictor = HighAccuracyTLEPredictor(SATE_ID, self.db) self.end = self.start + timedelta(days=5) def test_predicted_passes_are_equal_between_executions(self): location = Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666) first_set = list( self.predictor.passes_over(location, self.start, self.end)) second_set = list( self.predictor.passes_over(location, self.start + timedelta(seconds=3), self.end)) # We use delta=ONE_SECOND because # that's the hardcoded value for the precision self.assertAlmostEqual(first_set[0].aos, second_set[0].aos, delta=ONE_SECOND) self.assertAlmostEqual(first_set[0].los, second_set[0].los, delta=ONE_SECOND) def test_predicted_passes_have_elevation_positive_and_visible_on_date( self): end = self.start + timedelta(days=60) for pass_ in self.predictor.passes_over(ARG, self.start, end): self.assertGreater(pass_.max_elevation_deg, 0) position = self.predictor.get_position(pass_.max_elevation_date) ARG.is_visible(position) self.assertGreaterEqual(pass_.off_nadir_deg, -90) self.assertLessEqual(pass_.off_nadir_deg, 90) def test_predicted_passes_off_nadir_angle_works(self): start = datetime(2017, 3, 6, 13, 30) end = start + timedelta(hours=1) location = Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666) pass_ = self.predictor.get_next_pass(location, when_utc=start, limit_date=end) self.assertGreaterEqual(0, pass_.off_nadir_deg) @given(start=datetimes( min_value=datetime(2017, 1, 1), max_value=datetime(2020, 12, 31), ), location=tuples(floats(min_value=-90, max_value=90), floats(min_value=0, max_value=180), floats(min_value=-200, max_value=9000))) @settings(max_examples=10000, deadline=None) @example(start=datetime(2017, 1, 26, 11, 51, 51), location=(-37.69358328273305, 153.96875, 0.0)) def test_pass_is_always_returned(self, start, location): location = Location('bad-case-1', *location) pass_ = self.predictor.get_next_pass(location, start) self.assertGreater(pass_.max_elevation_deg, 0) def test_aos_deg_can_be_used_in_get_next_pass(self): start = datetime(2017, 3, 6, 13, 30) end = start + timedelta(hours=1) location = Location('bad-case-1', 11.937501570612568, -55.35189435098657, 1780.674044538666) complete_pass = self.predictor.get_next_pass(location, when_utc=start, limit_date=end) pass_with_aos = self.predictor.get_next_pass(location, when_utc=start, limit_date=end, aos_at_dg=5) self.assertGreater(pass_with_aos.aos, complete_pass.aos) self.assertLess(pass_with_aos.aos, complete_pass.max_elevation_date) self.assertAlmostEqual(pass_with_aos.max_elevation_date, complete_pass.max_elevation_date, delta=timedelta(seconds=1)) self.assertGreater(pass_with_aos.los, complete_pass.max_elevation_date) self.assertLess(pass_with_aos.los, complete_pass.los) position = self.predictor.get_position(pass_with_aos.aos) _, elev = location.get_azimuth_elev_deg(position) self.assertAlmostEqual(elev, 5, delta=0.1) position = self.predictor.get_position(pass_with_aos.los) _, elev = location.get_azimuth_elev_deg(position) self.assertAlmostEqual(elev, 5, delta=0.1) def test_predicted_passes_whit_aos(self): end = self.start + timedelta(days=60) for pass_ in self.predictor.passes_over(ARG, self.start, end, aos_at_dg=5): self.assertGreater(pass_.max_elevation_deg, 5) position = self.predictor.get_position(pass_.aos) _, elev = ARG.get_azimuth_elev_deg(position) self.assertAlmostEqual(elev, 5, delta=0.1)