13#include "ns3/double.h"
14#include "ns3/geographic-positions.h"
15#include "ns3/leo-circular-orbit-mobility-model.h"
16#include "ns3/leo-circular-orbit-position-allocator.h"
17#include "ns3/leo-orbital-shell.h"
20#include "ns3/simulator.h"
22#include "ns3/uinteger.h"
67 void DoRun()
override;
71 :
TestCase(
"LEO initial ECEF position at time zero")
81 mob->SetAttribute(
"Inclination",
DoubleValue(45.0));
83 node->AggregateObject(mob);
86 mob->SetPosition(Vector(0.0, 0.0, 0.0));
88 Vector pos = mob->GetPosition();
90 double expectedX =
ORBIT_RADIUS_M * std::cos(std::numbers::pi / 4.0);
91 double expectedY = 0.0;
92 double expectedZ =
ORBIT_RADIUS_M * std::sin(std::numbers::pi / 4.0);
125 void DoRun()
override;
136 :
TestCase(
"LEO orbital plane drifts westward due to Earth rotation")
143 Vector pos = mob->GetPosition();
146 double earthRotAngle =
147 (orbitalPeriod.
GetDouble() /
Hours(24).GetDouble()) * 2.0 * std::numbers::pi;
148 double lonAtT = -earthRotAngle;
150 double expectedX =
ORBIT_RADIUS_M * std::cos(std::numbers::pi / 4.0) * std::cos(lonAtT);
151 double expectedY =
ORBIT_RADIUS_M * std::cos(std::numbers::pi / 4.0) * std::sin(lonAtT);
152 double expectedZ =
ORBIT_RADIUS_M * std::sin(std::numbers::pi / 4.0);
157 "x coordinate at one orbital period is incorrect");
161 "y coordinate should be negative (westward drift)");
165 "z coordinate at one orbital period is incorrect");
176 mob->SetAttribute(
"Altitude",
DoubleValue(1000.0));
177 mob->SetAttribute(
"Inclination",
DoubleValue(45.0));
179 node->AggregateObject(mob);
181 mob->SetPosition(Vector(0.0, 0.0, 0.0));
217 void DoRun()
override;
221 :
TestCase(
"LEO non-zero initial longitude offset")
230 mob->SetAttribute(
"Altitude",
DoubleValue(1000.0));
231 mob->SetAttribute(
"Inclination",
DoubleValue(45.0));
233 node->AggregateObject(mob);
236 mob->SetPosition(Vector(90.0, 0.0, 0.0));
238 Vector pos = mob->GetPosition();
240 double expectedX = 0.0;
241 double expectedY =
ORBIT_RADIUS_M * std::cos(std::numbers::pi / 4.0);
242 double expectedZ =
ORBIT_RADIUS_M * std::sin(std::numbers::pi / 4.0);
247 "x coordinate should be near zero for longitude = 90 deg");
251 "y coordinate is incorrect for longitude = 90 deg");
255 "z coordinate is incorrect for longitude = 90 deg");
295 void DoRun()
override;
299 :
TestCase(
"LEO non-zero orbital offset exercises RotatePlane")
308 mob->SetAttribute(
"Altitude",
DoubleValue(1000.0));
309 mob->SetAttribute(
"Inclination",
DoubleValue(45.0));
311 node->AggregateObject(mob);
314 mob->SetPosition(Vector(0.0, 90.0, 0.0));
316 Vector pos = mob->GetPosition();
318 double expectedX = 0.0;
320 double expectedZ = 0.0;
325 "x coordinate should be near zero for orbital offset = 90 deg");
329 "y coordinate should equal orbit radius for orbital offset = 90 deg");
333 "z coordinate should be near zero for orbital offset = 90 deg");
359 void DoRun()
override;
370 :
TestCase(
"LEO on-demand orbital progress after quarter period")
378 Vector pos = mob->GetPosition();
382 double earthRotAngle =
383 (quarterPeriod.
GetDouble() /
Hours(24).GetDouble()) * 2.0 * std::numbers::pi;
384 double lonAtT = -earthRotAngle;
393 double inc = std::numbers::pi / 4.0;
405 double nx = -std::sin(inc) * std::cos(lonAtT);
406 double ny = -std::sin(inc) * std::sin(lonAtT);
407 double nz = std::cos(inc);
409 double x0 =
r * std::cos(inc) * std::cos(lonAtT);
410 double y0 =
r * std::cos(inc) * std::sin(lonAtT);
411 double z0 =
r * std::sin(inc);
414 double cx = ny * z0 - nz * y0;
415 double cy = nz * x0 - nx * z0;
416 double cz = nx * y0 - ny * x0;
419 double expectedX = cx;
420 double expectedY = cy;
421 double expectedZ = cz;
426 "x coordinate after quarter orbit is incorrect");
430 "y coordinate after quarter orbit is incorrect");
434 "z coordinate after quarter orbit is incorrect");
437 double radius = std::sqrt(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z);
441 "orbit radius should be preserved after quarter period");
449 mob->SetAttribute(
"Altitude",
DoubleValue(1000.0));
450 mob->SetAttribute(
"Inclination",
DoubleValue(45.0));
452 node->AggregateObject(mob);
454 mob->SetPosition(Vector(0.0, 0.0, 0.0));
493 void DoRun()
override;
497 :
TestCase(
"LEO Walker Delta phasing factor staggers adjacent planes")
510 Vector pos0 = allocator->GetNext();
515 Vector pos1 = allocator->GetNext();
520 Vector pos2 = allocator->GetNext();
525 Vector pos3 = allocator->GetNext();
530 "Plane 1 sat 1 offset should be 270 (180 + 90 phasing)");
547 void DoRun()
override;
551 :
TestCase(
"LEO Orbit constructor handles parameters")
596 void DoRun()
override;
600 :
TestCase(
"LEO Walker Star spaces planes over 180 degrees")
610 allocator->SetAttribute(
"RaanSpanDeg",
DoubleValue(180.0));
613 Vector pos0 = allocator->GetNext();
617 Vector pos1 = allocator->GetNext();
621 "Plane 1 RAAN should be 90 (180 / 2) for Walker Star");
639 void DoRun()
override;
643 :
TestCase(
"LEO allocator GetNextOrbitPosition returns correct struct")
654 allocator->SetAttribute(
"RaanSpanDeg",
DoubleValue(360.0));
657 auto params0 = allocator->GetNextOrbitPosition();
662 "Plane 0 sat 0 argLat should be 0");
666 auto params1 = allocator->GetNextOrbitPosition();
671 "Plane 0 sat 1 argLat should be 180");
674 auto params2 = allocator->GetNextOrbitPosition();
679 "Plane 1 sat 0 argLat should be 90");
682 auto params3 = allocator->GetNextOrbitPosition();
687 "Plane 1 sat 1 argLat should be 270");
692 allocCompat->SetAttribute(
"NumSatellites",
UintegerValue(2));
693 allocCompat->SetAttribute(
"PhasingFactor",
UintegerValue(1));
694 allocCompat->SetAttribute(
"RaanSpanDeg",
DoubleValue(360.0));
696 auto vecFirst = allocCompat->GetNext();
705 mob->SetAttribute(
"Altitude",
DoubleValue(1000.0));
706 mob->SetAttribute(
"Inclination",
DoubleValue(45.0));
708 node->AggregateObject(mob);
711 auto paramsFirst = allocator->GetNextOrbitPosition();
712 Vector setPositionVec{paramsFirst.longitude, paramsFirst.argumentOfLatitude, 0.0};
713 mob->SetPosition(setPositionVec);
716 Vector pos = mob->GetPosition();
719 double expectedX =
ORBIT_RADIUS_M * std::cos(std::numbers::pi / 4.0);
720 double expectedZ =
ORBIT_RADIUS_M * std::sin(std::numbers::pi / 4.0);
725 "x coordinate after SetPosition is incorrect");
729 "z coordinate after SetPosition is incorrect");
750 void DoRun()
override;
754 :
TestCase(
"LEO Orbit serialization round-trip preserves all fields")
765 std::ostringstream oss;
767 std::string csvText = oss.str();
773 std::istringstream iss(csvText);
781 "Altitude mismatch after round-trip");
785 "Inclination mismatch after round-trip");
791 "Phasing mismatch after round-trip");
795 "RAAN span mismatch after round-trip");
799 std::ostringstream oss2;
800 oss2 << starOriginal;
801 std::string csvText2 = oss2.str();
803 std::istringstream iss2(csvText2);
805 iss2 >> starRestored;
811 "Star inclination mismatch");
817 "Star phasing mismatch");
821 "Star RAAN span mismatch");
825 std::ostringstream oss3;
826 oss3 << defaultOriginal;
827 std::string csvText3 = oss3.str();
829 std::istringstream iss3(csvText3);
831 iss3 >> defaultRestored;
836 "Default altitude mismatch");
840 "Default inclination mismatch");
843 "Default planes mismatch");
848 "Default phasing mismatch");
852 "Default RAAN span mismatch");
Test that Earth rotation causes the orbital plane to drift westward in the ECEF frame.
void DoRun() override
Implementation to actually run this TestCase.
LeoEarthRotationTestCase()
void CheckPosition(Ptr< LeoCircularOrbitMobilityModel > mob, Time orbitalPeriod)
Check satellite position at the scheduled time.
Test that a satellite at time 0 is placed at the analytically expected ECEF position for a given alti...
LeoInitialPositionTestCase()
void DoRun() override
Implementation to actually run this TestCase.
Test that a non-zero initial longitude offsets the orbital plane correctly at time 0.
LeoLongitudeOffsetTestCase()
void DoRun() override
Implementation to actually run this TestCase.
Test that LeoOrbitalShell constructor correctly handles Delta and Star parameters.
LeoOrbitConstructorTestCase()
void DoRun() override
Implementation to actually run this TestCase.
Test that LeoCircularOrbitAllocator::GetNextOrbitPosition() returns the correct structured values mat...
LeoOrbitPositionStructTestCase()
void DoRun() override
Implementation to actually run this TestCase.
Test LeoOrbitalShell serialization and deserialization round-trip.
void DoRun() override
Implementation to actually run this TestCase.
LeoOrbitSerializationTestCase()
Test that a non-zero orbital offset correctly rotates the satellite along its orbital plane via the R...
LeoOrbitalOffsetTestCase()
void DoRun() override
Implementation to actually run this TestCase.
Test that on-demand orbital progress produces the expected position after a quarter orbital period.
void DoRun() override
Implementation to actually run this TestCase.
void CheckPosition(Ptr< LeoCircularOrbitMobilityModel > mob, Time quarterPeriod)
Check satellite position at T/4.
LeoOrbitalProgressTestCase()
Test that the Walker Delta phasing factor correctly staggers satellites in adjacent orbital planes.
LeoPhasingFactorTestCase()
void DoRun() override
Implementation to actually run this TestCase.
Test that Walker Star constellations (RaanSpanDeg = 180) space orbital planes over 180 degrees instea...
void DoRun() override
Implementation to actually run this TestCase.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
static constexpr double EARTH_SPHERE_RADIUS
Earth's radius in meters if modeled as a perfect sphere.
double inc
Inclination of orbit (degrees).
std::size_t sats
Number of satellites in those planes.
double raanSpanDeg
RAAN span in degrees (360 for Walker Delta, 180 for Walker Star).
std::size_t planes
Number of planes with that altitude and inclination.
double alt
Altitude of orbit (km, from earth surface).
double phasing
Walker Delta phasing factor F (0 means no inter-plane stagger).
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
static void Run()
Run the simulation.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Simulation virtual time values and global simulation resolution.
double GetDouble() const
Get the raw time value, in the current resolution unit.
Hold an unsigned integer type.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
#define NS_TEST_ASSERT_MSG_LT(actual, limit, msg)
Test that an actual value is less than a limit and report and abort if not.
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
#define NS_TEST_ASSERT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Time Seconds(double value)
Construct a Time in the indicated unit.
Time Hours(double value)
Construct a Time in the indicated unit.
static constexpr double ORBIT_HEIGHT_KM
Orbit height in km (geocentric radius) for altitude = 1000 km.
static constexpr double ORBIT_RADIUS_M
Orbit radius in meters for altitude = 1000 km.
static constexpr double GM_KM3_S2
Geocentric gravitational constant in km^3/s^2 (must match the model).
static LeoMobilityTestSuite g_leoMobilityTestSuite
Static variable for test initialization.
static constexpr double EARTH_RADIUS_KM
Earth sphere radius in km (must match the model).
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const double TOLERANCE
Tolerance used to check reciprocal of two numbers.