-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathpropagation.zig
More file actions
141 lines (120 loc) · 6.18 KB
/
Copy pathpropagation.zig
File metadata and controls
141 lines (120 loc) · 6.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
const std = @import("std");
const astroz = @import("astroz");
const Tle = astroz.Tle;
const Sgp4 = astroz.Sgp4;
const Satellite = astroz.Satellite;
const constants = astroz.constants;
const propagators = astroz.propagators;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const tleStr =
\\1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9025
\\2 25544 51.6400 208.9163 0006703 30.5502 329.5947 15.49560830484850
;
var tle = try Tle.parse(tleStr, allocator);
defer tle.deinit();
// Example 1: Direct SGP4 usage
std.debug.print("=== Direct SGP4 Propagation ===\n", .{});
var sgp4 = try Sgp4.init(tle, constants.wgs84);
// Propagate at different times (minutes from TLE epoch)
const times = [_]f64{ 0, 30, 60, 90, 120 };
for (times) |tsince| {
const result = try sgp4.propagate(tsince);
const pos = result[0];
const vel = result[1];
const r = @sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]);
const v = @sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
std.debug.print("t={d:6.1} min: r={d:8.1} km, v={d:.3} km/s\n", .{ tsince, r, v });
}
// Example 1.5: Using SIMD V4 (4 steps at once)
std.debug.print("\n=== SIMD V4 Batch Propagation (4 times) ===\n", .{});
const batchTimes4 = [4]f64{ 0, 30, 60, 90 };
const batchResults4 = try sgp4.propagateN(4, batchTimes4);
for (batchTimes4, batchResults4) |tsince, result| {
const pos = result[0];
const vel = result[1];
const r = @sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]);
const v = @sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
std.debug.print("t={d:6.1} min: r={d:8.1} km, v={d:.3} km/s\n", .{ tsince, r, v });
}
// Example 1.6: Using SIMD V8 (8 steps at once, AVX512)
std.debug.print("\n=== SIMD V8 Batch Propagation (8 times) ===\n", .{});
const batchTimes8 = [8]f64{ 0, 15, 30, 45, 60, 75, 90, 105 };
const batchResults8 = try sgp4.propagateN(8, batchTimes8);
for (batchTimes8, batchResults8) |tsince, result| {
const pos = result[0];
const vel = result[1];
const r = @sqrt(pos[0] * pos[0] + pos[1] * pos[1] + pos[2] * pos[2]);
const v = @sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
std.debug.print("t={d:6.1} min: r={d:8.1} km, v={d:.3} km/s\n", .{ tsince, r, v });
}
// Example 2: Using the modular propagator interface
std.debug.print("\n=== SGP4 via Propagator Interface ===\n", .{});
var sgp4Int = try propagators.Sgp4Integrator.init(tle, constants.wgs84);
var prop = propagators.Propagator.init(allocator, sgp4Int.integrator(), null);
// Propagate for 2 hours (7200 seconds) with 30-minute steps
const initial = [6]f64{ 0, 0, 0, 0, 0, 0 }; // ignored by SGP4
var trajectory = try prop.propagate(initial, 0, 7200, 1800);
defer trajectory.deinit(allocator);
std.debug.print("Generated {d} trajectory points\n", .{trajectory.items.len});
for (trajectory.items[1..]) |point| { // skip first point (SGP4 ignores initial state)
const r = @sqrt(point.state[0] * point.state[0] +
point.state[1] * point.state[1] +
point.state[2] * point.state[2]);
std.debug.print("t={d:6.0}s: r={d:8.1} km\n", .{ point.time, r });
}
// Example 3: Compare with numerical RK4 propagation
std.debug.print("\n=== Comparison: SGP4 vs RK4+TwoBody ===\n", .{});
// Get initial state from SGP4 at epoch
const sgp4State = try sgp4.propagate(0);
const initState = [6]f64{
sgp4State[0][0], sgp4State[0][1], sgp4State[0][2],
sgp4State[1][0], sgp4State[1][1], sgp4State[1][2],
};
// Setup RK4 with two-body gravity
var twobody = propagators.TwoBody.init(constants.earth.mu);
var rk4 = propagators.Rk4{};
var rk4Prop = propagators.Propagator.init(allocator, rk4.integrator(), propagators.ForceModel.wrap(propagators.TwoBody, &twobody));
// Propagate both for 90 minutes (one orbit)
const duration = 90.0 * 60.0;
const sgp4Final = try sgp4.propagate(90);
const rk4Final = try rk4Prop.propagateTo(initState, 0, duration, 10);
const sgp4R = @sqrt(sgp4Final[0][0] * sgp4Final[0][0] +
sgp4Final[0][1] * sgp4Final[0][1] +
sgp4Final[0][2] * sgp4Final[0][2]);
const rk4R = @sqrt(rk4Final[0] * rk4Final[0] +
rk4Final[1] * rk4Final[1] +
rk4Final[2] * rk4Final[2]);
std.debug.print("After 90 minutes:\n", .{});
std.debug.print(" SGP4: r = {d:.1} km\n", .{sgp4R});
std.debug.print(" RK4: r = {d:.1} km\n", .{rk4R});
std.debug.print(" Diff: {d:.1} km\n", .{@abs(sgp4R - rk4R)});
std.debug.print("\nNote: SGP4 includes J2/drag perturbations analytically,\n", .{});
std.debug.print("while RK4+TwoBody is pure Keplerian - expect divergence.\n", .{});
// Example 4: Unified Satellite type (auto-dispatches SGP4/SDP4)
std.debug.print("\n=== Unified Satellite (auto SGP4/SDP4) ===\n", .{});
// Near-earth: automatically uses SGP4
const sat_leo = try Satellite.init(tle, constants.wgs84);
std.debug.print("ISS (LEO): deep_space={}\n", .{sat_leo.isDeepSpace()});
const leo_result = try sat_leo.propagate(60);
const leo_r = @sqrt(leo_result[0][0] * leo_result[0][0] +
leo_result[0][1] * leo_result[0][1] +
leo_result[0][2] * leo_result[0][2]);
std.debug.print(" t=60 min: r={d:.1} km\n", .{leo_r});
// Deep-space: automatically uses SDP4
const gpsTleStr =
\\1 20413U 90005A 24186.00000000 .00000012 00000+0 10000-3 0 9992
\\2 20413 55.4408 61.4858 0112981 129.5765 231.5553 2.00561730104446
;
var gpsTle = try Tle.parse(gpsTleStr, allocator);
defer gpsTle.deinit();
const sat_gps = try Satellite.init(gpsTle, constants.wgs72);
std.debug.print("GPS (MEO): deep_space={}\n", .{sat_gps.isDeepSpace()});
const gps_result = try sat_gps.propagate(720);
const gps_r = @sqrt(gps_result[0][0] * gps_result[0][0] +
gps_result[0][1] * gps_result[0][1] +
gps_result[0][2] * gps_result[0][2]);
std.debug.print(" t=720 min: r={d:.1} km\n", .{gps_r});
}