korba 0.6.0 → 0.7.1

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: 2e1fb6aee8c669efdda379b50b45af24fc6fabf6514972cbfc93a8156c54f533
4
- data.tar.gz: cde0a77ead9cecb840aa1fad00693c5a5c61428ae6cd6f905f2faf05ec1973d7
3
+ metadata.gz: d032139625c6722891cef771fc76ffb90e8b082f89146ebb860a5f8034004b15
4
+ data.tar.gz: 354e2f0f7c382059bf7a424ffd952c32b56b6ae616b5c7bd42f50a148d2f42c3
5
5
  SHA512:
6
- metadata.gz: 8981644e546a11c656d83c751aa9e9ce19046df56258287a1f9219401377feef7def725de5d4cfa75481dd156179cd93404cc89d20aa80b0761ac0fba42c4d93
7
- data.tar.gz: 17306bb686d434c116d531681a6dcabd4998825e24ec042e65f1d08b84350e80a2645603ece086edf2c8d124811f641f0706011e5d32b29da687482c3ee61c5b
6
+ metadata.gz: 6f73a3a19efff8c89299173d67dbfa1aaf754ce1c0828148f7bd3933cd57d8de8ba74352cc12849fcd405882c964f345353e1f6d4204b4e451d00a8a6ebf5337
7
+ data.tar.gz: 293456b12a49007bb1f1c1acc6201fcf99678e5427b1c81942d9f1e53ab5c9cc8716ffdeaaa562846c45ef2b245400f7d73758a05494da91df1528da9e06cba0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.7.1] - 2026-04-05
2
+
3
+ - FIX: Fixed calculation when orbital inclination and eccentricity are 0
4
+
5
+ ## [0.7.0] - 2026-04-01
6
+
7
+ - FIX: Use SGP4 for TLE to Cartesian conversion
8
+ - FIX: Remove Newton's method library and implement Kepler equation processing
9
+
1
10
  ## [0.6.0] - 2024-12-27
2
11
 
3
12
  - Enable use SGP4
data/README.md CHANGED
@@ -70,6 +70,8 @@ kep.to_car
70
70
  - https://www.coronasha.co.jp/np/isbn/9784339012316/
71
71
  - 人工衛星の軌道 概論
72
72
  - https://www.coronasha.co.jp/np/isbn/9784339046403/
73
+ - SGP4
74
+ - https://github.com/aholinch/sgp4
73
75
 
74
76
  ## Development
75
77
 
data/lib/korba/kep.rb CHANGED
@@ -19,13 +19,23 @@ module Korba
19
19
  end
20
20
 
21
21
  def to_car
22
- vector_n = Vector[
23
- Math.sin(deg_to_rad(inclination)) * Math.sin(deg_to_rad(ra_of_asc_node)),
24
- -Math.sin(deg_to_rad(inclination)) * Math.cos(deg_to_rad(ra_of_asc_node)),
25
- Math.cos(deg_to_rad(inclination))
26
- ]
27
- vector_omega = Vector[Math.cos(deg_to_rad(ra_of_asc_node)), Math.sin(deg_to_rad(ra_of_asc_node)), 0]
28
- vector_m = vector_n.cross(vector_omega)
22
+ # 特異点対応: inclinationが0(または極めて小さい)場合の処理
23
+ is_equatorial = inclination.abs < 1e-10
24
+
25
+ if is_equatorial
26
+ # 赤道面内の場合、x軸を基準にする
27
+ vector_omega = Vector[1.0, 0.0, 0.0]
28
+ vector_m = Vector[0.0, 1.0, 0.0]
29
+ vector_n = Vector[0.0, 0.0, 1.0]
30
+ else
31
+ vector_n = Vector[
32
+ Math.sin(deg_to_rad(inclination)) * Math.sin(deg_to_rad(ra_of_asc_node)),
33
+ -Math.sin(deg_to_rad(inclination)) * Math.cos(deg_to_rad(ra_of_asc_node)),
34
+ Math.cos(deg_to_rad(inclination))
35
+ ]
36
+ vector_omega = Vector[Math.cos(deg_to_rad(ra_of_asc_node)), Math.sin(deg_to_rad(ra_of_asc_node)), 0.0]
37
+ vector_m = vector_n.cross(vector_omega)
38
+ end
29
39
 
30
40
  r_angle_factor = deg_to_rad(arg_of_pericenter + true_anomaly)
31
41
  vector_r = distance * (Math.cos(r_angle_factor) * vector_omega + Math.sin(r_angle_factor) * vector_m)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Korba
