Class: KerbalDyn::Orbit

Inherits:
Object
  • Object
show all
Includes:
Mixin::OptionsProcessor, Mixin::ParameterAttributes
Defined in:
lib/kerbaldyn/orbit.rb

Overview

The primary class for encapsulating an orbit around a primary body. At this time orbits are simplified to only consider the mass of the primary body, thus the orbit of the secondary body is around the center-of-mass of the primary body. This approximation works well for the Kerbal universe.

Constant Summary collapse

BASE_PARAMETERS =

A list of the independent parameters that define an orbit for this class.

[:periapsis, :periapsis_velocity, :inclination, :longitude_of_ascending_node, :argument_of_periapsis, :mean_anomaly, :epoch]
DEFAULT_OPTIONS =

A map of default values for initialization parameters.

BASE_PARAMETERS.inject({}) {|opts,param| opts[param] = 0.0; opts}.merge(:secondary_body => Body::TEST_PARTICLE)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixin::ParameterAttributes

included

Constructor Details

#initialize(primary_body, options = {}) ⇒ Orbit

Create a new orbit.

The first argument should be the Body (usually a Planetoid) that is being orbited.

The second argument is a list of parameters which should include a size and eccentricity specification, and a may include other optional parameters.

To specify an orbit, at least one of the following pairs must be given:

  • periapsis, periapsis_velocity

  • periapsis, apoapsis

  • semimajor_axis, eccentricity

  • radius (assumes circular orbit)

The following additional parameters may be given:

  • inclination

  • longitude_of_ascending_node

  • argument_of_periapsis

  • mean_anomaly

  • epoch



169
170
171
172
173
174
175
176
177
178
# File 'lib/kerbaldyn/orbit.rb', line 169

def initialize(primary_body, options={})
  # Set the primary planetoid
  self.primary_body = primary_body

  # Set the periapsis and periapsis_velocity from the options
  replaced_options = replace_orbital_parameters(options)

  # Default all the base parameters to zero if not given.
  process_options(replaced_options, DEFAULT_OPTIONS)
end

Instance Attribute Details

#primary_bodyObject

The body being orbited (required) Expected to be an instance of Planetoid.



184
185
186
# File 'lib/kerbaldyn/orbit.rb', line 184

def primary_body
  @primary_body
end

#secondary_bodyObject

The body in orbit (optional) Expected to be an instance of Planetoid.



188
189
190
# File 'lib/kerbaldyn/orbit.rb', line 188

def secondary_body
  @secondary_body
end

Class Method Details

.bopObject

:category: Library Methods



95
96
97
# File 'lib/kerbaldyn/orbit.rb', line 95

def self.bop
  return @bop ||= make(__method__)
end

.circular_orbit(primary_body, radius) ⇒ Object

Convenience method for creating a circular orbit about the given body. This is redundant to calling new with the option of :radius.



101
102
103
# File 'lib/kerbaldyn/orbit.rb', line 101

def self.circular_orbit(primary_body, radius)
  return self.new(primary_body, :radius => radius)
end

.circular_orbit_of_period(primary_body, period) ⇒ Object

Convenience method for creating a circular orbit of a given period around a given body.



107
108
109
110
111
# File 'lib/kerbaldyn/orbit.rb', line 107

def self.circular_orbit_of_period(primary_body, period)
  planetoid_angular_velocity = 2.0 * Math::PI / period
  radius = (primary_body.gravitational_parameter / planetoid_angular_velocity**2)**(1.0/3.0)
  return self.circular_orbit(primary_body, radius)
end

.dunaObject

:category: Library Methods



65
66
67
# File 'lib/kerbaldyn/orbit.rb', line 65

def self.duna
  return @duna ||= make(__method__)
end

.escape_orbit(primary_body, periapsis) ⇒ Object

Convenience method for creating an escape orbit around the given body.



119
120
121
122
# File 'lib/kerbaldyn/orbit.rb', line 119

def self.escape_orbit(primary_body, periapsis)
  periapsis_escape_velocity = Math.sqrt(2.0 * primary_body.gravitational_parameter / periapsis)
  return self.new(primary_body, :periapsis => periapsis, :periapsis_velocity => periapsis_escape_velocity)
