simple_metar_parser 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +13 -0
- data/Gemfile.lock +28 -0
- data/LICENSE.txt +165 -0
- data/README.rdoc +55 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/simple_metar_parser.rb +7 -0
- data/lib/simple_metar_parser/metar.rb +120 -0
- data/lib/simple_metar_parser/metar/base.rb +24 -0
- data/lib/simple_metar_parser/metar/clouds.rb +81 -0
- data/lib/simple_metar_parser/metar/metar_city.rb +36 -0
- data/lib/simple_metar_parser/metar/metar_other.rb +27 -0
- data/lib/simple_metar_parser/metar/metar_specials.rb +210 -0
- data/lib/simple_metar_parser/metar/metar_time.rb +40 -0
- data/lib/simple_metar_parser/metar/pressure.rb +52 -0
- data/lib/simple_metar_parser/metar/temperature.rb +101 -0
- data/lib/simple_metar_parser/metar/visibility.rb +47 -0
- data/lib/simple_metar_parser/metar/wind.rb +144 -0
- data/lib/simple_metar_parser/parser.rb +7 -0
- data/lib/simple_metar_parser/tmp/tmp.rb +34 -0
- metadata +114 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module SimpleMetarParser
|
4
|
+
class Temperature < Base
|
5
|
+
|
6
|
+
def reset
|
7
|
+
@temperature = nil
|
8
|
+
@dew = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
# Temperature in C
|
12
|
+
attr_reader :temperature
|
13
|
+
alias :degrees :temperature
|
14
|
+
|
15
|
+
# Dew temperature
|
16
|
+
attr_reader :dew
|
17
|
+
|
18
|
+
# Relative humidity
|
19
|
+
attr_reader :humidity
|
20
|
+
|
21
|
+
# Wind chill index
|
22
|
+
attr_reader :wind_chill
|
23
|
+
|
24
|
+
# US Wind chill index
|
25
|
+
attr_reader :wind_chill_us
|
26
|
+
|
27
|
+
def decode_split(s)
|
28
|
+
# Temperature in Celsius degrees
|
29
|
+
if s =~ /^(M?)(\d{2})\/(M?)(\d{2})$/
|
30
|
+
if $1 == "M"
|
31
|
+
@temperature = -1.0 * $2.to_f
|
32
|
+
else
|
33
|
+
@temperature = $2.to_f
|
34
|
+
end
|
35
|
+
|
36
|
+
if $3 == "M"
|
37
|
+
@dew = -1.0 * $4.to_f
|
38
|
+
else
|
39
|
+
@dew = $4.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
# shorter version
|
46
|
+
if s =~ /^(M?)(\d{2})\/$/
|
47
|
+
if $1 == "M"
|
48
|
+
@temperature = -1.0 * $2.to_f
|
49
|
+
else
|
50
|
+
@temperature = $2.to_f
|
51
|
+
end
|
52
|
+
|
53
|
+
return
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def post_process
|
58
|
+
calculate_humidity
|
59
|
+
calculate_wind_chill
|
60
|
+
end
|
61
|
+
|
62
|
+
def calculate_humidity
|
63
|
+
# Calculate relative humidity
|
64
|
+
return if self.temperature.nil? or self.dew.nil?
|
65
|
+
|
66
|
+
# http://github.com/brandonh/ruby-metar/blob/master/lib/metar.rb
|
67
|
+
# http://www.faqs.org/faqs/meteorology/temp-dewpoint/
|
68
|
+
|
69
|
+
es0 = 6.11 # hPa
|
70
|
+
t0 = 273.15 # kelvin
|
71
|
+
td = self.dew + t0 # kelvin
|
72
|
+
t = self.temperature + t0 # kelvin
|
73
|
+
lv = 2500000 # joules/kg
|
74
|
+
rv = 461.5 # joules*kelvin/kg
|
75
|
+
e = es0 * Math::exp(lv/rv * (1.0/t0 - 1.0/td))
|
76
|
+
es = es0 * Math::exp(lv/rv * (1.0/t0 - 1.0/t))
|
77
|
+
rh = 100 * e/es
|
78
|
+
|
79
|
+
@humidity = rh.round
|
80
|
+
end
|
81
|
+
|
82
|
+
def calculate_wind_chill
|
83
|
+
return if self.temperature.nil? or self.parent.wind.wind_speed.nil?
|
84
|
+
return if self.temperature > 10 or self.parent.wind.wind_speed_kmh < 4.8
|
85
|
+
|
86
|
+
# http://en.wikipedia.org/wiki/Wind_chill
|
87
|
+
v = self.parent.wind.wind_speed
|
88
|
+
ta = self.temperature
|
89
|
+
|
90
|
+
@wind_chill_us = 13.12 +
|
91
|
+
0.6215 * ta -
|
92
|
+
11.37 * v +
|
93
|
+
0.3965 * ta * v
|
94
|
+
|
95
|
+
@wind_chill = (10.0 * Math.sqrt(v) - v + 10.5)*(33.0 - ta)
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module SimpleMetarParser
|
4
|
+
class Visibility < Base
|
5
|
+
|
6
|
+
# max visibility
|
7
|
+
MAX_VISIBILITY = 10_000
|
8
|
+
|
9
|
+
# If visibility is greater than this it assume it is maximum
|
10
|
+
NEARLY_MAX_VISIBILITY = 9_500
|
11
|
+
|
12
|
+
def reset
|
13
|
+
@visibility = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :visibility
|
17
|
+
|
18
|
+
def decode_split(s)
|
19
|
+
# Visibility in meters
|
20
|
+
|
21
|
+
# Europa
|
22
|
+
if s =~ /^(\d{4})$/
|
23
|
+
@visibility = $1.to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
# US
|
27
|
+
if s =~ /^(\d{1,3})\/?(\d{0,2})SM$/
|
28
|
+
if $2 == ""
|
29
|
+
@visibility = $1.to_i * 1600.0
|
30
|
+
else
|
31
|
+
@visibility = $1.to_f * 1600.0 / $2.to_f
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# constant max value
|
36
|
+
if @visibility.to_i >= NEARLY_MAX_VISIBILITY
|
37
|
+
@visibility = MAX_VISIBILITY
|
38
|
+
end
|
39
|
+
|
40
|
+
if s =~ /^(CAVOK)$/
|
41
|
+
@visibility = MAX_VISIBILITY
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,144 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module SimpleMetarParser
|
4
|
+
class Wind < Base
|
5
|
+
|
6
|
+
def reset
|
7
|
+
@winds = Array.new
|
8
|
+
@winds_variable_directions = Array.new
|
9
|
+
end
|
10
|
+
|
11
|
+
KNOTS_TO_METERS_PER_SECOND = 1.85 / 3.6
|
12
|
+
KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND = 1.0 / 3.6
|
13
|
+
|
14
|
+
def decode_split(s)
|
15
|
+
decode_wind(s)
|
16
|
+
decode_wind_variable(s)
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_process
|
20
|
+
recalculate_winds
|
21
|
+
end
|
22
|
+
|
23
|
+
# Wind parameters in meters per second
|
24
|
+
def decode_wind(s)
|
25
|
+
|
26
|
+
if s =~ /(\d{3})(\d{2})G?(\d{2})?(KT|MPS|KMH)/
|
27
|
+
# different units
|
28
|
+
wind = case $4
|
29
|
+
when "KT" then
|
30
|
+
$2.to_f * KNOTS_TO_METERS_PER_SECOND
|
31
|
+
when "MPS" then
|
32
|
+
$2.to_f
|
33
|
+
when "KMH" then
|
34
|
+
$2.to_f * KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
wind_max = case $4
|
40
|
+
when "KT" then
|
41
|
+
$3.to_f * KNOTS_TO_METERS_PER_SECOND
|
42
|
+
when "MPS" then
|
43
|
+
$3.to_f
|
44
|
+
when "KMH" then
|
45
|
+
$3.to_f * KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND
|
46
|
+
else
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# wind_max is not less than normal wind
|
51
|
+
if wind_max < wind or wind_max.nil?
|
52
|
+
wind_max = wind
|
53
|
+
end
|
54
|
+
|
55
|
+
@winds << {
|
56
|
+
:wind => wind,
|
57
|
+
:wind_max => wind_max,
|
58
|
+
:wind_direction => $1.to_i
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
# variable/unknown direction
|
63
|
+
if s =~ /VRB(\d{2})(KT|MPS|KMH)/
|
64
|
+
wind = case $2
|
65
|
+
when "KT" then
|
66
|
+
$1.to_f * KNOTS_TO_METERS_PER_SECOND
|
67
|
+
when "MPS" then
|
68
|
+
$1.to_f
|
69
|
+
when "KMH" then
|
70
|
+
$1.to_f * KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
@winds << {
|
76
|
+
:wind => wind
|
77
|
+
}
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Variable wind direction
|
83
|
+
def decode_wind_variable(s)
|
84
|
+
if s =~ /(\d{3})V(\d{3})/
|
85
|
+
@winds_variable_directions << {
|
86
|
+
:wind_variable_direction_from => $1.to_i,
|
87
|
+
:wind_variable_direction_to => $2.to_i,
|
88
|
+
:wind_direction => ($1.to_i + $2.to_i) / 2,
|
89
|
+
:wind_variable => true
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Calculate wind parameters, some metar string has multiple winds recorded
|
95
|
+
def recalculate_winds
|
96
|
+
@wind = @winds.collect { |w| w[:wind] }.inject(0) { |b, i| b + i } / @winds.size
|
97
|
+
if @winds.size == 1
|
98
|
+
@wind_direction = @winds.first[:wind_direction]
|
99
|
+
else
|
100
|
+
@wind_direction = nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Wind speed in meters per second
|
105
|
+
attr_reader :wind
|
106
|
+
alias_method :wind_speed, :wind
|
107
|
+
|
108
|
+
# Direction of wind
|
109
|
+
attr_reader :wind_direction
|
110
|
+
|
111
|
+
# Wind speed in knots
|
112
|
+
def wind_speed_knots
|
113
|
+
return self.wind if self.wind.nil?
|
114
|
+
return self.wind / KNOTS_TO_METERS_PER_SECOND
|
115
|
+
end
|
116
|
+
|
117
|
+
# Wind speed in KM/H
|
118
|
+
def wind_speed_kmh
|
119
|
+
return self.wind if self.wind.nil?
|
120
|
+
return self.wind / KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND
|
121
|
+
end
|
122
|
+
|
123
|
+
# Meters per second
|
124
|
+
def mps
|
125
|
+
self.wind
|
126
|
+
end
|
127
|
+
|
128
|
+
# Kilometers per hour
|
129
|
+
def kmh
|
130
|
+
self.wind_speed_kmh
|
131
|
+
end
|
132
|
+
|
133
|
+
# Knots
|
134
|
+
def knots
|
135
|
+
self.wind_speed_knots
|
136
|
+
end
|
137
|
+
|
138
|
+
# Wind direction
|
139
|
+
def direction
|
140
|
+
self.wind_direction
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
# If metar string is valid, processed ok with basic data, and time was correct
|
3
|
+
def valid?
|
4
|
+
if TYPE_ARCHIVED == @type
|
5
|
+
if not @city_metar.nil? and
|
6
|
+
not self.temperature.nil? and
|
7
|
+
not self.wind.nil? and
|
8
|
+
not self.time_from.nil? and
|
9
|
+
self.time_from <= Time.now
|
10
|
+
return true
|
11
|
+
end
|
12
|
+
|
13
|
+
elsif TYPE_FRESH == @type
|
14
|
+
# time should be near now
|
15
|
+
if not @city_metar.nil? and
|
16
|
+
|
17
|
+
self.time_from <= Time.now and
|
18
|
+
self.time_from >= (Time.now - 3*24*3600)
|
19
|
+
return true
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
# Decode runway data. Not yet implemented.
|
30
|
+
def decode_runway(s)
|
31
|
+
# BIAR 130700Z 17003KT 0350 R01/0900V1500U +SN VV001 M04/M04 Q0996
|
32
|
+
# Runway 01, touchdown zone visual range is variable from a minimum of 0900 meters until a maximum of 1500 meters, and increasing
|
33
|
+
# http://heras-gilsanz.com/manuel/METAR-Decoder.html
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_metar_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Aleksander Kwiatkowski
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-26 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &28881540 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.3.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *28881540
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: bundler
|
27
|
+
requirement: &28881060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *28881060
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: jeweler
|
38
|
+
requirement: &28880580 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.6.4
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *28880580
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rcov
|
49
|
+
requirement: &18380860 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *18380860
|
58
|
+
description: Gem for parsing METARs fast and simple.
|
59
|
+
email: bobikx@poczta.fm
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files:
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.rdoc
|
65
|
+
files:
|
66
|
+
- Gemfile
|
67
|
+
- Gemfile.lock
|
68
|
+
- LICENSE.txt
|
69
|
+
- README.rdoc
|
70
|
+
- Rakefile
|
71
|
+
- VERSION
|
72
|
+
- lib/simple_metar_parser.rb
|
73
|
+
- lib/simple_metar_parser/metar.rb
|
74
|
+
- lib/simple_metar_parser/metar/base.rb
|
75
|
+
- lib/simple_metar_parser/metar/clouds.rb
|
76
|
+
- lib/simple_metar_parser/metar/metar_city.rb
|
77
|
+
- lib/simple_metar_parser/metar/metar_other.rb
|
78
|
+
- lib/simple_metar_parser/metar/metar_specials.rb
|
79
|
+
- lib/simple_metar_parser/metar/metar_time.rb
|
80
|
+
- lib/simple_metar_parser/metar/pressure.rb
|
81
|
+
- lib/simple_metar_parser/metar/temperature.rb
|
82
|
+
- lib/simple_metar_parser/metar/visibility.rb
|
83
|
+
- lib/simple_metar_parser/metar/wind.rb
|
84
|
+
- lib/simple_metar_parser/parser.rb
|
85
|
+
- lib/simple_metar_parser/tmp/tmp.rb
|
86
|
+
homepage: http://github.com/akwiatkowski/simple_metar_parser
|
87
|
+
licenses:
|
88
|
+
- LGPLv3
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
hash: 2798011357648341845
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 1.8.15
|
111
|
+
signing_key:
|
112
|
+
specification_version: 3
|
113
|
+
summary: Simple METAR parser
|
114
|
+
test_files: []
|