korba 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d032139625c6722891cef771fc76ffb90e8b082f89146ebb860a5f8034004b15
4
- data.tar.gz: 354e2f0f7c382059bf7a424ffd952c32b56b6ae616b5c7bd42f50a148d2f42c3
3
+ metadata.gz: 5dc3a4abbdd189f4388673e3960a615940a4feb68c359cce37a29ff47fa7efcb
4
+ data.tar.gz: c312b2be706e321242d0f4c762134ad82ea681348e5631ec36a13ed91c36db11
5
5
  SHA512:
6
- metadata.gz: 6f73a3a19efff8c89299173d67dbfa1aaf754ce1c0828148f7bd3933cd57d8de8ba74352cc12849fcd405882c964f345353e1f6d4204b4e451d00a8a6ebf5337
7
- data.tar.gz: 293456b12a49007bb1f1c1acc6201fcf99678e5427b1c81942d9f1e53ab5c9cc8716ffdeaaa562846c45ef2b245400f7d73758a05494da91df1528da9e06cba0
6
+ metadata.gz: f0cc15b9fa16cec125d3902e3b52e1336acf4246c72860049955c32456d1eaa0e56a2fd99953477d36141da23b3b8696ed0b8a611c80bc51e1249368c7f07f84
7
+ data.tar.gz: ffcbf5ed21c86f069d83276227c9db29e5b59d257d1630f5a1fb15eaff0550b881b1e7753fcc551ce6c647c49faf2bc84ee52efb015fbd9ad8efa9355b2da6ad
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.8.0] - 2026-04-19
2
+
3
+ - Enable orbit propagation using 4th-order Runge-Kutta
4
+ - Enable conversion from Cartesian to Keplerian elements
5
+
1
6
  ## [0.7.1] - 2026-04-05
2
7
 
3
8
  - FIX: Fixed calculation when orbital inclination and eccentricity are 0
data/lib/korba/car.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Korba
4
4
  class Car
5
+ include OrbitUtils
6
+
5
7
  attr_reader :object_name, :epoch, :x, :y, :z, :vx, :vy, :vz
6
8
 
7
9
  def initialize(object_name:, epoch:, x:, y:, z:, vx:, vy:, vz:)
@@ -14,5 +16,85 @@ module Korba
14
16
  @vy = vy
15
17
  @vz = vz
16
18
  end
19
+
20
+ def to_kep
21
+ inclination = rad_to_deg(Math.atan2(Math.sqrt(specific_angular_momentum_vector[0] ** 2 + specific_angular_momentum_vector[1] ** 2), specific_angular_momentum_vector[2]))
22
+ ra_of_asc_node = rad_to_deg(Math.atan2(specific_angular_momentum_vector[0], -specific_angular_momentum_vector[1]))
23
+
24
+ Kep.new(object_name:,
25
+ epoch:,
26
+ semi_major_axis:,
27
+ eccentricity:,
28
+ inclination:,
29
+ ra_of_asc_node:,
30
+ arg_of_pericenter: normalize_deg(arg_of_latitude - true_anomaly),
31
+ mean_anomaly: rad_to_deg(deg_to_rad(eccentric_anomaly) - eccentricity * Math.sin(deg_to_rad(eccentric_anomaly))))
32
+ end
33
+
34
+ private
35
+
36
+ def position_vector
37
+ @position_vector ||= Vector[x, y, z]
38
+ end
39
+
40
+ def velocity_vector
41
+ @velocity_vector ||= Vector[vx, vy, vz]
42
+ end
43
+
44
+ def distance
45
+ @distance ||= position_vector.norm
46
+ end
47
+
48
+ def velocity
49
+ @velocity ||= velocity_vector.norm
50
+ end
51
+
52
+ def semi_major_axis
53
+ @semi_major_axis ||= Constant::GME * distance / (2 * Constant::GME - distance * velocity ** 2)
54
+ end
55
+
56
+ def eccentricity
57
+ @eccentricity ||= Math.sqrt(((semi_major_axis - distance) / semi_major_axis) ** 2 + (position_vector.dot(velocity_vector) ** 2) / (Constant::GME * semi_major_axis))
58
+ end
59
+
60
+ def eccentric_anomaly
61
+ @eccentric_anomaly ||= rad_to_deg(Math.atan2(Math.sqrt(semi_major_axis / Constant::GME) * position_vector.dot(velocity_vector), semi_major_axis - distance))
62
+ end
63
+
64
+ def true_anomaly
65
+ factor = (Math.cos(deg_to_rad(eccentric_anomaly)) - eccentricity) / (1 - eccentricity * Math.cos(deg_to_rad(eccentric_anomaly)))
66
+ rad_to_deg(Math.atan2(Math.sqrt(1 - factor ** 2), factor))
67
+ end
68
+
69
+ def angular_momentum_vector
70
+ @angular_momentum_vector ||= position_vector.cross(velocity_vector)
71
+ end
72
+
73
+ def raan_vector
74
+ @raan_vector ||= Vector[0, 0, 1].cross(angular_momentum_vector)
75
+ end
76
+
77
+ def eccentricity_vector
78
+ @eccentricity_vector ||= ((velocity ** 2 - Constant::GME / distance) * position_vector - (position_vector * velocity_vector) * velocity_vector) / Constant::GME
79
+ end
80
+
81
+ def specific_angular_momentum_vector
82
+ @specific_angular_momentum_vector ||= position_vector.cross(velocity_vector)
83
+ end
84
+
85
+ def raan_vector
86
+ @raan_vector ||= Vector[0, 0, 1].cross(specific_angular_momentum_vector)
87
+ end
88
+
89
+ def arg_of_latitude
90
+ y = position_vector.dot(raan_vector)
91
+ x = position_vector.norm * raan_vector.norm
92
+ arg_of_latitude = (Math.atan2(
93
+ Math.sqrt(1 - (y / x) ** 2),
94
+ y / x
95
+ ))
96
+ arg_of_latitude = 2 * Math::PI - arg_of_latitude if z < 0
97
+ rad_to_deg(arg_of_latitude)
98
+ end
17
99
  end