4
+ class KeplersEquation
5
+ include OrbitUtils
6
+
7
+ attr_reader :eccentricity, :mean_anomaly
8
+
9
+ def initialize(eccentricity:, mean_anomaly:)
10
+ super()
11
+ @eccentricity = eccentricity
12
+ @mean_anomaly = mean_anomaly
13
+ end
14
+
15
+ MAX_ITERATIONS = 1000
16
+ def solve(tolerance = 1e-10)
17
+ m_rad = deg_to_rad(mean_anomaly)
18
+
19
+ if eccentricity < 0.8
20
+ en = m_rad
21
+ else
22
+ en = Math::PI
23
+ end
24
+
25
+ MAX_ITERATIONS.times do
26
+ # f(E) = E - e*sin(E) - M
27
+ # f'(E) = 1 - e*cos(E)
28
+
29
+ sin_en = Math.sin(en.to_f)
30
+ cos_en = Math.cos(en.to_f)
31
+
32
+ f = en - eccentricity * sin_en - m_rad
33
+ f_dot = 1 - eccentricity * cos_en
34
+
35
+ # 更新
36
+ delta = f / f_dot
37
+ en = en - delta
38
+
39
+ # 収束判定
40
+ break if delta.abs < tolerance
41
+ end
42
+
43
+ en
44
+ end
45
+ end
46
+ end
@@ -4,7 +4,7 @@ module Korba
4
4
  module OrbitUtils
5
5
  def semi_major_axis
6
6
  # a = (μ / n^2)^(1/3) m
7
- (Constant::GME / (mean_motion * 2 * Math::PI / 86400.0) ** 2.0) ** (1.0 / 3.0)
7
+ (Constant::GME / (mean_motion * 2.0 * Math::PI / 86400.0) ** 2.0) ** (1.0 / 3.0)
8
8
  end
9
9
 
10
10
  def height_at_perigee
@@ -16,15 +16,17 @@ module Korba
16
16
  end
17
17
 
18
18
  def eccentric_anomaly
19
- f = KeplerEquationFunction.new(eccentricity:, mean_anomaly:)
20
- x = [deg_to_rad(mean_anomaly)]
21
- nlsolve(f, x)
22
- rad_to_deg(x[0])
19
+ kepler = KeplersEquation.new(eccentricity:, mean_anomaly:)
20
+ rad_to_deg(kepler.solve)
23
21
  end
24
22
 
25
23
  def true_anomaly
26
- factor = (Math.cos(deg_to_rad(eccentric_anomaly)) - eccentricity) / (1 - eccentricity * Math.cos(deg_to_rad(eccentric_anomaly)))
27
- rad_to_deg(Math.acos(factor))
24
+ e_rad = deg_to_rad(eccentric_anomaly)
25
+ y = Math.sqrt(1 - eccentricity ** 2) * Math.sin(e_rad)
26
+ x = Math.cos(e_rad) - eccentricity
27
+
28
+ # atan2(y, x) で正確な位相(-pi から pi)を求める
29
+ rad_to_deg(Math.atan2(y, x))
28
30
  end
29
31
 
30
32
  def distance
@@ -32,10 +34,12 @@ module Korba
32
34
  end
33
35
 
34
36
  def velocity
35
- Math.sqrt(Constant::GME * (2 / distance - 1 / semi_major_axis))
37
+ Math.sqrt(Constant::GME * (2.0 / distance - 1.0 / semi_major_axis))
36
38
  end
37
39
 
38
40
  def path_angle
41
+ return 0.0 if eccentricity < 1e-15
42
+
39
43
  factor = Math.sqrt(Constant::GME * semi_major_axis * (1 - eccentricity ** 2)) / (distance * velocity)
40
44
  rad_to_deg(Math.acos(factor))
41
45
  end
@@ -46,8 +50,8 @@ module Korba
46
50
  end
47
51
 
48
52
  def normalize_rad(rad)
49
- rad = rad + 2 * Math::PI if rad < 0
50
- normalize_rad = rad > 2 * Math::PI ? rad - 2 * Math::PI : rad
53
+ rad = rad + 2.0 * Math::PI if rad < 0
54
+ normalize_rad = rad > 2.0 * Math::PI ? rad - 2.0 * Math::PI : rad
51
55
  normalize_rad(normalize_rad) if normalize_rad != rad
52
56
  normalize_rad
53
57
  end
@@ -58,8 +62,8 @@ module Korba
58
62
  end
59
63
 
60
64
  def normalize_deg(deg)
61
- deg = deg + 360 if deg < 0
62
- normalized_deg = deg > 360 ? deg - 360 : deg
65
+ deg = deg + 360.0 if deg < 0
66
+ normalized_deg = deg > 360.0 ? deg - 360.0 : deg
63
67
  normalize_deg(normalized_deg) if normalized_deg != deg
64
68
  normalized_deg
65
69
  end
data/lib/korba/tle.rb CHANGED
@@ -5,7 +5,7 @@ module Korba
5
5
  class Tle
6
6
  include OrbitUtils
7
7
 
8
- attr_reader :tle_json, :tle_string, :object_id, :object_name, :epoch_datetime, :julian_date,
8
+ attr_reader :tle_json, :tle_string, :sattelite_id, :object_name, :epoch_datetime, :julian_date,
9
9
  :satellite_number, :classification_type, :epoch, :mean_motion_dot, :mean_motion_ddot, :bstar, :element_set_no,
