Module: Atmospheric::Isa

Defined in:
lib/atmospheric/isa.rb

Constant Summary collapse

CONST =
constants.freeze
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

Class Method Summary collapse

Class Method Details

.air_number_density_from_geopotential(geopotential_alt) ⇒ Object

2.10 Air number density Formula (17) n



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

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

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

.air_particle_collision_frequency_from_geopotential(geopotential_alt) ⇒ Object



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

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



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

def air_particle_collision_frequency_from_temp(air_number_density, temp)
  4 * (3.65e-10**2) *
    ((3.141592654 / (CONST[:R_star] * CONST[:M]))**0.5) *
    air_number_density * CONST[:R_star] * (temp**0.5)
end

.density_from_geopotential(geopotential_alt) ⇒ Object

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



251
252
253
254
255
256
# File 'lib/atmospheric/isa.rb', line 251

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

  p / (CONST[:R] * temp)
end

.dynamic_viscosity(temp) ⇒ Object

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



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

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

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

.dynamic_viscosity_from_geopotential(geopotential_alt) ⇒ Object



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

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)



56
57
58
# File 'lib/atmospheric/isa.rb', line 56

def geometric_altitude_from_geopotential(geopotential_alt)
  CONST[:radius] * geopotential_alt / (CONST[:radius] - geopotential_alt)
end

.geopotential_altitude_from_geometric(geometric_alt) ⇒ Object

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



63
64
65
# File 'lib/atmospheric/isa.rb', line 63