end

.eveObject

:category: Library Methods



55
56
57
# File 'lib/kerbaldyn/orbit.rb', line 55

def self.eve
  return @eve ||= make(__method__)
end

.from_string(string) ⇒ Object

Given a string, create an orbit for it. The string specification is one of:

planetoid

The orbit for the planetoid around its parent body.

planetoid@numberdesignator

Builds an orbit around the given planetoid with the given radius or altitude in meters. The designator is one of r or a for radius or altitude. Defaults to radius.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/kerbaldyn/orbit.rb', line 129

def self.from_string(string)
  orbit_with_altitude_regex = /^([a-z]+)@([\d]+)([ra]{0,1})$/

  expression = string.to_s.downcase
  case expression
  when /^([a-z]+)$/
    planetoid_method = expression.to_sym
    raise ArgumentError, "Unknown planetoid: #{string}" unless Planetoid.planetoid_methods.include?(planetoid_method)
    self.send(planetoid_method)
  when orbit_with_altitude_regex
    matched, planetoid_name, distance, distance_designator = orbit_with_altitude_regex.match(expression).to_a
    planetoid_method = planetoid_name.to_sym
    raise ArgumentError, "Unknown planetoid: #{planetoid}" unless Planetoid.planetoid_methods.include?(planetoid_method)
    planetoid = Planetoid.send(planetoid_method)
    radius = (distance_designator=='a') ? (distance.to_f + planetoid.radius) : distance.to_f
    self.new(planetoid, :radius => radius)
  else
    raise ArgumentError, "Unknown orbit expression: #{string}"
  end
end

.geostationary_orbit(primary_body) ⇒ Object

Convenience method for creating a geostationary orbit around the given body.



114
115
116
# File 'lib/kerbaldyn/orbit.rb', line 114

def self.geostationary_orbit(primary_body)
  return self.circular_orbit_of_period(primary_body, primary_body.rotational_period)
end

.gillyObject

:category: Library Methods



60
61
62
# File 'lib/kerbaldyn/orbit.rb', line 60

def self.gilly
  return @gilly ||= make(__method__)
end

.ikeObject

:category: Library Methods



70
71
72
# File 'lib/kerbaldyn/orbit.rb', line 70

def self.ike
  return @ike ||= make(__method__)
end

.joolObject

:category: Library Methods



75
76
77
# File 'lib/kerbaldyn/orbit.rb', line 75

def self.jool
  return @jool ||= make(__method__)
end

.kerbinObject

:category: Library Methods



35
36
37
# File 'lib/kerbaldyn/orbit.rb', line 35

def self.kerbin
  return @kerbin ||= make(__method__)
end

.laytheObject

:category: Library Methods



80
81
82
# File 'lib/kerbaldyn/orbit.rb', line 80

def self.laythe
  return @laythe ||= make(__method__)
end

.make(planet_ref) ⇒ Object

For data read in from data files, this private method DRYs the process.



20
21
22
23
24
25
26
27
28
# File 'lib/kerbaldyn/orbit.rb', line 20

def self.make(planet_ref)
  # Get the data and dup it so we can muck with it.
  data = Data.fetch(:planet_data)[planet_ref][:orbit].dup
  # Get the primary/secondary body refs from it and then lookup to get the values.
  primary_body = Planetoid.send( data.delete(:primary_body) )
  secondary_body = Planetoid.send( data.delete(:secondary_body) )
  # Now construct the object.
  return self.new( primary_body, data.merge(:secondary_body => secondary_body) ).freeze
end

.minmusObject

:category: Library Methods



45
46
47
# File 'lib/kerbaldyn/orbit.rb', line 45

def self.minmus
  return @minmus ||= make(__method__)
end

.mohoObject

:category: Library Methods



50
51
52
# File 'lib/kerbaldyn/orbit.rb', line 50

def self.moho
  return @moho ||= make(__method__)
end

.munObject

:category: Library Methods



40
41
42
# File 'lib/kerbaldyn/orbit.rb', line 40

def self.mun
  return @mun ||= make(__method__)
end

.tyloObject

