orbit 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.rbc
2
+ *.sassc
3
+ .sass-cache
4
+ capybara-*.html
5
+ .rspec
6
+ /.bundle
7
+ /vendor/bundle
8
+ /log/*
9
+ /tmp/*
10
+ /db/*.sqlite3
11
+ /public/system/*
12
+ /coverage/
13
+ /spec/tmp/*
14
+ **.orig
15
+ rerun.txt
16
+ pickle-email-*.html
17
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,14 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ orbit (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ orbit!
@@ -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}"
@@ -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
@@ -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}"
@@ -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
@@ -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