10
10
  :inclination, :ra_of_asc_node, :eccentricity, :arg_of_pericenter, :mean_anomaly, :mean_motion, :revolution_number,
11
11
  :element_set_record, :epoch_days
@@ -35,8 +35,7 @@ module Korba
35
35
  end
36
36
 
37
37
  def to_car
38
- kep = to_kep
39
- kep.to_car
38
+ propagate_to(0)
40
39
  end
41
40
 
42
41
  def propagate_to(minutesAfterEpoch)
@@ -62,7 +61,7 @@ module Korba
62
61
  end
63
62
 
64
63
  def parse_line1(line1_strings)
65
- # TODO: object_id
64
+ # TODO: sattelite_id
66
65
  @satellite_number = line1_strings[1][0..4].to_i
67
66
  @classification_type = line1_strings[1][-1]
68
67
  # For now, only supports years after 2000
@@ -103,7 +102,7 @@ module Korba
103
102
  def initialize_from_json(tle_json)
104
103
  @tle_json = tle_json
105
104
  @object_name = tle_json[:OBJECT_NAME]
106
- @object_id = tle_json[:OBJECT_ID]
105
+ @sattelite_id = tle_json[:OBJECT_ID]
107
106
  @satellite_number = tle_json[:NORAD_CAT_ID]
108
107
  @classification_type = tle_json[:CLASSIFICATION_TYPE]
109
108
  @epoch = tle_json[:EPOCH]
data/lib/korba/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Korba
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.1"
5
5
  end
data/lib/korba.rb CHANGED
@@ -6,7 +6,7 @@ require_relative "korba/tle"
6
6
  require_relative "korba/kep"
7
7
  require_relative "korba/car"
8
8
  require_relative "korba/orbit_utils"
9
- require_relative "korba/kepler_equation_fucntion"
9
+ require_relative "korba/keplers_equation"
10
10
  require_relative "korba/sgp4/elset_rec"
11
11
  require_relative "korba/sgp4/sgp4"
12
12
 
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4.5"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: korba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - kk0000-kk
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-12-26 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: Orbital elements calculation library
14
13
  email:
@@ -25,13 +24,13 @@ files:
25
24
  - lib/korba/car.rb
26
25
  - lib/korba/constant.rb
27
26
  - lib/korba/kep.rb
28
- - lib/korba/kepler_equation_fucntion.rb
29
- - lib/korba/newton_function.rb
27
+ - lib/korba/keplers_equation.rb
30
28
  - lib/korba/orbit_utils.rb
31
29
  - lib/korba/sgp4/elset_rec.rb
32
30
  - lib/korba/sgp4/sgp4.rb
33
31
  - lib/korba/tle.rb
34
32
  - lib/korba/version.rb
33
+ - mise.toml
35
34
  - sig/korba.rbs
36
35
  homepage: https://github.com/kk0000-kk/korba
37
36
  licenses: []
@@ -40,7 +39,6 @@ metadata:
40
39
  homepage_uri: https://github.com/kk0000-kk/korba
41
40
  source_code_uri: https://github.com/kk0000-kk/korba
42
41
  changelog_uri: https://github.com/kk0000-kk/korba/blob/main/CHANGELOG.md
43
- post_install_message:
44
42
  rdoc_options: []
45
43
  require_paths:
46
44
  - lib
@@ -55,8 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
53
  - !ruby/object:Gem::Version
56
54
  version: '0'
57
55
  requirements: []
58
- rubygems_version: 3.5.23
59
- signing_key:
56
+ rubygems_version: 3.7.2
60
57
  specification_version: 4
61
58
  summary: Orbital elements calculation library
62
59
  test_files: []
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative "newton_function"
3
-
4
- module Korba
5
- class KeplerEquationFunction < NewtonFunction
6
- include OrbitUtils
7
-
8
- attr_reader :eccentricity, :mean_anomaly
9
-
10
- def initialize(eccentricity:, mean_anomaly:)
11
- super()
12
- @eccentricity = eccentricity
13
- @mean_anomaly = mean_anomaly
14
- end
15
-
16
- def values(x)
17
- [x[0] - eccentricity * Math.sin(x[0]) - deg_to_rad(mean_anomaly)]
18
- end
19
- end
20
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
- require "bigdecimal/newton"
3
- include Newton
4
-
5
- module Korba
6
- class NewtonFunction
7
- def initialize()
8
- @zero = BigDecimal("0.0")
9
- @one = BigDecimal("1.0")
10
- @two = BigDecimal("2.0")
11
- @ten = BigDecimal("10.0")
12
- @eps = BigDecimal("1.0e-14")
13
- end
14
-
15
- def zero; @zero; end
16
- def one; @one; end
17
- def two; @two; end
18
- def ten; @ten; end
19
- def eps; @eps; end
20
-
21
- def values(x)
22
- raise NotImplementedError
23
- end
24
- end
25
- end