atmospheric 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +25 -0
- data/README.adoc +97 -0
- data/lib/atmospheric/isa.rb +350 -0
- data/lib/atmospheric/version.rb +5 -0
- data/lib/atmospheric.rb +9 -0
- data/spec/fixtures/iso-2533-1975-table5.yaml +18297 -0
- data/spec/fixtures/iso-2533-1975-table6.yaml +18307 -0
- data/spec/fixtures/iso-2533-1975-table7.yaml +16265 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 91653cc446f211fbec67bb75c9ca04fb3135e24bb7d1e1e52707e865508285d5
|
4
|
+
data.tar.gz: c7cb3677f1d0d1c896815a6607241a58b2649bc43313efc270ce8d124ddf44e7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f8233e299548737ac029e652c50effc3a94fccc83bf1038295429242f9554da545c0c9abdc8c57638da3abf5e91535ec29d01c9cb3e8d978c4d05411d9b30a6c
|
7
|
+
data.tar.gz: a8c034abf9efec7b006e9be2d22119083f2d46fbacda5b2592e6d0fcc1fd657e9d1894dcb5e0ec0b81ac07268be51baa29ee3d8e8d2c8f31a26bd0adb1b3330e
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
BSD 2-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2018, Ribose
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
20
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
24
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
25
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.adoc
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
= Atmospheric for Ruby (International Standard Atmosphere / ICAO Standard Atmosphere (ISA))
|
2
|
+
|
3
|
+
== Purpose
|
4
|
+
|
5
|
+
This repository provides Ruby code for calculating values defined in the
|
6
|
+
following documents:
|
7
|
+
|
8
|
+
* International Standard Atmosphere (ISA) from ISO 2533:1975
|
9
|
+
* ICAO Standard Atmosphere (ICAO Doc 7488/3, 1994)
|
10
|
+
|
11
|
+
Which are technically identical documents but different in presentation and
|
12
|
+
units (the ICAO document includes `ft` in addition to `m`).
|
13
|
+
|
14
|
+
== Usage
|
15
|
+
|
16
|
+
[source,ruby]
|
17
|
+
----
|
18
|
+
> require 'atmospheric'
|
19
|
+
> instance = Atmospheric::Isa.method_name
|
20
|
+
> # method_name is one of the following
|
21
|
+
----
|
22
|
+
|
23
|
+
The available methods are:
|
24
|
+
|
25
|
+
* `geometric_altitude_from_geopotential(geopotential_altitude)`
|
26
|
+
* `geopotential_altitude_from_geometric(geometric_altitude)`
|
27
|
+
* `temperature_at_layer_from_H(geopotential_altitude)`
|
28
|
+
* `temperature_at_layer_celcius(geopotential_altitude)`
|
29
|
+
* `pressure_from_H_mbar(geopotential_altitude)`
|
30
|
+
* `pressure_from_H_mmhg(geopotential_altitude)`
|
31
|
+
* `density_from_H(geopotential_altitude)`
|
32
|
+
* `gravity_at_geopotential(geopotential_altitude)`
|
33
|
+
* `p_p_n_from_H(geopotential_altitude)`
|
34
|
+
* `rho_rho_n_from_H(geopotential_altitude)`
|
35
|
+
* `root_rho_rho_n_from_H(geopotential_altitude)`
|
36
|
+
* `speed_of_sound_from_H(geopotential_altitude)`
|
37
|
+
* `dynamic_viscosity_from_H(geopotential_altitude)`
|
38
|
+
* `kinematic_viscosity_from_H(geopotential_altitude)`
|
39
|
+
* `thermal_conductivity_from_H(geopotential_altitude)`
|
40
|
+
* `pressure_scale_height_from_H(geopotential_altitude)`
|
41
|
+
* `specific_weight_from_H(geopotential_altitude)`
|
42
|
+
* `air_number_density_from_H(geopotential_altitude)`
|
43
|
+
* `mean_air_particle_speed_from_H(geopotential_altitude)`
|
44
|
+
* `air_particle_collision_frequency_from_H(geopotential_altitude)`
|
45
|
+
* `mean_free_path_of_air_particles_from_H(geopotential_altitude)`
|
46
|
+
|
47
|
+
|
48
|
+
== Testing
|
49
|
+
|
50
|
+
[source,sh]
|
51
|
+
----
|
52
|
+
$ rspec
|
53
|
+
----
|
54
|
+
|
55
|
+
Tests are encoded in `spec/fixtures/tests.yml` in the following format:
|
56
|
+
|
57
|
+
[source,yml]
|
58
|
+
----
|
59
|
+
- H: -2000.0
|
60
|
+
h: -1999.0
|
61
|
+
TK: 301.15
|
62
|
+
TC: 28.0
|
63
|
+
p_mbar: 1277.74
|
64
|
+
p_mmhg: 958.382
|
65
|
+
rho: 1.47808
|
66
|
+
g: 9.8128
|
67
|
+
p_p_n: 1.26103
|
68
|
+
rho_rho_n: 1.20659
|
69
|
+
root_rho_rho_n: 1.09845
|
70
|
+
a: 347.886
|
71
|
+
mu: 1.8514e-05
|
72
|
+
v: 1.2526e-05
|
73
|
+
lambda: 0.026359
|
74
|
+
H_p: 8809.5
|
75
|
+
gamma: 14.504
|
76
|
+
n: 3.0734e+25
|
77
|
+
v_bar: 469.18
|
78
|
+
omega: 8535100000.0
|
79
|
+
l: 549710000.0
|
80
|
+
----
|
81
|
+
|
82
|
+
Each of these values are associated with a cell in the tables of the source
|
83
|
+
documents.
|
84
|
+
|
85
|
+
The only defining value in a tests is `H` (geopotential altitude).
|
86
|
+
It is used to generate all the other values.
|
87
|
+
|
88
|
+
|
89
|
+
== License
|
90
|
+
|
91
|
+
Copyright Ribose and its respective owners.
|
92
|
+
|
93
|
+
|
94
|
+
== TODO
|
95
|
+
|
96
|
+
* make into module
|
97
|
+
* expose this as a plugin to LutaML / Metanorma YAML2text
|
@@ -0,0 +1,350 @@
|
|
1
|
+
module Atmospheric
|
2
|
+
module Isa
|
3
|
+
# International Standard Atmosphere (ISA) (ISO 2533:1975)
|
4
|
+
# ICAO Standard Atmosphere (ICAO Doc 7488/3, 1994)
|
5
|
+
|
6
|
+
# 2.1 Primary constants and characteristics
|
7
|
+
# Table 1 - Main constants and characteristics adopted for
|
8
|
+
# the calculation of the ISO Standard Atmosphere
|
9
|
+
CONST = {
|
10
|
+
g_n: 9.80665, # m.s-2
|
11
|
+
N_A: 602.257e21, # Avogadro constant, mol-1
|
12
|
+
p_n: 101325, # In Pascal
|
13
|
+
rho_n: 1.225, # rho_n standard air density
|
14
|
+
T_n: 288.15, # T_n standard thermodynamic air temperature at mean sea level
|
15
|
+
R_star: 8.31432, # universal gas constant
|
16
|
+
|
17
|
+
radius: 6356766, # radius of the Earth (m)
|
18
|
+
k: 1.4 # adiabatic index, dimensionless
|
19
|
+
}
|
20
|
+
|
21
|
+
# 2.2 The equation of the static atmosphere and the perfect gas law
|
22
|
+
# Formula (2)
|
23
|
+
# M: air molar mass at sea level, kg.kmol-1
|
24
|
+
# Value given in 2.1 as M: 28.964720
|
25
|
+
CONST[:M] = (CONST[:rho_n] * CONST[:R_star] * CONST[:T_n]) / CONST[:p_n]
|
26
|
+
|
27
|
+
# Formula (3)
|
28
|
+
# R: specific gas constant, J.K-1.kg-1.
|
29
|
+
# Value given in 2.1 as R: 287.05287
|
30
|
+
CONST[:R] = CONST[:R_star] / CONST[:M]
|
31
|
+
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# 2.3 Geopotential and geometric altitides; acceleration of free fall
|
35
|
+
|
36
|
+
# 2.3 Formula (8)
|
37
|
+
# H to h
|
38
|
+
# h(m)
|
39
|
+
def geometric_altitude_from_geopotential(geopotential_alt)
|
40
|
+
CONST[:radius] * geopotential_alt / (CONST[:radius] - geopotential_alt)
|
41
|
+
end
|
42
|
+
|
43
|
+
# 2.3 Formula (9)
|
44
|
+
# h to H
|
45
|
+
# H(m)
|
46
|
+
def geopotential_altitude_from_geometric(geometric_alt)
|
47
|
+
CONST[:radius] * geometric_alt / (CONST[:radius] + geometric_alt)
|
48
|
+
end
|
49
|
+
|
50
|
+
# 2.3 Formula (7)
|
51
|
+
# g(h)
|
52
|
+
def gravity_at_geometric(geometric_alt)
|
53
|
+
temp = CONST[:radius] / (CONST[:radius] + geometric_alt)
|
54
|
+
CONST[:g_n] * temp * temp
|
55
|
+
end
|
56
|
+
|
57
|
+
def gravity_at_geopotential(geopotential_alt)
|
58
|
+
geometric_h = geometric_altitude_from_geopotential(geopotential_alt)
|
59
|
+
gravity_at_geometric(geometric_h)
|
60
|
+
end
|
61
|
+
|
62
|
+
# 2.4 Atmospheric composition and air molar mass
|
63
|
+
|
64
|
+
# 2.5 Physical characteristics of the atmosphere at mean sea level
|
65
|
+
|
66
|
+
# 2.6 Temperature and vertical temperature gradient
|
67
|
+
|
68
|
+
# Formula (11)
|
69
|
+
# T
|
70
|
+
def temperature_at_layer_from_H(geopotential_alt)
|
71
|
+
lower_layer_index = locate_lower_layer(geopotential_alt)
|
72
|
+
lower_layer = TEMPERATURE_LAYERS[lower_layer_index]
|
73
|
+
beta = lower_layer[:B]
|
74
|
+
capital_t_b = lower_layer[:T]
|
75
|
+
capital_h_b = lower_layer[:H]
|
76
|
+
|
77
|
+
capital_t_b + (beta * (geopotential_alt - capital_h_b))
|
78
|
+
end
|
79
|
+
|
80
|
+
def temperature_at_layer_celcius(geopotential_alt)
|
81
|
+
kelvin_to_celsius(temperature_at_layer_from_H(geopotential_alt))
|
82
|
+
end
|
83
|
+
|
84
|
+
def locate_lower_layer(geopotential_alt)
|
85
|
+
# Return first layer if lower than lowest
|
86
|
+
return 0 if geopotential_alt < TEMPERATURE_LAYERS[0][:H]
|
87
|
+
|
88
|
+
# Return second last layer if beyond last layer
|
89
|
+
i = TEMPERATURE_LAYERS.length - 1
|
90
|
+
return i - 1 if geopotential_alt >= TEMPERATURE_LAYERS[i][:H]
|
91
|
+
|
92
|
+
# find last layer with H larger than our H
|
93
|
+
TEMPERATURE_LAYERS.each_with_index do |layer, i|
|
94
|
+
return i if layer[:H] > geopotential_alt
|
95
|
+
end
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
# Table 4 - Temperature and vertical temperature gradients
|
101
|
+
#
|
102
|
+
TEMPERATURE_LAYERS = [
|
103
|
+
# H is Geopotential altitude (base altitude) above mean sea level, m
|
104
|
+
# T is Temperature, K
|
105
|
+
# B is Temperature gradient, "beta", K m^-1
|
106
|
+
|
107
|
+
# This line is from ICAO 7488/3
|
108
|
+
# [H: -5000, T: 320.65, B: -0.0065 ],
|
109
|
+
|
110
|
+
# This line is from ISO 2533:1975
|
111
|
+
{H: -2000, T: 301.15, B: -0.0065 },
|
112
|
+
{H: 0, T: 288.15, B: -0.0065 },
|
113
|
+
{H: 11000, T: 216.65, B: 0 },
|
114
|
+
{H: 20000, T: 216.65, B: 0.001 },
|
115
|
+
{H: 32000, T: 228.65, B: 0.0028 },
|
116
|
+
{H: 47000, T: 270.65, B: 0 },
|
117
|
+
{H: 51000, T: 270.65, B: -0.0028 },
|
118
|
+
{H: 71000, T: 214.65, B: -0.002 },
|
119
|
+
{H: 80000, T: 196.65},
|
120
|
+
]
|
121
|
+
|
122
|
+
|
123
|
+
# 2.7 Pressure
|
124
|
+
|
125
|
+
# Base pressure values given defined `TEMPERATURE_LAYERS` and constants
|
126
|
+
def pressure_layers
|
127
|
+
return @pressure_layers if @pressure_layers
|
128
|
+
|
129
|
+
# assuming TEMPERATURE_LAYERS index 1 base altitude is zero (mean sea level)
|
130
|
+
p = []
|
131
|
+
|
132
|
+
TEMPERATURE_LAYERS.each_with_index do |x, i|
|
133
|
+
last_i = (i == 0) ? 0 : i - 1
|
134
|
+
last_layer = TEMPERATURE_LAYERS[last_i]
|
135
|
+
beta = last_layer[:B]
|
136
|
+
|
137
|
+
if last_layer[:H] <= 0
|
138
|
+
pb = CONST[:p_n]
|
139
|
+
capital_h_b = 0
|
140
|
+
capital_t_b = CONST[:T_n]
|
141
|
+
else
|
142
|
+
pb = p[last_i]
|
143
|
+
capital_h_b = last_layer[:H]
|
144
|
+
capital_t_b = last_layer[:T]
|
145
|
+
end
|
146
|
+
|
147
|
+
current_layer = TEMPERATURE_LAYERS[i]
|
148
|
+
geopotential_alt = current_layer[:H]
|
149
|
+
temp = current_layer[:T]
|
150
|
+
|
151
|
+
p[i] = if beta != 0
|
152
|
+
# Formula (12)
|
153
|
+
pb * (1 + ((beta / capital_t_b) * (geopotential_alt - capital_h_b))) ** (-CONST[:g_n] / (beta * CONST[:R]))
|
154
|
+
else
|
155
|
+
# Formula (13)
|
156
|
+
pb * Math.exp(-(CONST[:g_n] / (CONST[:R] * temp)) * (geopotential_alt - capital_h_b))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
@pressure_layers = p
|
161
|
+
end
|
162
|
+
|
163
|
+
# puts "PRE-CALCULATED PRESSURE LAYERS:"
|
164
|
+
# pp @pressure_layers
|
165
|
+
|
166
|
+
def pa_to_mmhg(pascal)
|
167
|
+
pascal * 0.007500616827
|
168
|
+
end
|
169
|
+
|
170
|
+
def pa_to_mbar(pascal)
|
171
|
+
pascal * 0.01
|
172
|
+
end
|
173
|
+
|
174
|
+
# Pressure for a given geopotential altitude `H` (m) above mean sea level
|
175
|
+
def pressure_from_H(geopotential_alt)
|
176
|
+
i = locate_lower_layer(geopotential_alt)
|
177
|
+
lower_temperature_layer = TEMPERATURE_LAYERS[i]
|
178
|
+
beta = lower_temperature_layer[:B]
|
179
|
+
capital_h_b = lower_temperature_layer[:H]
|
180
|
+
capital_t_b = lower_temperature_layer[:T]
|
181
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
182
|
+
pb = pressure_layers[i]
|
183
|
+
|
184
|
+
if beta != 0
|
185
|
+
# Formula (12)
|
186
|
+
pb * (1 + ((beta / capital_t_b) * (geopotential_alt - capital_h_b))) ** (-CONST[:g_n] / (beta * CONST[:R]))
|
187
|
+
else
|
188
|
+
# Formula (13)
|
189
|
+
pb * Math.exp(-(CONST[:g_n] / (CONST[:R] * temp)) * (geopotential_alt - capital_h_b))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def pressure_from_H_mbar(geopotential_alt)
|
194
|
+
pa_to_mbar(pressure_from_H(geopotential_alt))
|
195
|
+
end
|
196
|
+
|
197
|
+
def pressure_from_H_mmhg(geopotential_alt)
|
198
|
+
pa_to_mmhg(pressure_from_H(geopotential_alt))
|
199
|
+
end
|
200
|
+
|
201
|
+
def p_p_n_from_H(geopotential_alt)
|
202
|
+
pressure_from_H(geopotential_alt) / CONST[:p_n]
|
203
|
+
end
|
204
|
+
|
205
|
+
# 2.8 Density and specific weight
|
206
|
+
|
207
|
+
# Calculate density for a given geopotential altitude `H` (m) above mean sea level
|
208
|
+
# Formula (14)
|
209
|
+
# rho
|
210
|
+
def density_from_H(geopotential_alt)
|
211
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
212
|
+
p = pressure_from_H(geopotential_alt)
|
213
|
+
|
214
|
+
p / (CONST[:R] * temp)
|
215
|
+
end
|
216
|
+
|
217
|
+
def rho_rho_n_from_H(geopotential_alt)
|
218
|
+
density_from_H(geopotential_alt) / CONST[:rho_n]
|
219
|
+
end
|
220
|
+
|
221
|
+
def root_rho_rho_n_from_H(geopotential_alt)
|
222
|
+
Math.sqrt(rho_rho_n_from_H(geopotential_alt))
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
# Specific weight
|
227
|
+
# Formula (15)
|
228
|
+
# gamma
|
229
|
+
def specific_weight_from_H(geopotential_alt)
|
230
|
+
density_from_H(geopotential_alt) * gravity_at_geopotential(geopotential_alt)
|
231
|
+
end
|
232
|
+
|
233
|
+
# 2.9 Pressure scale height
|
234
|
+
# Formula (16)
|
235
|
+
# H_p
|
236
|
+
def pressure_scale_height_from_temp(temp)
|
237
|
+
(CONST[:R] * temp) / CONST[:g_n]
|
238
|
+
end
|
239
|
+
|
240
|
+
def pressure_scale_height_from_H(geopotential_alt)
|
241
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
242
|
+
(CONST[:R] * temp) / gravity_at_geopotential(geopotential_alt)
|
243
|
+
end
|
244
|
+
|
245
|
+
# 2.10 Air number density
|
246
|
+
# Formula (17)
|
247
|
+
# n
|
248
|
+
def air_number_density_from_H(geopotential_alt)
|
249
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
250
|
+
p = pressure_from_H(geopotential_alt)
|
251
|
+
|
252
|
+
CONST[:N_A] * p / (CONST[:R_star] * temp)
|
253
|
+
end
|
254
|
+
|
255
|
+
# 2.11 Mean air-particle speed
|
256
|
+
# Formula (18)
|
257
|
+
# v_bar
|
258
|
+
# CORRECT
|
259
|
+
def mean_air_particle_speed_from_temp(temp)
|
260
|
+
1.595769 * Math.sqrt(CONST[:R] * temp)
|
261
|
+
end
|
262
|
+
|
263
|
+
def mean_air_particle_speed_from_H(geopotential_alt)
|
264
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
265
|
+
mean_air_particle_speed_from_temp(temp)
|
266
|
+
end
|
267
|
+
|
268
|
+
# 2.12 Mean free path of air particles
|
269
|
+
# Formula (19)
|
270
|
+
# l
|
271
|
+
def mean_free_path_of_air_particles_from_H(geopotential_alt)
|
272
|
+
1 / (1.414213562 * 3.141592654 * (0.365e-9 ** 2) * air_number_density_from_H(geopotential_alt))
|
273
|
+
end
|
274
|
+
|
275
|
+
# 2.13 Air-particle collision frequency
|
276
|
+
# Formula (20)
|
277
|
+
# omega
|
278
|
+
def air_particle_collision_frequency_from_temp(n, temp)
|
279
|
+
4 * (0.365e-9 ** 2) * ((3.141592654 / (CONST[:R_star] * CONST[:M])) ** 0.5) * n * CONST[:R_star] * (temp ** 0.5)
|
280
|
+
end
|
281
|
+
|
282
|
+
def air_particle_collision_frequency_from_H(geopotential_alt)
|
283
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
284
|
+
n = air_number_density_from_H(geopotential_alt)
|
285
|
+
air_particle_collision_frequency_from_temp(n, temp)
|
286
|
+
end
|
287
|
+
|
288
|
+
# 2.14 Speed of sound
|
289
|
+
# Formula (21)
|
290
|
+
# a (ms-1)
|
291
|
+
# CORRECT
|
292
|
+
def speed_of_sound_from_temp(temp)
|
293
|
+
# `kappa` (ratio of c_p / c_v) = 1.4 (see 2.14)
|
294
|
+
kappa = 1.4
|
295
|
+
Math.sqrt(kappa * CONST[:R] * temp)
|
296
|
+
end
|
297
|
+
|
298
|
+
def speed_of_sound_from_H(geopotential_alt)
|
299
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
300
|
+
speed_of_sound_from_temp(temp)
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
# 2.15 Dynamic viscosity
|
305
|
+
# Formula (22)
|
306
|
+
# mu (Pa s)
|
307
|
+
def dynamic_viscosity(temp)
|
308
|
+
# Sutherland's empirical constants in the equation for dynamic viscosity
|
309
|
+
capital_b_s = 1.458e-6
|
310
|
+
capital_s = 110.4
|
311
|
+
|
312
|
+
(capital_b_s * (temp ** (1.5))) / (temp + capital_s)
|
313
|
+
end
|
314
|
+
|
315
|
+
def dynamic_viscosity_from_H(geopotential_alt)
|
316
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
317
|
+
dynamic_viscosity(temp)
|
318
|
+
end
|
319
|
+
|
320
|
+
# 2.16 Kinematic viscosity
|
321
|
+
# Formula (23)
|
322
|
+
# v
|
323
|
+
def kinematic_viscosity(temp)
|
324
|
+
dynamic_viscosity(temp) / CONST[:rho_n]
|
325
|
+
end
|
326
|
+
|
327
|
+
def kinematic_viscosity_from_H(geopotential_alt)
|
328
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
329
|
+
dynamic_viscosity(temp) / density_from_H(geopotential_alt)
|
330
|
+
end
|
331
|
+
|
332
|
+
# 2.17 Thermal conductivity
|
333
|
+
# Formula (24)
|
334
|
+
# lambda
|
335
|
+
def thermal_conductivity_from_temp(temp)
|
336
|
+
(2.648151e-3 * (temp ** (1.5))) / (temp + (245.4 * (10 ** (-12.0/temp))))
|
337
|
+
end
|
338
|
+
|
339
|
+
def thermal_conductivity_from_H(geopotential_alt)
|
340
|
+
temp = temperature_at_layer_from_H(geopotential_alt)
|
341
|
+
thermal_conductivity_from_temp(temp)
|
342
|
+
end
|
343
|
+
|
344
|
+
def kelvin_to_celsius(kelvin)
|
345
|
+
kelvin - 273.15
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|