class SkippedPassesRegressionTests(TestCase): """Check that we do not skip passes""" # See https://github.com/satellogic/orbit-predictor/issues/99 def setUp(self): self.db = MemoryTLESource() self.db.add_tle(TRICKY_SAT_ID, TRICKY_SAT_TLE_LINES, dt.datetime.now()) self.predictor = TLEPredictor(TRICKY_SAT_ID, self.db) @pytest.mark.xfail(reason="Legacy LocationPredictor skips some passes") def test_pass_is_not_skipped_old(self): loc = Location( name="loc", latitude_deg=-15.137152171507697, longitude_deg=-0.4276612055384211, elevation_m=1.665102900005877e-05, ) PASS_DATE = dt.datetime(2020, 9, 25, 9, 2, 6) LIMIT_DATE = dt.datetime(2020, 9, 25, 10, 36, 0) predicted_passes = list( self.predictor.passes_over( loc, when_utc=PASS_DATE, limit_date=LIMIT_DATE, aos_at_dg=0, max_elevation_gt=0, location_predictor_class=LocationPredictor, )) assert predicted_passes @pytest.mark.skipif(sys.version_info < (3, 5), reason="Not installing SciPy in Python 3.4") def test_pass_is_not_skipped_smart(self): loc = Location( name="loc", latitude_deg=-15.137152171507697, longitude_deg=-0.4276612055384211, elevation_m=1.665102900005877e-05, ) PASS_DATE = dt.datetime(2020, 9, 25, 9, 2, 6) LIMIT_DATE = dt.datetime(2020, 9, 25, 10, 36, 0) predicted_passes = list( self.predictor.passes_over( loc, when_utc=PASS_DATE, limit_date=LIMIT_DATE, aos_at_dg=0, max_elevation_gt=0, location_predictor_class=SmartLocationPredictor, )) assert predicted_passes
class LOSComputationRegressionTests(TestCase): """Check that the LOS is computed correctly""" # See https://github.com/satellogic/orbit-predictor/issues/104 def setUp(self): tle_lines = ( "1 42760U 17034C 19070.46618549 .00000282 00000-0 30543-4 0 9995", "2 42760 43.0166 56.1509 0009676 356.3576 146.0151 15.09909885 95848", ) self.db = MemoryTLESource() self.db.add_tle("42760U", tle_lines, dt.datetime.now()) self.predictor = TLEPredictor("42760U", self.db) @pytest.mark.skipif(sys.version_info < (3, 5), reason="Not installing SciPy in Python 3.4") def test_los_is_correctly_computed(self): loc = Location( name='loc', latitude_deg=-34.61315, longitude_deg=-58.37723, elevation_m=30, ) PASS_DATE = dt.datetime(2019, 1, 1, 0, 0) LIMIT_DATE = dt.datetime(2019, 1, 15, 0, 0) predicted_passes = list( self.predictor.passes_over( loc, when_utc=PASS_DATE, limit_date=LIMIT_DATE, aos_at_dg=0, max_elevation_gt=0, location_predictor_class=SmartLocationPredictor, )) assert predicted_passes
class AccuratePredictorTests(TestCase): def setUp(self): # Source self.db = MemoryTLESource() self.start = dt.datetime(2017, 3, 6, 7, 51) self.db.add_tle(SATE_ID, LINES, self.start) # Predictor self.predictor = TLEPredictor(SATE_ID, self.db) self.end = self.start + dt.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 + dt.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 + dt.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 = dt.datetime(2017, 3, 6, 13, 30) end = start + dt.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=dt.datetime(2017, 1, 1), max_value=dt.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=dt.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 = dt.datetime(2017, 3, 6, 13, 30) end = start + dt.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=dt.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 + dt.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)