Class: Atmospheric::Isa::Algorithms

Inherits:
Object
  • Object
show all
Defined in:
lib/atmospheric/isa.rb

Overview

International Standard Atmosphere (ISA) (ISO 2533:1975) ICAO Standard Atmosphere (ICAO Doc 7488/3, 1994)

Direct Known Subclasses

HighPrecision, NormalPrecision

Constant Summary collapse

TEMPERATURE_LAYERS =

Table 4 - Temperature and vertical temperature gradients

[
  # H is Geopotential altitude (base altitude) above mean sea level, m
  # T is Temperature, K
  # B is Temperature gradient, "beta", K m^-1

  # This line is from ICAO 7488/3
  # { H: "-5000", T: "320.65", B: "-0.0065" },

  # This line is from ISO 2533:1975
  { H: "-2000", T: "301.15", B: "-0.0065" },
  { H: "0",     T: "288.15", B: "-0.0065" },
  { H: "11000", T: "216.65", B: "0"       },
  { H: "20000", T: "216.65", B: "0.001"   },
  { H: "32000", T: "228.65", B: "0.0028"  },
  { H: "47000", T: "270.65", B: "0"       },
  { H: "51000", T: "270.65", B: "-0.0028" },
  { H: "71000", T: "214.65", B: "-0.002"  },
  { H: "80000", T: "196.65" }
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#constantsObject (readonly)

Returns the value of attribute constants.



14
15
16
# File 'lib/atmospheric/isa.rb', line 14

def constants
  @constants
end

#piObject (readonly)

Returns the value of attribute pi.



14
15
16
# File 'lib/atmospheric/isa.rb', line 14

def pi
  @pi
end

#precisionObject

Returns the value of attribute precision.



13
14
15
# File 'lib/atmospheric/isa.rb', line 13

def precision
  @precision
end

#pressure_layersObject (readonly)

Base pressure values given defined TEMPERATURE_LAYERS and constants



118
119
120
# File 'lib/atmospheric/isa.rb', line 118

def pressure_layers
  @pressure_layers
end

#sqrt2Object (readonly)

Returns the value of attribute sqrt2.



14
15
16
# File 'lib/atmospheric/isa.rb', line 14

def sqrt2
  @sqrt2
end

Instance Method Details

#air_number_density_from_geopotential(geopotential_alt) ⇒ Object

2.10 Air number density Formula (17) n



256
257
258
259
260
261
# File 'lib/atmospheric/isa.rb', line 256

def air_number_density_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  p = pressure_from_geopotential(geopotential_alt)

  @constants[:N_A] * p / (@constants[:R_star] * temp)
end

#air_particle_collision_frequency_from_geopotential(geopotential_alt) ⇒ Object



295
296
297
298
299
# File 'lib/atmospheric/isa.rb', line 295

def air_particle_collision_frequency_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  n = air_number_density_from_geopotential(geopotential_alt)
  air_particle_collision_frequency_from_temp(n, temp)
end

#air_particle_collision_frequency_from_temp(air_number_density, temp) ⇒ Object

2.13 Air-particle collision frequency Formula (20) omega



288
289
290
291
292
293
# File 'lib/atmospheric/isa.rb', line 288

def air_particle_collision_frequency_from_temp(air_number_density, temp)
  # 4 * (3.65e-10**2) * ...
  4 * num("0.133225e-18") *
    ((@pi / (@constants[:R_star] * @constants[:M]))**num("0.5")) *
    air_number_density * @constants[:R_star] * (temp**num("0.5"))
end

#density_from_geopotential(geopotential_alt) ⇒ Object

Density for a given geopotential altitude H (m) above mean sea level Formula (14) rho



218
219
220
221
222
223
# File 'lib/atmospheric/isa.rb', line 218

def density_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  p = pressure_from_geopotential(geopotential_alt)

  p / (@constants[:R] * temp)
end

#dynamic_viscosity(temp) ⇒ Object

2.15 Dynamic viscosity Formula (22) mu (Pa s)



319
320
321
322
323
324
325
# File 'lib/atmospheric/isa.rb', line 319

def dynamic_viscosity(temp)
  # Sutherland's empirical constants in the equation for dynamic viscosity
  capital_b_s = num("1.458e-6")
  capital_s = num("110.4")

  (capital_b_s * (temp**num("1.5"))) / (temp + capital_s)
end

#dynamic_viscosity_from_geopotential(geopotential_alt) ⇒ Object



327
328
329
330
# File 'lib/atmospheric/isa.rb', line 327

def dynamic_viscosity_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  dynamic_viscosity(temp)
end

#geometric_altitude_from_geopotential(geopotential_alt) ⇒ Object

2.3 Formula (8) H to h h(m)



28
29
30
31
# File 'lib/atmospheric/isa.rb', line 28

def geometric_altitude_from_geopotential(geopotential_alt)
  @constants[:radius] * geopotential_alt \
    / (@constants[:radius] - geopotential_alt)
end

#geopotential_altitude_from_geometric(geometric_alt) ⇒ Object

2.3 Formula (9) h to H H(m)



36
37
38
39
# File 'lib/atmospheric/isa.rb', line 36

def geopotential_altitude_from_geometric(geometric_alt)
  @constants[:radius] * geometric_alt \
    / (@constants[:radius] + geometric_alt)
end

#geopotential_altitude_from_pressure_mbar(pressure) ⇒ Object

ADD 1 Formulae used in the calculation of the relationships between geopotential altitude and pressure



364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/atmospheric/isa.rb', line 364

def geopotential_altitude_from_pressure_mbar(pressure)
  if pressure >= pa_to_mbar(pressure_layers[2]) # H <= 11 000 m
    (num("3.731444") - pressure**num("0.1902631")) / num("8.41728e-5")
  elsif pressure >= pa_to_mbar(pressure_layers[3]) # H <= 20 000 m
    (num("3.1080387") - log10(pressure)) / num("6.848325e-5")
  elsif pressure >= pa_to_mbar(pressure_layers[4]) # H <= 32 000 m
    (num("1.2386515") - pressure**num("0.02927125")) \
/ (num("5.085177e-6") * pressure**num("0.02927125"))
  elsif pressure >= pa_to_mbar(pressure_layers[5]) # H <= 47 000 m
    (num("1.9630052") - pressure**num("0.08195949")) \
/ (num("2.013664e-5") * pressure**num("0.08195949"))
  end
end

#geopotential_altitude_from_pressure_mmhg(pressure) ⇒ Object



378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/atmospheric/isa.rb', line 378

def geopotential_altitude_from_pressure_mmhg(pressure)
  if pressure >= pa_to_mmhg(pressure_layers[2]) # H <= 11 000 m
    (num("3.532747") - pressure**num("0.1902631")) / num("7.96906e-5")
  elsif pressure >= pa_to_mmhg(pressure_layers[3]) # H <= 20 000 m
    (num("2.9831357") - log10(pressure)) / num("6.848325e-5")
  elsif pressure >= pa_to_mmhg(pressure_layers[4]) # H <= 32 000 m
    (num("1.2282678") - pressure**num("0.02927125")) \
      / (num("5.085177e-6") * pressure**num("0.02927125"))
  elsif pressure >= pa_to_mmhg(pressure_layers[5]) # H <= 47 000 m
    (num("1.9172753") - pressure**num("0.08195949")) \
      / (num("2.013664e-5") * pressure**num("0.08195949"))
  end
end

#gravity_at_geometric(geometric_alt) ⇒ Object

2.3 Formula (7) g(h)



43
44
45
46
# File 'lib/atmospheric/isa.rb', line 43

def gravity_at_geometric(geometric_alt)
  temp = @constants[:radius] / (@constants[:radius] + geometric_alt)
  @constants[:g_n] * temp * temp
end

#gravity_at_geopotential(geopotential_alt) ⇒ Object



48
49
50
51
# File 'lib/atmospheric/isa.rb', line 48

def gravity_at_geopotential(geopotential_alt)
  geometric_h = geometric_altitude_from_geopotential(geopotential_alt)
  gravity_at_geometric(geometric_h)
end

#kelvin_to_celsius(kelvin) ⇒ Object



357
358
359
# File 'lib/atmospheric/isa.rb', line 357

def kelvin_to_celsius(kelvin)
  kelvin - num("273.15")
end

#kinematic_viscosity(temp) ⇒ Object

2.16 Kinematic viscosity Formula (23) v



335
336
337
# File 'lib/atmospheric/isa.rb', line 335

def kinematic_viscosity(temp)
  dynamic_viscosity(temp) / @constants[:rho_n]
end

#kinematic_viscosity_from_geopotential(geopotential_alt) ⇒ Object



339
340
341
342
# File 'lib/atmospheric/isa.rb', line 339

def kinematic_viscosity_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  dynamic_viscosity(temp) / density_from_geopotential(geopotential_alt)
end

#locate_lower_layer(geopotential_alt) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/atmospheric/isa.rb', line 77

def locate_lower_layer(geopotential_alt)
  # Return first layer if lower than lowest
  return 0 if geopotential_alt < num(TEMPERATURE_LAYERS[0][:H])

  # Return second last layer if beyond last layer
  i = TEMPERATURE_LAYERS.length - 1
  return i - 1 if geopotential_alt >= num(TEMPERATURE_LAYERS[i][:H])

  # find last layer with H smaller than our H
  TEMPERATURE_LAYERS.each_with_index do |layer, ind|
    return ind - 1 if num(layer[:H]) > geopotential_alt
  end

  nil
end

#mbar_to_mmhg(mbar) ⇒ Object



392
393
394
395
396
# File 'lib/atmospheric/isa.rb', line 392

def mbar_to_mmhg(mbar)
  # Convert mbar to Pa, then Pa to mmHg
  pa = mbar / num("0.01") # or mbar * 100
  pa_to_mmhg(pa)
end

#mean_air_particle_speed_from_geopotential(geopotential_alt) ⇒ Object



271
272
273
274
# File 'lib/atmospheric/isa.rb', line 271

def mean_air_particle_speed_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  mean_air_particle_speed_from_temp(temp)
end

#mean_air_particle_speed_from_temp(temp) ⇒ Object

2.11 Mean air-particle speed Formula (18) v_bar CORRECT



267
268
269
# File 'lib/atmospheric/isa.rb', line 267

def mean_air_particle_speed_from_temp(temp)
  num("1.595769") * sqrt(@constants[:R] * temp)
end

#mean_free_path_of_air_particles_from_geopotential(geopotential_alt) ⇒ Object

2.12 Mean free path of air particles Formula (19) l



279
280
281
282
283
# File 'lib/atmospheric/isa.rb', line 279

def mean_free_path_of_air_particles_from_geopotential(geopotential_alt)
  # 1 / (sqrt(2) * Pi * (3.65e-10**2) * air_number_density
  1 / (@sqrt2 * @pi * num("0.133225e-18") * \
    air_number_density_from_geopotential(geopotential_alt))
end

#mmhg_to_mbar(mmhg) ⇒ Object



398
399
400
401
402
# File 'lib/atmospheric/isa.rb', line 398

def mmhg_to_mbar(mmhg)
  # Convert mmHg to Pa, then Pa to mbar
  pa = mmhg / num("0.007500616827")
  pa_to_mbar(pa)
end

#p_p_n_from_geopotential(geopotential_alt) ⇒ Object



209
210
211
# File 'lib/atmospheric/isa.rb', line 209

def p_p_n_from_geopotential(geopotential_alt)
  pressure_from_geopotential(geopotential_alt) / @constants[:p_n]
end

#pa_to_mbar(pascal) ⇒ Object



177
178
179
# File 'lib/atmospheric/isa.rb', line 177

def pa_to_mbar(pascal)
  pascal * num("0.01")
end

#pa_to_mmhg(pascal) ⇒ Object

puts “PRE-CALCULATED PRESSURE LAYERS:” pp @pressure_layers



173
174
175
# File 'lib/atmospheric/isa.rb', line 173

def pa_to_mmhg(pascal)
  pascal * num("0.007500616827")
end

#pressure_formula_beta_nonzero(p_b, beta, temp, height_diff) ⇒ Object

Formula (12)



159
160
161
162
# File 'lib/atmospheric/isa.rb', line 159

def pressure_formula_beta_nonzero(p_b, beta, temp, height_diff)
  p_b * (1 + ((beta / temp) * height_diff)) \
    **(-@constants[:g_n] / (beta * @constants[:R]))
end

#pressure_formula_beta_zero(p_b, temp, height_diff) ⇒ Object

Formula (13)



165
166
167
168
# File 'lib/atmospheric/isa.rb', line 165

def pressure_formula_beta_zero(p_b, temp, height_diff)
  p_b *
    Math.exp(-(@constants[:g_n] / (@constants[:R] * temp)) * height_diff)
end

#pressure_from_geopotential(geopotential_alt) ⇒ Object

Pressure for a given geopotential altitude H (m) above mean sea level



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/atmospheric/isa.rb', line 182

def pressure_from_geopotential(geopotential_alt)
  i = locate_lower_layer(geopotential_alt)
  lower_temperature_layer = TEMPERATURE_LAYERS[i]
  beta = num(lower_temperature_layer[:B])
  capital_h_b = num(lower_temperature_layer[:H])
  capital_t_b = num(lower_temperature_layer[:T])
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  p_b = pressure_layers[i]
  height_diff = geopotential_alt - capital_h_b

  if beta.zero?
    # Formula (13)
    pressure_formula_beta_zero(p_b, temp, height_diff)
  else
    # Formula (12)
    pressure_formula_beta_nonzero(p_b, beta, capital_t_b, height_diff)
  end
end

#pressure_from_geopotential_mbar(geopotential_alt) ⇒ Object



201
202
203
# File 'lib/atmospheric/isa.rb', line 201

def pressure_from_geopotential_mbar(geopotential_alt)
  pa_to_mbar(pressure_from_geopotential(geopotential_alt))
end

#pressure_from_geopotential_mmhg(geopotential_alt) ⇒ Object



205
206
207
# File 'lib/atmospheric/isa.rb', line 205

def pressure_from_geopotential_mmhg(geopotential_alt)
  pa_to_mmhg(pressure_from_geopotential(geopotential_alt))
end

#pressure_scale_height_from_geopotential(geopotential_alt) ⇒ Object



248
249
250
251
# File 'lib/atmospheric/isa.rb', line 248

def pressure_scale_height_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  (@constants[:R] * temp) / gravity_at_geopotential(geopotential_alt)
end

#pressure_scale_height_from_temp(temp) ⇒ Object

2.9 Pressure scale height Formula (16) H_p



244
245
246
# File 'lib/atmospheric/isa.rb', line 244

def pressure_scale_height_from_temp(temp)
  (@constants[:R] * temp) / @constants[:g_n]
end

#rho_rho_n_from_geopotential(geopotential_alt) ⇒ Object



225
226
227
# File 'lib/atmospheric/isa.rb', line 225

def rho_rho_n_from_geopotential(geopotential_alt)
  density_from_geopotential(geopotential_alt) / @constants[:rho_n]
end

#root_rho_rho_n_from_geopotential(geopotential_alt) ⇒ Object



229
230
231
# File 'lib/atmospheric/isa.rb', line 229

def root_rho_rho_n_from_geopotential(geopotential_alt)
  sqrt(rho_rho_n_from_geopotential(geopotential_alt))
end

#set_precision(precision) ⇒ Object



16
17
18
19
20
21
# File 'lib/atmospheric/isa.rb', line 16

def set_precision(precision)
  @precision = precision == :high ? :high : :normal
  remove_instance_variable(:@pressure_layers) \
    if defined?(@pressure_layers)
  make_constants
end

#specific_weight_from_geopotential(geopotential_alt) ⇒ Object

Specific weight Formula (15) gamma



236
237
238
239
# File 'lib/atmospheric/isa.rb', line 236

def specific_weight_from_geopotential(geopotential_alt)
  density_from_geopotential(geopotential_alt) *
    gravity_at_geopotential(geopotential_alt)
end

#speed_of_sound_from_geopotential(geopotential_alt) ⇒ Object



311
312
313
314
# File 'lib/atmospheric/isa.rb', line 311

def speed_of_sound_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  speed_of_sound_from_temp(temp)
end

#speed_of_sound_from_temp(temp) ⇒ Object

2.14 Speed of sound Formula (21) a (ms-1) CORRECT



305
306
307
308
309
# File 'lib/atmospheric/isa.rb', line 305

def speed_of_sound_from_temp(temp)
  # `kappa` (ratio of c_p / c_v) = 1.4 (see 2.14)
  kappa = num("1.4")
  sqrt(kappa * @constants[:R] * temp)
end

#temperature_at_layer_celcius(geopotential_alt) ⇒ Object



71
72
73
74
75
# File 'lib/atmospheric/isa.rb', line 71

def temperature_at_layer_celcius(geopotential_alt)
  kelvin_to_celsius(
    temperature_at_layer_from_geopotential(geopotential_alt)
  )
end

#temperature_at_layer_from_geopotential(geopotential_alt) ⇒ Object

Formula (11) T



61
62
63
64
65
66
67
68
69
# File 'lib/atmospheric/isa.rb', line 61

def temperature_at_layer_from_geopotential(geopotential_alt)
  lower_layer_index = locate_lower_layer(geopotential_alt)
  lower_layer = TEMPERATURE_LAYERS[lower_layer_index]
  beta = num(lower_layer[:B])
  capital_t_b = num(lower_layer[:T])
  capital_h_b = num(lower_layer[:H])

  capital_t_b + (beta * (geopotential_alt - capital_h_b))
end

#thermal_conductivity_from_geopotential(geopotential_alt) ⇒ Object



352
353
354
355
# File 'lib/atmospheric/isa.rb', line 352

def thermal_conductivity_from_geopotential(geopotential_alt)
  temp = temperature_at_layer_from_geopotential(geopotential_alt)
  thermal_conductivity_from_temp(temp)
end

#thermal_conductivity_from_temp(temp) ⇒ Object

2.17 Thermal conductivity Formula (24) lambda



347
348
349
350
# File 'lib/atmospheric/isa.rb', line 347

def thermal_conductivity_from_temp(temp)
  (num("2.648151e-3") * (temp**num("1.5"))) \
    / (temp + (num("245.4") * (num("10")**(num("-12") / temp))))
end