:category: Library Methods



90
91
92
# File 'lib/kerbaldyn/orbit.rb', line 90

def self.tylo
  return @tylo ||= make(__method__)
end

.vallObject

:category: Library Methods



85
86
87
# File 'lib/kerbaldyn/orbit.rb', line 85

def self.vall
  return @vall ||= make(__method__)
end

Instance Method Details

#apoapsisObject

The apoapsis radius, if the eccentricity is less than one.



342
343
344
345
346
347
348
# File 'lib/kerbaldyn/orbit.rb', line 342

def apoapsis
  if self.closed?
    return self.semimajor_axis * (1 + self.eccentricity)
  else
    return nil
  end
end

#apoapsis_velocityObject

The apoapsis velocity, if the eccentricity is less than one.



351
352
353
354
355
356
357
358
359
# File 'lib/kerbaldyn/orbit.rb', line 351

def apoapsis_velocity
  if self.closed?
    e = self.eccentricity
    k = self.gravitational_parameter / self.semimajor_axis
    return Math.sqrt( (1-e)/(1+e) * k )
  else
    return nil
  end
end

#circularizeObject

Instantiates a new orbit with the same period and semimajor axis, zero inclination, and is circular.

This is useful for idealizing orbits for rough calculations. – TODO: Figure out how to translate parameters such as mean anomaly and LAN. ++



368
369
370
371
372
373
374
# File 'lib/kerbaldyn/orbit.rb', line 368

def circularize
  return self.class.new(primary_body, {
    :secondary_body => self.secondary_body,
    :radius => self.semimajor_axis,
    :inclination => 0.0
  })
end

#classification(delta = 0.000000001) ⇒ Object Also known as: kind

Orbit classification, returns one of :subelliptical, :circular, :elliptical, :parabolic, or :hyperbolic.

Because of how floats work, a delta is given for evaluation of “critical” points such as circular and elliptical orbits. The default value is 1e-9, however other values may be given.



231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/kerbaldyn/orbit.rb', line 231

def classification(delta=0.000000001)
  e = self.eccentricity
  if( e.abs < delta )
    return :circular
  elsif( (e-1.0).abs < delta )
    return :parabolic
  elsif( e > 0.0 && e < 1.0 )
    return :elliptical
  elsif( e > 1.0 )
    return :hyperbolic
  elsif( e < 0.0 )
    return :subelliptical
  end
end

#closed?Boolean

Returns true if the orbit is a closed orbit (eccentricity < 1)

Returns:

  • (Boolean)


248
249
250
# File 'lib/kerbaldyn/orbit.rb', line 248

def closed?
  return self.eccentricity < 1.0
end

#eccentricityObject

The orbit eccentricity.



288
289
290
# File 'lib/kerbaldyn/orbit.rb', line 288

def eccentricity
  return (self.periapsis * self.periapsis_velocity**2 / self.gravitational_parameter) - 1
end

#equivalent_gravity_sphere_of_influenceObject

This is yet another sphere of influence definition I came across, from the bottom of Wikipedia. This matched some numbers I got from a data dump, but don’t match empirical data from the conic patching in game.



217
218
219
# File 'lib/kerbaldyn/orbit.rb', line 217

def equivalent_gravity_sphere_of_influence
  return self.periapsis * (self.secondary_body.mass / self.primary_body.mass)**(1.0/3.0)
end

#gravitational_parameterObject

Returns the gravitational parameter for this orbit. Note that this currently is G*M rather than G*(M+m).



259
260
261
# File 'lib/kerbaldyn/orbit.rb', line 259

def gravitational_parameter
  return self.primary_body.gravitational_parameter
end

#hill_sphere_radiusObject

The Hill Sphere radius. This comes from the approximation of L1/L2.

This is NOT the KSP SOI, for it, use kerbal_sphere_of_influence



210
211
212
# File 'lib/kerbaldyn/orbit.rb', line 210

def hill_sphere_radius
  return self.periapsis * (self.secondary_body.mass / (3.0*self.primary_body.mass))**(2.0/3.0)
end

#mean_angular_velocityObject

This is the mean angular velocity (angle change per unit time) for this orbit.



