orbit 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +14 -0
- data/README.md +16 -0
- data/lib/orbit.rb +27 -0
- data/lib/orbit/demo.rb +152 -0
- data/lib/orbit/eci.rb +130 -0
- data/lib/orbit/geocentric_coordinates.rb +37 -0
- data/lib/orbit/julian.rb +153 -0
- data/lib/orbit/norad_base.rb +261 -0
- data/lib/orbit/norad_sdp4.rb +4 -0
- data/lib/orbit/norad_sgp4.rb +101 -0
- data/lib/orbit/orbit.rb +163 -0
- data/lib/orbit/orbit_globals.rb +128 -0
- data/lib/orbit/satellite.rb +40 -0
- data/lib/orbit/site.rb +115 -0
- data/lib/orbit/tle.rb +127 -0
- data/lib/orbit/topocentric_horizon_coordinates.rb +33 -0
- data/lib/orbit/vector.rb +56 -0
- data/orbit.gemspec +17 -0
- metadata +67 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
orbit
|
2
|
+
=====
|
3
|
+
|
4
|
+
A ruby gem for calculating satellite positions and observation angles, etc.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
tle = "EYESAT-1 (AO-27)\n1 22825U 93061C 12265.90994989 .00000070 00000-0 44528-4 0 2022\n2 22825 98.5823 207.2528 0008444 2.3056 357.8161 14.29486540990291"
|
9
|
+
s = Orbit::Satellite.new( tle )
|
10
|
+
l = Orbit::Site.new( 33.5, -95.3, 23 ) # Lat, Lng, Elevation Above Sea Level in Meters
|
11
|
+
tc = l.view_angle_to_satellite_at_time( s, Time.now )
|
12
|
+
|
13
|
+
elevation = Orbit::OrbitGlobals.rad_to_deg( tc.elevation )
|
14
|
+
azimuth = Orbit::OrbitGlobals.rad_to_deg( tc.azimuth )
|
15
|
+
|
16
|
+
puts "Elevation: #{elevation}, Azimuth: #{azimuth}"
|
data/lib/orbit.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'orbit/orbit_globals'
|
2
|
+
require 'orbit/geocentric_coordinates'
|
3
|
+
require 'orbit/topocentric_horizon_coordinates'
|
4
|
+
require 'orbit/julian'
|
5
|
+
require 'orbit/norad_base'
|
6
|
+
require 'orbit/norad_sgp4'
|
7
|
+
require 'orbit/norad_sdp4'
|
8
|
+
require 'orbit/eci'
|
9
|
+
require 'orbit/site'
|
10
|
+
require 'orbit/satellite'
|
11
|
+
require 'orbit/tle'
|
12
|
+
require 'orbit/orbit'
|
13
|
+
require 'orbit/vector'
|
14
|
+
require 'date'
|
15
|
+
|
16
|
+
module Orbit
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
# Testing
|
21
|
+
# tle_string = "CUBESAT XI-V (CO-58)\n1 28895U 05043F 12264.16320281 .00000287 00000-0 67805-4 0 2813\n2 28895 97.9003 126.1967 0016829 209.8455 150.1749 14.60744896367522"
|
22
|
+
#
|
23
|
+
# tle = Orbit::Tle.new( tle_string )
|
24
|
+
# o = Orbit::Orbit.new( tle )
|
25
|
+
# eci = o.get_position( ( Time.new.utc.to_f - tle.epoch.to_f ) / 60.0 )
|
26
|
+
# puts eci
|
27
|
+
# puts eci.to_geo
|
data/lib/orbit/demo.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
require './orbit_globals.rb'
|
2
|
+
require './geocentric_coordinates.rb'
|
3
|
+
require './topocentric_horizon_coordinates.rb'
|
4
|
+
require './julian.rb'
|
5
|
+
require './norad_base.rb'
|
6
|
+
require './norad_sgp4.rb'
|
7
|
+
require './norad_sdp4.rb'
|
8
|
+
require './eci.rb'
|
9
|
+
require './site.rb'
|
10
|
+
require './tle.rb'
|
11
|
+
require './orbit.rb'
|
12
|
+
require './vector.rb'
|
13
|
+
require 'pp'
|
14
|
+
require 'date'
|
15
|
+
|
16
|
+
# def PrintPosVel(Tle tle)
|
17
|
+
# const int Step = 360;
|
18
|
+
#
|
19
|
+
# Orbit orbit = new Orbit(tle);
|
20
|
+
# List<Eci> coords = new List<Eci>();
|
21
|
+
#
|
22
|
+
# # Calculate position, velocity
|
23
|
+
# # mpe = "minutes past epoch"
|
24
|
+
# for (int mpe = 0; mpe <= (Step * 4); mpe += Step)
|
25
|
+
# {
|
26
|
+
# # Get the position of the satellite at time "mpe".
|
27
|
+
# # The coordinates are placed into the variable "eci".
|
28
|
+
# Eci eci = orbit.GetPosition(mpe);
|
29
|
+
#
|
30
|
+
# # Add the coordinate object to the list
|
31
|
+
# coords.Add(eci);
|
32
|
+
# }
|
33
|
+
#
|
34
|
+
# # Print TLE data
|
35
|
+
# Console.Write("{0}\n", tle.Name);
|
36
|
+
# Console.Write("{0}\n", tle.Line1);
|
37
|
+
# Console.Write("{0}\n", tle.Line2);
|
38
|
+
#
|
39
|
+
# # Header
|
40
|
+
# Console.Write("\n TSINCE X Y Z\n\n");
|
41
|
+
#
|
42
|
+
# # Iterate over each of the ECI position objects pushed onto the
|
43
|
+
# # coordinate list, above, printing the ECI position information
|
44
|
+
# # as we go.
|
45
|
+
# for (int i = 0; i < coords.Count; i++)
|
46
|
+
# {
|
47
|
+
# Eci e = coords[i] as Eci;
|
48
|
+
#
|
49
|
+
# Console.Write("{0,8}.00 {1,16:f8} {2,16:f8} {3,16:f8}\n",
|
50
|
+
# i * Step,
|
51
|
+
# e.Position.X,
|
52
|
+
# e.Position.Y,
|
53
|
+
# e.Position.Z);
|
54
|
+
# }
|
55
|
+
#
|
56
|
+
# Console.Write("\n XDOT YDOT ZDOT\n\n");
|
57
|
+
#
|
58
|
+
# # Iterate over each of the ECI position objects in the coordinate
|
59
|
+
# # list again, but this time print the velocity information.
|
60
|
+
# for (int i = 0; i < coords.Count; i++)
|
61
|
+
# {
|
62
|
+
# Eci e = coords[i] as Eci;
|
63
|
+
#
|
64
|
+
# Console.Write("{0,24:f8} {1,16:f8} {2,16:f8}\n",
|
65
|
+
# e.Velocity.X,
|
66
|
+
# e.Velocity.Y,
|
67
|
+
# e.Velocity.Z);
|
68
|
+
# }
|
69
|
+
# end
|
70
|
+
|
71
|
+
|
72
|
+
tle_string = "OSCAR 3\n"
|
73
|
+
tle_string += "1 01293U 65016F 12263.95608778 +.00000319 +00000-0 +23014-3 0 04606\n"
|
74
|
+
tle_string += "2 01293 070.0701 117.1490 0017260 014.5647 345.5955 14.05174409427057"
|
75
|
+
|
76
|
+
tle1 = Tle.new(tle_string)
|
77
|
+
|
78
|
+
#puts tle1
|
79
|
+
|
80
|
+
# PrintPosVel(tle1);
|
81
|
+
|
82
|
+
# puts ""
|
83
|
+
|
84
|
+
# Test SDP4
|
85
|
+
# tle_string = "AO-7\n"
|
86
|
+
# tle_string += "1 07530U 74089B 12263.39564296 -.00000027 00000-0 10000-3 0 4844\n"
|
87
|
+
# tle_string += "2 07530 101.4097 256.9929 0012088 96.9320 263.3131 12.53591429731853"
|
88
|
+
|
89
|
+
tle2 = Tle.new(tle_string)
|
90
|
+
|
91
|
+
# pp tle2
|
92
|
+
# puts "Epoch: #{tle2.epoch}"
|
93
|
+
# puts "Now: #{Time.now}"
|
94
|
+
|
95
|
+
diff = ( Time.new.to_i - tle2.epoch.to_i ) / 60.0
|
96
|
+
|
97
|
+
# puts "Diff: #{diff}"
|
98
|
+
|
99
|
+
# PrintPosVel(tle2);
|
100
|
+
|
101
|
+
#puts "\nExample output:"
|
102
|
+
|
103
|
+
# Example: Define a location on the earth, then determine the look-angle
|
104
|
+
# to the SDP4 satellite defined above.
|
105
|
+
|
106
|
+
# Create an orbit object using the SDP4 TLE object.
|
107
|
+
orbitSDP4 = Orbit.new(tle2)
|
108
|
+
|
109
|
+
# pp orbitSDP4
|
110
|
+
|
111
|
+
# Get the location of the satellite from the Orbit object. The
|
112
|
+
# earth-centered inertial information is placed into eciSDP4.
|
113
|
+
# Here we ask for the location of the satellite 90 minutes after
|
114
|
+
# the TLE epoch.
|
115
|
+
eciSDP4 = orbitSDP4.get_position( diff )
|
116
|
+
|
117
|
+
eciGeo = eciSDP4.to_geo
|
118
|
+
#pp eciSDP4
|
119
|
+
|
120
|
+
sat_lat = OrbitGlobals.rad_to_deg( eciGeo.latitude_rad )
|
121
|
+
sat_lon = OrbitGlobals.rad_to_deg( eciGeo.longitude_rad )
|
122
|
+
sat_alt = eciGeo.altitude
|
123
|
+
|
124
|
+
if sat_lon > 180
|
125
|
+
sat_lon = 360 - sat_lon
|
126
|
+
sat_lon *= -1
|
127
|
+
end
|
128
|
+
|
129
|
+
puts "Sat Lat: #{sat_lat }"
|
130
|
+
puts "Sat Lon: #{sat_lon}"
|
131
|
+
puts "Sat Ele: #{sat_alt}"
|
132
|
+
|
133
|
+
# Now create a site object. Site objects represent a location on the
|
134
|
+
# surface of the earth. Here we arbitrarily select a point on the
|
135
|
+
# equator.
|
136
|
+
site_me = Site.new(33.5, -112.05, 380) # 0.00 N, 100.00 W, 0 km altitude
|
137
|
+
|
138
|
+
# pp site_me.get_position( eciSDP4.date )
|
139
|
+
|
140
|
+
# Now get the "look angle" from the site to the satellite.
|
141
|
+
# Note that the ECI object "eciSDP4" has a time associated
|
142
|
+
# with the coordinates it contains; this is the time at which
|
143
|
+
# the look angle is valid.
|
144
|
+
topoLook = site_me.get_look_angle(eciSDP4)
|
145
|
+
|
146
|
+
# pp topoLook
|
147
|
+
|
148
|
+
# Print out the results. Note that the Azimuth and Elevation are
|
149
|
+
# stored in the CoordTopo object as radians. Here we convert
|
150
|
+
# to degrees using Rad2Deg()
|
151
|
+
|
152
|
+
puts "AZ: #{OrbitGlobals.rad_to_deg(topoLook.azimuth).to_f} EL: #{OrbitGlobals.rad_to_deg(topoLook.elevation).to_f}"
|
data/lib/orbit/eci.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
module Orbit
|
2
|
+
class Eci
|
3
|
+
attr_accessor :m_Position
|
4
|
+
attr_accessor :m_Velocity
|
5
|
+
attr_accessor :m_Date
|
6
|
+
|
7
|
+
def self.new_with_pos_vel_gmt(pos, vel, gmt)
|
8
|
+
# puts "new_with_pos_vel_gmt #{pos}, #{vel}, #{gmt}"
|
9
|
+
|
10
|
+
eci = self.new
|
11
|
+
|
12
|
+
eci.m_Position = pos
|
13
|
+
eci.m_Velocity = vel
|
14
|
+
eci.m_Date = gmt
|
15
|
+
|
16
|
+
eci
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize( geo = nil, date = nil )
|
20
|
+
if !geo.nil? && !date.nil?
|
21
|
+
setup( geo, date )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup( geo, date )
|
26
|
+
# puts "Eci.setup( geo, #{date} )"
|
27
|
+
mfactor = OrbitGlobals::TWO_PI * (OrbitGlobals::OMEGAE / OrbitGlobals::SEC_PER_DAY)
|
28
|
+
lat = geo.latitude_rad
|
29
|
+
lon = geo.longitude_rad
|
30
|
+
alt = geo.altitude
|
31
|
+
|
32
|
+
# Calculate Local Mean Sidereal Time (theta)
|
33
|
+
theta = OrbitGlobals.time_to_lmst( date, lon )
|
34
|
+
c = 1.0 / Math.sqrt(1.0 + OrbitGlobals::F * (OrbitGlobals::F - 2.0) * OrbitGlobals::sqr(Math.sin(lat)))
|
35
|
+
s = ((1.0 - OrbitGlobals::F) ** 2 ) * c
|
36
|
+
achcp = (OrbitGlobals::XKMPER * c + alt) * Math.cos(lat)
|
37
|
+
|
38
|
+
@m_Date = date
|
39
|
+
@m_Position = Vector.new()
|
40
|
+
|
41
|
+
@m_Position.m_x = achcp * Math.cos(theta) # km
|
42
|
+
@m_Position.m_y = achcp * Math.sin(theta) # km
|
43
|
+
@m_Position.m_z = (OrbitGlobals::XKMPER * s + alt) * Math.sin(lat) # km
|
44
|
+
@m_Position.m_w = Math.sqrt(OrbitGlobals::sqr(@m_Position.m_x) +
|
45
|
+
OrbitGlobals::sqr(@m_Position.m_y) +
|
46
|
+
OrbitGlobals::sqr(@m_Position.m_z)) # range, km
|
47
|
+
|
48
|
+
@m_Velocity = Vector.new()
|
49
|
+
|
50
|
+
@m_Velocity.m_x = -mfactor * @m_Position.m_y # km / sec
|
51
|
+
@m_Velocity.m_y = mfactor * @m_Position.m_x
|
52
|
+
@m_Velocity.m_z = 0.0
|
53
|
+
@m_Velocity.m_w = Math.sqrt(OrbitGlobals::sqr(@m_Velocity.m_x) + # range rate km/sec^2
|
54
|
+
OrbitGlobals::sqr(@m_Velocity.m_y))
|
55
|
+
end
|
56
|
+
|
57
|
+
#endregion
|
58
|
+
|
59
|
+
#region Properties
|
60
|
+
|
61
|
+
def position
|
62
|
+
@m_Position
|
63
|
+
end
|
64
|
+
|
65
|
+
def velocity
|
66
|
+
@m_Velocity
|
67
|
+
end
|
68
|
+
|
69
|
+
def date
|
70
|
+
@m_Date
|
71
|
+
end
|
72
|
+
|
73
|
+
#endregion
|
74
|
+
|
75
|
+
# #####################################/
|
76
|
+
# Return the corresponding geodetic position (based on the current ECI
|
77
|
+
# coordinates/Julian date).
|
78
|
+
# Assumes the earth is an oblate spheroid as defined in WGS '72.
|
79
|
+
# Reference: The 1992 Astronomical Almanac, page K12.
|
80
|
+
# Reference: www.celestrak.com (Dr. TS Kelso)
|
81
|
+
def to_geo
|
82
|
+
# puts "to_geo"
|
83
|
+
theta = OrbitGlobals::actan(@m_Position.m_y, @m_Position.m_x)
|
84
|
+
# puts "theta: #{theta}"
|
85
|
+
# puts "m_Date: #{@m_Date}"
|
86
|
+
lon = (theta - OrbitGlobals.time_to_gmst( @m_Date )) % OrbitGlobals::TWO_PI
|
87
|
+
|
88
|
+
if (lon < 0.0)
|
89
|
+
lon += OrbitGlobals::TWO_PI # "wrap" negative modulo
|
90
|
+
end
|
91
|
+
|
92
|
+
r = Math.sqrt(OrbitGlobals.sqr(@m_Position.m_x) + OrbitGlobals.sqr(@m_Position.m_y))
|
93
|
+
e2 = OrbitGlobals::F * (2.0 - OrbitGlobals::F)
|
94
|
+
lat = OrbitGlobals.actan(@m_Position.m_z, r)
|
95
|
+
|
96
|
+
delta = 1.0e-07
|
97
|
+
phi = nil
|
98
|
+
c = nil
|
99
|
+
|
100
|
+
begin
|
101
|
+
phi = lat
|
102
|
+
c = 1.0 / Math.sqrt(1.0 - e2 * OrbitGlobals::sqr(Math.sin(phi)))
|
103
|
+
lat = OrbitGlobals::actan(@m_Position.m_z + OrbitGlobals::XKMPER * c * e2 * Math.sin(phi), r)
|
104
|
+
end while ((lat - phi).abs > delta)
|
105
|
+
|
106
|
+
alt = r / Math.cos(lat) - OrbitGlobals::XKMPER * c
|
107
|
+
|
108
|
+
return GeocentricCoordinates.new(lat, lon, alt) # radians, radians, kilometers
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
#/ <summary>
|
113
|
+
#/ Scale the position vector by the given scaling factor.
|
114
|
+
#/ </summary>
|
115
|
+
#/ <param name="factor">The scaling factor.</param>
|
116
|
+
def scale_pos_vector(factor)
|
117
|
+
@m_Position.mul(factor)
|
118
|
+
end
|
119
|
+
|
120
|
+
#/ <summary>
|
121
|
+
#/ Scales the velocity vector by the given scaling factor.
|
122
|
+
#/ </summary>
|
123
|
+
#/ <param name="factor">The scaling factor.</param>
|
124
|
+
def scale_vel_vector(factor)
|
125
|
+
@m_Velocity.mul(factor)
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Orbit
|
2
|
+
class GeocentricCoordinates
|
3
|
+
attr_accessor :latitude_rad
|
4
|
+
attr_accessor :longitude_rad
|
5
|
+
attr_accessor :altitude
|
6
|
+
|
7
|
+
def initialize( lat = nil, lon = nil, alt = 0 )
|
8
|
+
@latitude_rad = lat
|
9
|
+
@longitude_rad = lon
|
10
|
+
@altitude = alt
|
11
|
+
end
|
12
|
+
|
13
|
+
def latitude
|
14
|
+
OrbitGlobals.rad_to_deg( @latitude_rad )
|
15
|
+
end
|
16
|
+
|
17
|
+
def longitude
|
18
|
+
l = OrbitGlobals.rad_to_deg( @longitude_rad )
|
19
|
+
|
20
|
+
if l > 180
|
21
|
+
l = 360 - l
|
22
|
+
l *= -1
|
23
|
+
end
|
24
|
+
|
25
|
+
l
|
26
|
+
end
|
27
|
+
|
28
|
+
def altitude
|
29
|
+
@altitude * 1000.0 #Convert from km to m
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"Lat: #{latitude}, Lng: #{longitude}, Alt: #{altitude}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/orbit/julian.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
class Julian
|
2
|
+
# EPOCH_JAN0_12H_1900 = 2415020.0 # Dec 31.5 1899 = Dec 31 1899 12h UTC
|
3
|
+
# EPOCH_JAN1_00H_1900 = 2415020.5 # Jan 1.0 1900 = Jan 1 1900 00h UTC
|
4
|
+
# EPOCH_JAN1_12H_1900 = 2415021.0 # Jan 1.5 1900 = Jan 1 1900 12h UTC
|
5
|
+
# EPOCH_JAN1_12H_2000 = 2451545.0 # Jan 1.5 2000 = Jan 1 2000 12h UTC
|
6
|
+
#
|
7
|
+
# @m_Date # Julian date
|
8
|
+
# @m_Year # Year including century
|
9
|
+
# @m_Day # Day of year, 1.0 = Jan 1 00h
|
10
|
+
#
|
11
|
+
# #region Construction
|
12
|
+
#
|
13
|
+
# # ##################################/
|
14
|
+
# # Create a Julian date object from a DateTime object. The time
|
15
|
+
# # contained in the DateTime object is assumed to be UTC.
|
16
|
+
# public Julian(DateTime dt)
|
17
|
+
# {
|
18
|
+
# double day = dt.DayOfYear +
|
19
|
+
# (dt.Hour +
|
20
|
+
# ((dt.Minute +
|
21
|
+
# ((dt.Second + (dt.Millisecond / 1000.0)) / 60.0)) / 60.0)) / 24.0
|
22
|
+
#
|
23
|
+
# Initialize(dt.Year, day)
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# # ##################################/
|
27
|
+
# # Create a Julian date object from a year and day of year.
|
28
|
+
# # The year is given with the century (i.e. 2001).
|
29
|
+
# # The integer part of the day value is the day of year, with 1 meaning
|
30
|
+
# # January 1.
|
31
|
+
# # The fractional part of the day value is the fractional portion of
|
32
|
+
# # the day.
|
33
|
+
# # Examples:
|
34
|
+
# # day = 1.0 Jan 1 00h
|
35
|
+
# # day = 1.5 Jan 1 12h
|
36
|
+
# # day = 2.0 Jan 2 00h
|
37
|
+
# public Julian(int year, double day)
|
38
|
+
# {
|
39
|
+
# Initialize(year, day)
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# #endregion
|
43
|
+
#
|
44
|
+
# #region Properties
|
45
|
+
#
|
46
|
+
# public double Date { get { return @m_Date } }
|
47
|
+
#
|
48
|
+
# public double FromJan1_00h_1900() { return @m_Date - EPOCH_JAN1_00H_1900 }
|
49
|
+
# public double FromJan1_12h_1900() { return @m_Date - EPOCH_JAN1_12H_1900 }
|
50
|
+
# public double FromJan0_12h_1900() { return @m_Date - EPOCH_JAN0_12H_1900 }
|
51
|
+
# public double FromJan1_12h_2000() { return @m_Date - EPOCH_JAN1_12H_2000 }
|
52
|
+
#
|
53
|
+
# #endregion
|
54
|
+
#
|
55
|
+
# # ##################################/
|
56
|
+
# public TimeSpan Diff(Julian date)
|
57
|
+
# {
|
58
|
+
# const double TICKS_PER_DAY = 8.64e11 # 1 tick = 100 nanoseconds
|
59
|
+
# return new TimeSpan((long)((m_Date - date.m_Date) * TICKS_PER_DAY))
|
60
|
+
# }
|
61
|
+
#
|
62
|
+
# # ##################################/
|
63
|
+
# # Initialize the Julian object.
|
64
|
+
# # The first day of the year, Jan 1, is day 1.0. Noon on Jan 1 is
|
65
|
+
# # represented by the day value of 1.5, etc.
|
66
|
+
# protected void Initialize(int year, double day)
|
67
|
+
# {
|
68
|
+
# # Arbitrary years used for error checking
|
69
|
+
# if (year < 1900 || year > 2100)
|
70
|
+
# {
|
71
|
+
# throw new ArgumentOutOfRangeException("year")
|
72
|
+
# }
|
73
|
+
#
|
74
|
+
# # The last day of a leap year is day 366
|
75
|
+
# if (day < 1.0 || day >= 367.0)
|
76
|
+
# {
|
77
|
+
# throw new ArgumentOutOfRangeException("day")
|
78
|
+
# }
|
79
|
+
#
|
80
|
+
# @m_Year = year
|
81
|
+
# @m_Day = day
|
82
|
+
#
|
83
|
+
# # Now calculate Julian date
|
84
|
+
# # Ref: "Astronomical Formulae for Calculators", Jean Meeus, pages 23-25
|
85
|
+
#
|
86
|
+
# year--
|
87
|
+
#
|
88
|
+
# # Centuries are not leap years unless they divide by 400
|
89
|
+
# int A = (year / 100)
|
90
|
+
# int B = 2 - A + (A / 4)
|
91
|
+
#
|
92
|
+
# double NewYears = (int)(365.25 * year) +
|
93
|
+
# (int)(30.6001 * 14) +
|
94
|
+
# 1720994.5 + B
|
95
|
+
#
|
96
|
+
# @m_Date = NewYears + day
|
97
|
+
# }
|
98
|
+
#
|
99
|
+
# # ##################################/
|
100
|
+
# # ToGmst()
|
101
|
+
# # Calculate Greenwich Mean Sidereal Time for the Julian date. The
|
102
|
+
# # return value is the angle, in radians, measuring eastward from the
|
103
|
+
# # Vernal Equinox to the prime meridian. This angle is also referred
|
104
|
+
# # to as "ThetaG" (Theta GMST).
|
105
|
+
# #
|
106
|
+
# # References:
|
107
|
+
# # The 1992 Astronomical Almanac, page B6.
|
108
|
+
# # Explanatory Supplement to the Astronomical Almanac, page 50.
|
109
|
+
# # Orbital Coordinate Systems, Part III, Dr. T.S. Kelso,
|
110
|
+
# # Satellite Times, Nov/Dec 1995
|
111
|
+
# public double ToGmst()
|
112
|
+
# {
|
113
|
+
# double UT = (m_Date + 0.5) % 1.0
|
114
|
+
# double TU = (FromJan1_12h_2000() - UT) / 36525.0
|
115
|
+
#
|
116
|
+
# double GMST = 24110.54841 + TU *
|
117
|
+
# (8640184.812866 + TU * (0.093104 - TU * 6.2e-06))
|
118
|
+
#
|
119
|
+
# GMST = (GMST + Globals.SecPerDay * Globals.OmegaE * UT) % Globals.SecPerDay
|
120
|
+
#
|
121
|
+
# if (GMST < 0.0)
|
122
|
+
# {
|
123
|
+
# GMST += Globals.SecPerDay # "wrap" negative modulo value
|
124
|
+
# }
|
125
|
+
#
|
126
|
+
# return (Globals.TwoPi * (GMST / Globals.SecPerDay))
|
127
|
+
# }
|
128
|
+
#
|
129
|
+
# # ##################################/
|
130
|
+
# # ToLmst()
|
131
|
+
# # Calculate Local Mean Sidereal Time for given longitude (for this date).
|
132
|
+
# # The longitude is assumed to be in radians measured west from Greenwich.
|
133
|
+
# # The return value is the angle, in radians, measuring eastward from the
|
134
|
+
# # Vernal Equinox to the given longitude.
|
135
|
+
# public double ToLmst(double lon)
|
136
|
+
# {
|
137
|
+
# return (ToGmst() + lon) % Globals.TwoPi
|
138
|
+
# }
|
139
|
+
#
|
140
|
+
# # ##################################/
|
141
|
+
# # ToTime()
|
142
|
+
# # Convert to type DateTime. The resulting value is UTC.
|
143
|
+
# public DateTime ToTime()
|
144
|
+
# {
|
145
|
+
# # Jan 1
|
146
|
+
# DateTime dt = new DateTime(m_Year, 1, 1)
|
147
|
+
#
|
148
|
+
# # @m_Day = 1 = Jan1
|
149
|
+
# dt = dt.AddDays(m_Day - 1.0)
|
150
|
+
#
|
151
|
+
# return dt
|
152
|
+
# }
|
153
|
+
end
|