Tests/GeodesyTests.mo
Download original .moGitHub source
Documentation: Tests.GeodesyTests · Tests.GeodesyTests.run
within Tests;
model GeodesyTests "Local-frame and geodetic conversion tests"
function run
output Boolean passed;
protected
constant Real pi = 3.141592653589793;
constant Real earthRadius_m = 6378137.0;
constant Real roundTripTolerance = 1.0e-6;
Geodesy.GeodeticOrigin origin = Geodesy.GeodeticOrigin(
latitude_deg = 40.4237,
longitude_deg = -86.9212,
altitude_m = 180.0);
Real enu[3];
Real geodetic[3];
Real enuBack[3];
Real northEast[2];
Real latLon[2];
Real northEastBack[2];
Real northByOneDegree[3];
Real expectedNorth_m;
Real localRoute[3, 3];
Real globalRoute[3, 3];
Real localBack[3, 3];
Real magneticFieldEnu_T[3];
Boolean magneticFieldValid;
algorithm
// East-North-Up round trip through the geodetic frame.
enu := {300.0, -150.0, 25.0};
geodetic := Geodesy.localEnuToGeodetic(origin, enu[1], enu[2], enu[3]);
enuBack := Geodesy.geodeticToLocalEnu(
origin, geodetic[1], geodetic[2], geodetic[3]);
assert(Tests.Assertions.maxAbsVector(enuBack - enu) < roundTripTolerance,
"geodeticToLocalEnu did not invert localEnuToGeodetic");
// North/east inverse recovers the forward great-circle projection.
northEast := {1000.0, -500.0};
latLon := Geodesy.localNorthEastToLatLon(
origin.latitude_deg, origin.longitude_deg, northEast[1], northEast[2]);
northEastBack := Geodesy.latLonToLocalNorthEast(
origin.latitude_deg, origin.longitude_deg, latLon[1], latLon[2]);
assert(
Tests.Assertions.maxAbsVector(northEastBack - northEast)
< roundTripTolerance,
"latLonToLocalNorthEast did not invert localNorthEastToLatLon");
// One degree of latitude is one Earth radius times one degree in radians,
// straight north with no east component.
northByOneDegree := Geodesy.geodeticToLocalEnu(
origin, origin.latitude_deg + 1.0, origin.longitude_deg,
origin.altitude_m);
expectedNorth_m := earthRadius_m * pi / 180.0;
assert(abs(northByOneDegree[2] - expectedNorth_m) < 1.0,
"One degree of latitude did not map to the meridian arc length");
assert(abs(northByOneDegree[1]) < 1.0e-3,
"A pure latitude change produced an east component");
assert(abs(northByOneDegree[3]) < 1.0e-9,
"A pure latitude change produced an up component");
// Whole-route projection round trip.
localRoute := [
0.0, 0.0, 0.0;
100.0, 50.0, 10.0;
-30.0, 80.0, 5.0];
globalRoute := Geodesy.routeLocalEnuToGeodetic(origin, localRoute);
localBack := Geodesy.projectRouteToLocalEnu(origin, globalRoute);
assert(
Tests.Assertions.maxAbsMatrix(localBack - localRoute)
< roundTripTolerance,
"projectRouteToLocalEnu did not invert routeLocalEnuToGeodetic");
// Official NOAA WMM2025 test vector: X north, Y east, Z down at
// 43 deg N, 93 deg E, 65 km WGS84 ellipsoid altitude, epoch 2025.0.
magneticFieldEnu_T :=
Geodesy.WMM2025.magneticFieldEnu(43.0, 93.0, 65000.0, 2025.0);
magneticFieldValid :=
Geodesy.WMM2025.validInputs(43.0, 65000.0, 2025.0);
assert(magneticFieldValid and Tests.Assertions.maxAbsVector(
magneticFieldEnu_T * 1.0e9
- {210.517066, 24299.852822, -50037.923998}) < 0.01,
"Pure-Modelica WMM2025 field did not match the NOAA reference vector");
passed := true;
end run;
parameter Boolean passed = run();
equation
assert(passed, "Geodesy assertions did not complete");
annotation(experiment(StartTime = 0.0, StopTime = 1.0, Tolerance = 1.0e-8,
Interval = 0.001));
end GeodesyTests;