def geopotential_altitude_from_geometric(geometric_alt)
  CONST[:radius] * geometric_alt / (CONST[: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 rubocop:disable Metrics/AbcSize rubocop:disable Metrics/MethodLength



396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'lib/atmospheric/isa.rb', line 396

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

.geopotential_altitude_from_pressure_mmhg(pressure) ⇒ Object



410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/atmospheric/isa.rb', line 410

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

.gravity_at_geometric(geometric_alt) ⇒ Object

2.3 Formula (7) g(h)



69
70
71
72
# File 'lib/atmospheric/isa.rb', line 69

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

.gravity_at_geopotential(geopotential_alt) ⇒ Object



74
75
76
77
# File 'lib/atmospheric/isa.rb', line 74

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



387
388
389
# File 'lib/atmospheric/isa.rb', line 387

def kelvin_to_celsius(kelvin)
  kelvin - 273.15
end

.kinematic_viscosity(temp) ⇒ Object

2.16 Kinematic viscosity Formula (23) v



366
367
368
# File 'lib/atmospheric/isa.rb', line 366

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

.kinematic_viscosity_from_geopotential(geopotential_alt) ⇒ Object



370
371
372
373
# File 'lib/atmospheric/isa.rb', line 370

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



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/atmospheric/isa.rb', line 103

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

  # Return second last layer if beyond last layer
  i = TEMPERATURE_LAYERS.length - 1
  return i - 1 if geopotential_alt >= 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 layer[:H] > geopotential_alt
  end

  nil
end

.mean_air_particle_speed_from_geopotential(geopotential_alt) ⇒ Object



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

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



300
301
302
# File 'lib/atmospheric/isa.rb', line 300

def mean_air_particle_speed_from_temp(temp)
  1.595769 * Math.sqrt(CONST[: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



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

def mean_free_path_of_air_particles_from_geopotential(geopotential_alt)
  1 / (1.414213562 * 3.141592654 * (3.65e-10**2) * \
    air_number_density_from_geopotential(geopotential_alt))
end

.p_p_n_from_geopotential(geopotential_alt) ⇒ Object



242
243
244
# File 'lib/atmospheric/isa.rb', line 242

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

.pa_to_mbar(pascal) ⇒ Object



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

def pa_to_mbar(pascal)
  pascal * 0.01
end

.pa_to_mmhg(pascal) ⇒ Object

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



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

def pa_to_mmhg(pascal)
  pascal * 0.007500616827
end

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

Formula (12)



191
192
193
194
# File 'lib/atmospheric/isa.rb', line 191

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

.pressure_formula_beta_zero(p_b, temp, height_diff) ⇒ Object

Formula (13)



197
198
199
# File 'lib/atmospheric/isa.rb', line 197

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

.pressure_from_geopotential(geopotential_alt) ⇒ Object

rubocop:disable Metrics/MethodLength Pressure for a given geopotential altitude ‘H` (m) above mean sea level



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/atmospheric/isa.rb', line 214

def pressure_from_geopotential(geopotential_alt)
  i = locate_lower_layer(geopotential_alt)
  lower_temperature_layer = TEMPERATURE_LAYERS[i]
  beta = lower_temperature_layer[:B]
  capital_h_b = lower_temperature_layer[:H]
  capital_t_b = 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 != 0
    # Formula (12)
    pressure_formula_beta_nonzero(p_b, beta, capital_t_b, height_diff)
  else
    # Formula (13)
    pressure_formula_beta_zero(p_b, temp, height_diff)
  end
end

.pressure_from_geopotential_mbar(geopotential_alt) ⇒ Object

rubocop:enable Metrics/MethodLength



234
235
236
# File 'lib/atmospheric/isa.rb', line 234

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

.pressure_from_geopotential_mmhg(geopotential_alt) ⇒ Object



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

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

.pressure_layersObject

Base pressure values given defined ‘TEMPERATURE_LAYERS` and constants rubocop:disable Metrics/AbcSize rubocop:disable Metrics/PerceivedComplexity rubocop:disable Metrics/MethodLength



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/atmospheric/isa.rb', line 147

def pressure_layers
  return @pressure_layers if @pressure_layers

  # assume TEMPERATURE_LAYERS index 1 base altitude is 0 (mean sea level)
  p = []

  TEMPERATURE_LAYERS.each_with_index do |_x, i|
    last_i = i.zero? ? 0 : i - 1
    last_layer = TEMPERATURE_LAYERS[last_i]
    beta = last_layer[:B]

    if last_layer[:H] <= 0
      p_b = CONST[:p_n]
      capital_h_b = 0
      capital_t_b = CONST[:T_n]
    else
      p_b = p[last_i]
      capital_h_b = last_layer[:H]
      capital_t_b = last_layer[:T]
    end

    current_layer = TEMPERATURE_LAYERS[i]
    geopotential_alt = current_layer[:H]
    temp = current_layer[:T]
    height_diff = geopotential_alt - capital_h_b

    p_i = if beta != 0
            # Formula (12)
            pressure_formula_beta_nonzero(p_b, beta, capital_t_b,
                                          height_diff)
          else
            # Formula (13)
            pressure_formula_beta_zero(p_b, temp, height_diff)
          end
    p[i] = p_i
  end

  @pressure_layers = p
end

.pressure_scale_height_from_geopotential(geopotential_alt) ⇒ Object



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

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

.pressure_scale_height_from_temp(temp) ⇒ Object

2.9 Pressure scale height Formula (16) H_p



277
278
279
# File 'lib/atmospheric/isa.rb', line 277

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

.rho_rho_n_from_geopotential(geopotential_alt) ⇒ Object



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

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

.root_rho_rho_n_from_geopotential(geopotential_alt) ⇒ Object



262
263
264
# File 'lib/atmospheric/isa.rb', line 262

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

.specific_weight_from_geopotential(geopotential_alt) ⇒ Object

Specific weight Formula (15) gamma



269
270
271
272
# File 'lib/atmospheric/isa.rb', line 269

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



342
343
344
345
# File 'lib/atmospheric/isa.rb', line 342

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



336
337
338
339
340
# File 'lib/atmospheric/isa.rb', line 336

def speed_of_sound_from_temp(temp)
  # `kappa` (ratio of c_p / c_v) = 1.4 (see 2.14)
  kappa = 1.4
  Math.sqrt(kappa * CONST[:R] * temp)
end

.temperature_at_layer_celcius(geopotential_alt) ⇒ Object



97
98
99
100
101
# File 'lib/atmospheric/isa.rb', line 97

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



87
88
89
90
91
92
93
94
95
# File 'lib/atmospheric/isa.rb', line 87

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

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

.thermal_conductivity_from_geopotential(geopotential_alt) ⇒ Object



382
383
384
385
# File 'lib/atmospheric/isa.rb', line 382

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



378
379
380
# File 'lib/atmospheric/isa.rb', line 378

def thermal_conductivity_from_temp(temp)
  (2.648151e-3 * (temp**1.5)) / (temp + (245.4 * (10**(-12.0 / temp))))
end