18
100
  end
@@ -5,6 +5,7 @@ module Korba
5
5
  # geocentric gravitational constant in m3/s2
6
6
  GME = 3.9860044188e14
7
7
  # nominal equatorial Earth radius in m
8
- EARTH_RADIUS = 6378137
8
+ EARTH_RADIUS = 6378137.0
9
+ J2 = 1.08262668e-3
9
10
  end
10
11
  end
data/lib/korba/kep.rb CHANGED
@@ -42,6 +42,14 @@ module Korba
42
42
  v_angle_factor = deg_to_rad(arg_of_pericenter + true_anomaly - path_angle)
43
43
  vector_v = velocity * (-Math.sin(v_angle_factor) * vector_omega + (Math.cos(v_angle_factor)) * vector_m)
44
44
 
45
+ # NOTE: こっちでもいい
46
+ # factor_matrix = Matrix[[Math.cos(deg_to_rad(ra_of_asc_node)), -Math.sin(deg_to_rad(ra_of_asc_node)) * Math.cos(deg_to_rad(inclination))],
47
+ # [Math.sin(deg_to_rad(ra_of_asc_node)), Math.cos(deg_to_rad(ra_of_asc_node)) * Math.cos(deg_to_rad(inclination))],
48
+ # [0, Math.sin(deg_to_rad(inclination))]] *
49
+ # Matrix[[Math.cos(deg_to_rad(arg_of_pericenter)), -Math.sin(deg_to_rad(arg_of_pericenter))], [Math.sin(deg_to_rad(arg_of_pericenter)), Math.cos(deg_to_rad(arg_of_pericenter))]]
50
+ # vector_r = Vector[*(factor_matrix * Matrix[[Math.cos(deg_to_rad(true_anomaly)) - eccentricity], [Math.sqrt(1 - eccentricity ** 2) * Math.sin(deg_to_rad(true_anomaly))]] * semi_major_axis).to_a.flatten]
51
+ # vector_v = Vector[*(factor_matrix * Matrix[[-Math.sin(deg_to_rad(true_anomaly))], [Math.sqrt(1 - eccentricity ** 2) * Math.cos(deg_to_rad(true_anomaly))]] * Math.sqrt(Constant::GME * semi_major_axis) / vector_r.norm).to_a.flatten]
52
+
45
53
  Car.new(object_name:, epoch:, x: vector_r[0], y: vector_r[1], z: vector_r[2], vx: vector_v[0], vy: vector_v[1], vz: vector_v[2])
46
54
  end
47
55
  end
@@ -0,0 +1,63 @@
1
+ module Korba
2
+ module Propagator
3
+ class Rk4
4
+ def initialize(initial_car, disable_j2: false)
5
+ @initial_car = initial_car
6
+ @disable_j2 = disable_j2
7
+ end
8
+
9
+ def propagate(seconds_after_epoch, dt = 1.0)
10
+ steps = (seconds_after_epoch / dt).to_i
11
+ t = 0.0
12
+ y = Vector[@initial_car.x, @initial_car.y, @initial_car.z, @initial_car.vx, @initial_car.vy, @initial_car.vz]
13
+
14
+ steps.times do
15
+ y = step(t, y, dt)
16
+ t += dt
17
+ end
18
+
19
+ Car.new(
20
+ object_name: @initial_car.object_name,
21
+ epoch: @initial_car.epoch + seconds_after_epoch,
22
+ x: y[0],
23
+ y: y[1],
24
+ z: y[2],
25
+ vx: y[3],
26
+ vy: y[4],
27
+ vz: y[5],
28
+ )
29
+ end
30
+
31
+ private
32
+
33
+ def step(t, y, dt)
34
+ k1 = f(t, y)
35
+ k2 = f(t + dt / 2.0, y + k1 * (dt / 2.0))
36
+ k3 = f(t + dt / 2.0, y + k2 * (dt / 2.0))
37
+ k4 = f(t + dt, y + k3 * dt)
38
+
39
+ y + (k1 + 2 * k2 + 2 * k3 + k4) * (dt / 6.0)
40
+ end
41
+
42
+ def f(t, y)
43
+ position_vector = Vector[y[0], y[1], y[2]]
44
+ velocity_vector = Vector[y[3], y[4], y[5]]
45
+ r = position_vector.magnitude
46
+ base_acceleration_vector = -Constant::GME * position_vector / (r ** 3)
47
+ acceleration_vector = @disable_j2 ? base_acceleration_vector : add_j2_effect(base_acceleration_vector, r, position_vector[2])
48
+
49
+ Vector[velocity_vector[0], velocity_vector[1], velocity_vector[2], acceleration_vector[0], acceleration_vector[1], acceleration_vector[2]]
50
+ end
51
+
52
+ def add_j2_effect(base_acceleration_vector, r, z)
53
+ j2_factor = (3.0 / 2.0) * Constant::J2 * (Constant::EARTH_RADIUS / r) ** 2
54
+ factor = 5 * (z / r) ** 2
55
+ [
56
+ base_acceleration_vector[0] * (1 + j2_factor * (1 - factor)),
57
+ base_acceleration_vector[1] * (1 + j2_factor * (1 - factor)),
58
+ base_acceleration_vector[2] * (1 + j2_factor * (3 - factor)),
59
+ ]
60
+ end
61
+ end
62
+ end
63
+ end