320
321
322
323
324
325
326
# File 'lib/kerbaldyn/orbit.rb', line 320

def mean_angular_velocity
  if self.closed?
    return 2.0 * Math::PI / self.period
  else
    return nil
  end
end

#mean_motionObject

This is the mean angular velocity (angle change per unit time) for this orbit.

This simply calls mean_angular_velocity on self.



331
332
333
# File 'lib/kerbaldyn/orbit.rb', line 331

def mean_motion
  return self.mean_angular_velocity
end

#mean_velocityObject

This is the velocity associated with the mean motion at the semimajor axis, This works out to be the velocity of an object in a circular orbit with the same period.



337
338
339
# File 'lib/kerbaldyn/orbit.rb', line 337

def mean_velocity
  return self.mean_motion * self.semimajor_axis
end

#open?Boolean

Returns false if the orbit is closed.

Returns:

  • (Boolean)


253
254
255
# File 'lib/kerbaldyn/orbit.rb', line 253

def open?
  return !self.closed?
end

#periodObject

The orbital period, if the eccentricity is less than one.



311
312
313
314
315
316
317
# File 'lib/kerbaldyn/orbit.rb', line 311

def period
  if self.closed?
    return 2.0 * Math::PI * Math.sqrt( self.semimajor_axis**3 / self.gravitational_parameter )
  else
    return nil
  end
end

#primary_body_sphere_of_influenceObject

Returns the sphere of influence (SOI) for the primary body in the context of the two-body system.

This is NOT the KSP SOI, for it, use kerbal_sphere_of_influence



194
195
196
# File 'lib/kerbaldyn/orbit.rb', line 194

def primary_body_sphere_of_influence
  return self.semimajor_axis * (self.primary_body.mass / self.secondary_body.mass)**(0.4)
end

#secondary_body_sphere_of_influenceObject Also known as: laplace_sphere_of_influence, sphere_of_influence

Returns the sphere of influence (SOI) for the secondary body in the context of the two-body system.

In 0.17, for Mun, this matches to better than 0.015% error, while the others are way off.



202
203
204
# File 'lib/kerbaldyn/orbit.rb', line 202

def secondary_body_sphere_of_influence
  return self.semimajor_axis * (self.secondary_body.mass / self.primary_body.mass)**(0.4)
end

#semimajor_axisObject

The orbit semimajor-axis.



293
294
295
296
297
298
299
# File 'lib/kerbaldyn/orbit.rb', line 293

def semimajor_axis
  if self.closed?
    return self.periapsis / (1.0 - self.eccentricity)
  else
    return self.periapsis / (self.eccentricity - 1.0)
  end
end

#semiminor_axisObject

The orbit semiminor_axis, if the eccentricity is less than one.



302
303
304
305
306
307
308
# File 'lib/kerbaldyn/orbit.rb', line 302

def semiminor_axis
  if self.closed?
    return self.semimajor_axis * Math.sqrt(1.0 - self.eccentricity**2)
  else
    return nil
  end
end

#specific_angular_momentumObject Also known as: angular_momentum

The specific angular momentum for this orbit; this is constant over the entire orbit.



282
283
284
# File 'lib/kerbaldyn/orbit.rb', line 282

def specific_angular_momentum
  return self.periapsis * self.periapsis_velocity
end

#specific_energyObject Also known as: vis_viva_energy

The total specific energyy of the orbit; this is constant over the entire orbit.



275
276
277
# File 'lib/kerbaldyn/orbit.rb', line 275

def specific_energy
  return self.specific_potential_energy(self.periapsis) + self.specific_kinetic_energy(self.periapsis_velocity)
end

#specific_kinetic_energy(v) ⇒ Object

The specific kinetic energy for any given velocity.



269
270
271
# File 'lib/kerbaldyn/orbit.rb', line 269

def specific_kinetic_energy(v)
  return 0.5 * v**2
end

#specific_potential_energy(r) ⇒ Object

The specific potential energy for any given orbit radius.



264
265
266
# File 'lib/kerbaldyn/orbit.rb', line 264

def specific_potential_energy(r)
  return -self.gravitational_parameter / r
end