argos-ruby 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/LICENSE +674 -0
- data/README.md +35 -0
- data/argos-ruby.gemspec +21 -0
- data/bin/argos-ruby +137 -0
- data/lib/argos/command.rb +58 -0
- data/lib/argos/diag.rb +316 -0
- data/lib/argos/ds.rb +438 -0
- data/lib/argos/exception.rb +4 -0
- data/lib/argos.rb +142 -0
- data/spec/argos/_diag/990660_A.DIA +2708 -0
- data/spec/argos/_diag/valid_2009-03-02_DB_DIAG.txt +25 -0
- data/spec/argos/_ds/990660_A.DAT +1312 -0
- data/spec/argos/_ds/sensor_mismatch_ds.txt +27 -0
- data/spec/argos/diag_spec.rb +75 -0
- data/spec/argos/ds_spec.rb +117 -0
- data/spec/spec_helper.rb +14 -0
- metadata +82 -0
data/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# argos-ruby
|
|
2
|
+
|
|
3
|
+
A Ruby library for parsing Argos tracking data
|
|
4
|
+
|
|
5
|
+
```argos-ruby``` has been developed to parse [Argos](http://www.argos-system.org)
|
|
6
|
+
satellite tracking data collected at the [Norwegian Polar Institute]
|
|
7
|
+
(http://npolar.no/en) over a 25-year period (!) from 1989 to 2013.
|
|
8
|
+
|
|
9
|
+
Be warned, the Argos file formats have changed over time. No promises are
|
|
10
|
+
made that the library will work outside of Norway :).
|
|
11
|
+
|
|
12
|
+
Currently, the library parses Argos DS/DIAG files dating from 1991
|
|
13
|
+
and onwards.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
Now
|
|
17
|
+
$ git clone https://github.com/npolar/argos-ruby.git
|
|
18
|
+
|
|
19
|
+
Soon
|
|
20
|
+
$ gem install argos-ruby
|
|
21
|
+
|
|
22
|
+
## Command-line usage
|
|
23
|
+
```sh
|
|
24
|
+
$ curl "https://raw.github.com/npolar/argos-ruby/master/spec/argos/_ds/990660_A.DAT" > /tmp/990660_A.DAT
|
|
25
|
+
$ ./bin/argos-ruby /tmp/990660_A.DAT --filter "lambda {|a| a[:program] == 660 }"
|
|
26
|
+
```
|
|
27
|
+
This will output (the lambda filter is of course optional):
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
[{"program":660,"platform":14747,"lines":2,"sensors":32,"satellite":"K","lc":null,"positioned":null,"latitude":null,"longitude":null,"altitude":null,"headers":5,"measured":"1999-12-16T00:46:49Z","identical":1,"sensor_data":["92","128","130","132"],"technology":"argos","type":"ds","filename":"/tmp/990660_A.DAT","source":"3a39e0bd0b944dca4f4fbf17bc0680704cde2994","warn":["missing-position","sensors-count-mismatch"],"parser":"argos-ruby-1.0.0","id":"f2c82a5ca1330b312925949a15ac300d07452a12"}]
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Links
|
|
34
|
+
* [http://api.npolar.no/tracking/?q=&filter-technology=argos](http://api.npolar.no/tracking/?q=&filter-technology=argos)
|
|
35
|
+
* [Argos users manual v1.5](http://www.argos-system.org/files/pmedia/public/r363_9_argos_users_manual-v1.5.pdf) (PDF)
|
data/argos-ruby.gemspec
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# https://github.com/radar/guides/blob/master/gem-development.md
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__)+"/lib/argos")
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "argos-ruby"
|
|
7
|
+
s.version = Argos::VERSION
|
|
8
|
+
s.platform = Gem::Platform::RUBY
|
|
9
|
+
s.authors = ["Espen Egeland", "Conrad Helgeland"]
|
|
10
|
+
s.email = ["data*npolar.no"]
|
|
11
|
+
s.homepage = "http://github.com/npolar/argos-ruby"
|
|
12
|
+
s.summary = %q{Argos satellite tracking data parsers}
|
|
13
|
+
s.description = %q{Parses Argos (http://www.argos-system.org/) DS/DAT and DIAG/DIA files.}
|
|
14
|
+
s.license = "GPL-3.0"
|
|
15
|
+
s.add_development_dependency "rspec"
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
|
+
s.require_paths = ["lib"]
|
|
21
|
+
end
|
data/bin/argos-ruby
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
# argos-ruby /path/argos/ --dest=/path/dest --level=info 2>> /path/argos-json.log
|
|
5
|
+
require_relative "../lib/argos"
|
|
6
|
+
require "optparse"
|
|
7
|
+
require "yaml"
|
|
8
|
+
|
|
9
|
+
param = { format: "json",
|
|
10
|
+
action: "parse",
|
|
11
|
+
level: Logger::WARN,
|
|
12
|
+
dest: nil,
|
|
13
|
+
filter: nil,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
optparser = OptionParser.new(ARGV) do |opts|
|
|
17
|
+
#opts.banner ""
|
|
18
|
+
|
|
19
|
+
opts.on_tail("--version", "-v", "Library version") do
|
|
20
|
+
puts Argos.library_version
|
|
21
|
+
exit
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
opts.on("--action={parse|source}", "-a", "Action") do |action|
|
|
25
|
+
param[:action] = action
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
opts.on("--dest=destination", "-a", "Destination directory") do |dest|
|
|
29
|
+
param[:dest] = dest
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
opts.on("--format=FORMAT", "-f", "Format") do |format|
|
|
33
|
+
param[:format] = format
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
opts.on("--filter=FILTER", "Filter lambda") do |filter|
|
|
37
|
+
param[:filter] = filter
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
opts.on("--level=LEVEL", "-l=LEVEL", "Log level: debug|info|warn|error|fatal") do |level|
|
|
41
|
+
|
|
42
|
+
param[:level] = case level
|
|
43
|
+
when /debug|0/i
|
|
44
|
+
Logger::DEBUG
|
|
45
|
+
when /info|1/i
|
|
46
|
+
Logger::INFO
|
|
47
|
+
when /warn|2/i
|
|
48
|
+
Logger::WARN
|
|
49
|
+
when /error|3/i
|
|
50
|
+
Logger::ERROR
|
|
51
|
+
when /fatal|4/i
|
|
52
|
+
Logger::FATAL
|
|
53
|
+
else
|
|
54
|
+
param[:level]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
optparser.parse!
|
|
60
|
+
glob = ARGV[0]||Dir.pwd
|
|
61
|
+
|
|
62
|
+
begin
|
|
63
|
+
|
|
64
|
+
log = Logger.new(STDERR)
|
|
65
|
+
log.level = param[:level]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if not Argos.argos? glob
|
|
69
|
+
glob = glob.gsub(/\/$/, "")
|
|
70
|
+
if glob != /\*/
|
|
71
|
+
glob += "/**/*"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
log.debug "#{File.realpath(__FILE__)} #{param}"
|
|
76
|
+
bundle = Digest::SHA1.hexdigest(glob+param[:filter].to_s)
|
|
77
|
+
result = []
|
|
78
|
+
|
|
79
|
+
Dir[glob].select {|f|
|
|
80
|
+
Argos.argos? f
|
|
81
|
+
}.map {|filename|
|
|
82
|
+
|
|
83
|
+
argos = Argos.factory(Argos.type(filename))
|
|
84
|
+
argos.filename = filename
|
|
85
|
+
argos.filter = param[:filter]
|
|
86
|
+
argos.log = log
|
|
87
|
+
|
|
88
|
+
case param[:action]
|
|
89
|
+
when "source"
|
|
90
|
+
result << Argos.source(argos).merge(glob: glob, bundle: bundle)
|
|
91
|
+
when "parse"
|
|
92
|
+
arr = argos.parse(filename)
|
|
93
|
+
unless param[:dest].nil?
|
|
94
|
+
jsonfile = "#{param[:dest].gsub(/\$/, "")}/#{argos.source}.json"
|
|
95
|
+
File.open(jsonfile, "w") { |file| file.write(arr.to_json) }
|
|
96
|
+
end
|
|
97
|
+
result += arr
|
|
98
|
+
when "messages"
|
|
99
|
+
argos.parse(filename)
|
|
100
|
+
result += argos.messages
|
|
101
|
+
end
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
ds_count = result.select {|argos| argos[:type] == "ds"}.size
|
|
105
|
+
diag_count = result.select {|argos| argos[:type] == "diag"}.size
|
|
106
|
+
# err count
|
|
107
|
+
# warn count
|
|
108
|
+
|
|
109
|
+
if ["parse", "messages"].include? param[:action]
|
|
110
|
+
log.info "Documents: #{result.size}, ds: #{ds_count}, diag: #{diag_count}, bundle: #{bundle}, glob: #{glob}"
|
|
111
|
+
elsif "source" == param[:action]
|
|
112
|
+
result = result.select {|s| s[:size] > 0 }
|
|
113
|
+
sum_count = result.map {|s| s[:size]}.inject { |sum, c| sum + c }
|
|
114
|
+
result = result.map {|s|
|
|
115
|
+
s[:total] = sum_count
|
|
116
|
+
s
|
|
117
|
+
}
|
|
118
|
+
log.info "Documents (Σcount): #{sum_count}, sources: #{result.size} (ds: #{ds_count}, diag: #{diag_count}), bundle: #{bundle}, glob: #{glob}"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if param[:dest].nil?
|
|
122
|
+
case param[:format]
|
|
123
|
+
when "json"
|
|
124
|
+
puts result.to_json
|
|
125
|
+
when /y(a)?ml/
|
|
126
|
+
puts result.to_yaml
|
|
127
|
+
when /(ruby|rb)/
|
|
128
|
+
puts result
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
exit(0)
|
|
133
|
+
|
|
134
|
+
rescue => e
|
|
135
|
+
Logger.new(STDERR).fatal e
|
|
136
|
+
exit(1)
|
|
137
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require "optparse"
|
|
2
|
+
|
|
3
|
+
module Argos
|
|
4
|
+
class Command
|
|
5
|
+
|
|
6
|
+
attr_accessor :param
|
|
7
|
+
|
|
8
|
+
PARAM_DEFAULT = { format: "json",
|
|
9
|
+
action: "parse",
|
|
10
|
+
level: Logger::WARN,
|
|
11
|
+
dest: nil,
|
|
12
|
+
filter: nil,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@param = PARAM_DEFAULT
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def param(argv=ARGV)
|
|
20
|
+
optparser = OptionParser.new(ARGV) do |opts|
|
|
21
|
+
|
|
22
|
+
opts.on_tail("--version", "-v", "Library version") do
|
|
23
|
+
puts Argos.library_version
|
|
24
|
+
exit
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
opts.on("--action=ACTION", "-a", "Action") do |action|
|
|
28
|
+
param[:action] = action
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
opts.on("--filter=FILTER", "-f", "Filter") do |filter|
|
|
32
|
+
param[:filter] = filter
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
opts.on("--level=LEVEL", "-l=LEVEL", "Log level") do |level|
|
|
36
|
+
|
|
37
|
+
param[:level] = case level
|
|
38
|
+
when /debug|0/i
|
|
39
|
+
Logger::DEBUG
|
|
40
|
+
when /info|1/i
|
|
41
|
+
Logger::INFO
|
|
42
|
+
when /warn|2/i
|
|
43
|
+
Logger::WARN
|
|
44
|
+
when /error|3/i
|
|
45
|
+
Logger::ERROR
|
|
46
|
+
when /fatal|4/i
|
|
47
|
+
Logger::FATAL
|
|
48
|
+
else
|
|
49
|
+
param[:level]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
optparser.parse!
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/argos/diag.rb
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
module Argos
|
|
2
|
+
|
|
3
|
+
# Argos DIAG file parser
|
|
4
|
+
#
|
|
5
|
+
# Usage
|
|
6
|
+
#
|
|
7
|
+
# diag = Argos::Diag.new
|
|
8
|
+
# diag.log = Logger.new(STDERR)
|
|
9
|
+
# puts diag.parse(filename).to_json
|
|
10
|
+
#
|
|
11
|
+
# For information about Argos, see: http://www.argos-system.org
|
|
12
|
+
#
|
|
13
|
+
# @author Espen Egeland
|
|
14
|
+
# @author Conrad Helgeland
|
|
15
|
+
class Diag < Array
|
|
16
|
+
include Argos
|
|
17
|
+
|
|
18
|
+
LOCATION_CLASS = ["3", "2", "1", "0", "A", "B", "Z"]
|
|
19
|
+
|
|
20
|
+
attr_accessor :log, :filename, :programs
|
|
21
|
+
|
|
22
|
+
attr_reader :filename, :filter, :filtername, :sha1, :valid, :filesize
|
|
23
|
+
|
|
24
|
+
START_REGEX = /^\s*\d{5,6}\s+Date : \d{2}.\d{2}.\d{2} \d{2}:\d{2}:\d{2}/
|
|
25
|
+
$start_diag ='^\s*\d{5,6}\s+Date : \d{2}.\d{2}.\d{2} \d{2}:\d{2}:\d{2}'
|
|
26
|
+
|
|
27
|
+
# Diag format 1
|
|
28
|
+
# 02168 Date : 21.06.94 08:43:16 LC : Z IQ : 00
|
|
29
|
+
# Lat1 : ??????? Lon1 : ???????? Lat2 : ??????? Lon2 : ????????
|
|
30
|
+
# Nb mes : 002 Nb mes>-120dB : 000 Best level : -125 dB
|
|
31
|
+
# Pass duration : 113s NOPC : 0
|
|
32
|
+
# Calcul freq : 401 650000.0 Hz Altitude : 0 m
|
|
33
|
+
# 24551 00 137
|
|
34
|
+
#$FORMAT_1 = '\s*\d{5,6} +Date : (0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[012])\.\d{2} ([0-1][0-9]|2[0-3]):([0-5][0-9]:[0-5][0-9]) +LC : (3|2|1|0|A|B|Z) +IQ : *\d{2} *Lat1 : +((\d+\.\d{3}[NS])|\?)+ +Lon1 : +((\d+\.\d{3}[EW])|\?+) +Lat2 : +((\d+\.\d{3}[NS])|\?+) +Lon2 : +((\d+\.\d{3}[EW])|\?+) +Nb mes : (\d{3})? +Nb mes>-120dB : (\d{3})? +Best level : (-\d{3})? *dB +Pass duration : *(\d+|\?+) *s? +NOPC : +([0-4]|\?) +Calcul freq : +\d{3} (\d+\.\d+)? *Hz +Altitude : +(\d+)? m( +(\d{2,5}|\w{2}))*$'
|
|
35
|
+
$FORMAT_1 =' *\d{5,6} +Date : (0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[012])\.\d{2} ([0-1][0-9]|2[0-3]):([0-5][0-9]:[0-5][0-9]) +LC : (3|2|1|0|A|B|Z) +IQ : *\d{2} *Lat1 : +((\d+\.\d{3}[NS])|\?+) +Lon1 : +((\d+\.\d{3}[EW])|\?+) +Lat2 : +((\d+\.\d{3}[NS])|\?)+ +Lon2 : +((\d+\.\d{3}[EW])|\?+) +Nb mes : (\d{3})? +Nb mes>-120dB : (\d{3})? +Best level : (-\d{3})? *dB +Pass duration : *(\d+|\?+) *s? +NOPC : *([0-4]|\?)? +Calcul freq : +\d{3} (\d+\.\d+)? *Hz +Altitude : +(\d+)? m( +.+E[+-]\d+)?( +(\d{2,5}|\w{2}))*'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# 09689 Date : 01.02.90 08:35:35 LC : 0 LI : -7
|
|
39
|
+
# Lat1 : 76.304N Lon1 : 18.925E Lat2 : 75.769N Lon2 : 21.554E
|
|
40
|
+
# Nb mes : 004 Nb mes>-120Db : 000 Best level : -130 Db
|
|
41
|
+
# Pass duration : 426s Dist track : 0
|
|
42
|
+
# Calcul freq : 401 649507.6Khz Altitude : 0 m
|
|
43
|
+
# -.81408E+1 03 70
|
|
44
|
+
$FORMAT_2 = '\s*\d{5,6} +Date : (0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[012])\.\d{2} ([0-1][0-9]|2[0-3]):([0-5][0-9]:[0-5][0-9]) +LC : (3|2|1|0|A|B|Z) +(LI : *\-?\d+)? *Lat1 : +\d+\.\d{3}[NS] +Lon1 : +\d+\.\d{3}[EW] +Lat2 : +\d+\.\d{3}[NS] +Lon2 : +\d+\.\d{3}[EW] +Nb mes : \d{3} +Nb mes>-120(Db|dB) : \d{3} +Best level : -\d{3}? *(Db|dB) +Pass duration : +\d+s +Dist track : +\d+ +Calcul freq : +\d{3} \d+\.\d+ *(Khz|Hz) +Altitude : +\d+ m+(.+E[+-]\d+)*( +(\d{2,5}|\w{2}))*$'
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# 09689 Date : 01.02.90 08:35:35 LC : 0 IQ : 00
|
|
48
|
+
# Lat1 : 76.304N Lon1 : 18.925E Lat2 : 75.769N Lon2 : 21.554E
|
|
49
|
+
# Nb mes : 004 Nb mes>-120Db : 000 Best level : -130 Db
|
|
50
|
+
# Pass duration : 426s NOPC :
|
|
51
|
+
# Calcul freq : 401 649507.6Khz Altitude : 0 m
|
|
52
|
+
# 03 70
|
|
53
|
+
$FORMAT_3 =' *\d{5,6} +Date : (0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[012])\.\d{2} ([0-1][0-9]|2[0-3]):([0-5][0-9]:[0-5][0-9]) +LC : (3|2|1|0|A|B|Z) +IQ : *\d{2} *Lat1 : +((\d+\.\d{3}[NS])|\?+) +Lon1 : +((\d+\.\d{3}[EW])|\?+) +Lat2 : +((\d+\.\d{3}[NS])|\?)+ +Lon2 : +((\d+\.\d{3}[EW])|\?+) +Nb mes : (\d{3})? +Nb mes>-120dB : (\d{3})? +Best level : (-\d{3})? *dB +Pass duration : *(\d+|\?+) *s? +NOPC : +([0-4]|\?) +Calcul freq : +\d{3} (\d+\.\d+)? *Hz +Altitude : +(\d+)? m +.+E[+-]\d+( +(\d{2,5}|\w{2}))*$'
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def initialize (filename = nil)
|
|
57
|
+
@index = 0
|
|
58
|
+
@error_num = 0
|
|
59
|
+
@errors_num =0
|
|
60
|
+
@argos_contacts = Array.new
|
|
61
|
+
@filename = filename
|
|
62
|
+
read_file (filename) unless filename == nil
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def filter?
|
|
67
|
+
not @filter.nil?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def filter=filter
|
|
71
|
+
if filter.respond_to? :call
|
|
72
|
+
@filter = filter
|
|
73
|
+
elsif filter =~ /lambda|Proc/
|
|
74
|
+
@filtername = filter
|
|
75
|
+
@filter = eval(filter)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def get_hash
|
|
80
|
+
@argos_contacts
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def parse(filename=nil)
|
|
84
|
+
if filename.nil?
|
|
85
|
+
filename = @filename
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
self.clear # Needed if you parse multiple times
|
|
89
|
+
@total = linecount = 0
|
|
90
|
+
@valid = false
|
|
91
|
+
|
|
92
|
+
#filename = File.realpath(filename)
|
|
93
|
+
@filename = filename
|
|
94
|
+
if filename.nil? or not File.exists? filename
|
|
95
|
+
raise ArgumentError, "Missing ARGOS DS file: \"#{filename}\""
|
|
96
|
+
end
|
|
97
|
+
@sha1 = Digest::SHA1.file(filename).hexdigest
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
valid_file = false
|
|
101
|
+
|
|
102
|
+
contact = []
|
|
103
|
+
file = File.open(filename)
|
|
104
|
+
@filesize = file.size
|
|
105
|
+
|
|
106
|
+
log.debug "Parsing Argos DIAG file #{filename} sha1:#{sha1} (#{filesize} bytes)"
|
|
107
|
+
if filter?
|
|
108
|
+
log.info "Using filter: #{filter}"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
linecount = 0
|
|
113
|
+
match =0
|
|
114
|
+
startline = 0
|
|
115
|
+
contact =""
|
|
116
|
+
|
|
117
|
+
File.open(filename, :encoding => "iso-8859-1").each do |line|
|
|
118
|
+
line = line.to_s.strip
|
|
119
|
+
linecount+=1
|
|
120
|
+
if line =~ /#{$start_diag}/
|
|
121
|
+
match+=1
|
|
122
|
+
if contact !=""
|
|
123
|
+
check_format(contact.strip, startline)
|
|
124
|
+
end
|
|
125
|
+
contact = line
|
|
126
|
+
startline = linecount
|
|
127
|
+
else
|
|
128
|
+
contact = contact + " " +line
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
check_format(contact.strip, startline)
|
|
132
|
+
|
|
133
|
+
if filter?
|
|
134
|
+
total = self.size
|
|
135
|
+
filtered = self.select{|diag| filter.call(diag)}
|
|
136
|
+
log.info "Selected #{filtered.size}/#{total} Argos DIAG segments sha1:#{sha1} #{filename}"
|
|
137
|
+
self.clear
|
|
138
|
+
|
|
139
|
+
filtered.each do |filtered|
|
|
140
|
+
self << filtered
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
log.info "Parsed #{self.size} Argos DIAG segments sha1:#{sha1} #{filename}"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
self
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def check_format(contact, line_num)
|
|
151
|
+
|
|
152
|
+
if contact =~ /#{$FORMAT_1}/ or contact =~ /#{$FORMAT_2}/ or contact =~ /#{$FORMAT_2}/
|
|
153
|
+
self << create_diag_hash(contact)
|
|
154
|
+
true
|
|
155
|
+
else
|
|
156
|
+
error = "#{__FILE__}#check_format #{filename}:#{line_num} source:#{@sha1} Invalid format:\n" + contact
|
|
157
|
+
log.error error
|
|
158
|
+
false
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#http://www.argos-system.org/files/pmedia/public/r363_9_argos_users_manual-v1.5.pdf p. 48
|
|
164
|
+
#Nb mes : 025 Number of messages received
|
|
165
|
+
#Nb mes>-120 dB: 015 Number of messages received by the satellite at a signal strength greater than -120 decibels
|
|
166
|
+
#Best level : -113 dB Best signal strength, units are dB
|
|
167
|
+
#Pass duration : 900s Time elapsed between the first and last message received by the
|
|
168
|
+
#satellite
|
|
169
|
+
#NOPC = 4 Number Of Plausibility Checks successful (from 0-4)
|
|
170
|
+
#Calcul Freq : 401 650000.3 Calculated frequency
|
|
171
|
+
#Altitude : 213 m Altitude used for location calculation
|
|
172
|
+
def create_diag_hash(contact="")
|
|
173
|
+
platform = contact[/^(\d{5,})/,1]
|
|
174
|
+
location_data = contact[/Date : (\d{2}.\d{2}.\d{2} \d{2}:\d{2}:\d{2})/,1]
|
|
175
|
+
contact_time = convert_date(location_data) unless location_data ==nil
|
|
176
|
+
lc = contact[/LC : (3|2|1|0|A|B|Z)/,1]
|
|
177
|
+
li = contact[/LI : *(\-?\d+)/,1]
|
|
178
|
+
iq= contact[/IQ : *(\d{2})/,1]
|
|
179
|
+
lat1= contact[/Lat1 : +(\d+\.\d{3}[NS]|\?+)/,1]
|
|
180
|
+
lat1 = coordinate_conv(lat1)
|
|
181
|
+
lon1= contact[/Lon1 : +(\d+\.\d{3}[EW]|\?+)/,1]
|
|
182
|
+
lon1 = coordinate_conv(lon1)
|
|
183
|
+
lat2= contact[/Lat2 : +(\d+\.\d{3}[NS]|\?+)/,1]
|
|
184
|
+
lat2 = coordinate_conv(lat2)
|
|
185
|
+
lon2= contact[/Lon2 : +(\d+\.\d{3}[EW]|\?+)/,1]
|
|
186
|
+
lon2 = coordinate_conv(lon2)
|
|
187
|
+
nb= contact[/Nb mes : (\d{3})/,1]
|
|
188
|
+
nb120= contact[/Nb mes>-120(Db|dB) : (\d{3})/,2]
|
|
189
|
+
best_level= contact[/Best level : (-\d{3})/,1]
|
|
190
|
+
pass_duration= contact[/Pass duration : +(\d+|\?)/,1]
|
|
191
|
+
dist_track= contact[/Dist track : +(\d+)/,1]
|
|
192
|
+
nopc= contact[/NOPC : +([0-4]|\?)/,1]
|
|
193
|
+
nopc = nopc =~/\?+/ ? nil : nopc
|
|
194
|
+
nopc.to_i unless nopc == nil
|
|
195
|
+
frequency = contact[/Calcul freq : +(\d{3} \d+\.\d+)/,1]
|
|
196
|
+
if frequency =~ /[ ]/
|
|
197
|
+
frequency = frequency.split(" ").join("").to_f
|
|
198
|
+
end
|
|
199
|
+
altitude= contact[/Altitude : +(\d+)? m/,1]
|
|
200
|
+
altitude = altitude.to_i unless altitude == nil
|
|
201
|
+
|
|
202
|
+
data_start = contact.index(" m ")
|
|
203
|
+
sensor_data = contact[data_start+2,contact.length].split(" ") unless data_start == nil
|
|
204
|
+
|
|
205
|
+
diag = { platform: platform.to_i,
|
|
206
|
+
measured: contact_time,
|
|
207
|
+
lc: lc,
|
|
208
|
+
iq: iq,
|
|
209
|
+
li: li,
|
|
210
|
+
latitude: lat1,
|
|
211
|
+
longitude: lon1,
|
|
212
|
+
latitude2: lat2,
|
|
213
|
+
longitude2: lon2,
|
|
214
|
+
messages: nb.to_i,
|
|
215
|
+
messages_120dB: nb120.to_i,
|
|
216
|
+
best_level: best_level.to_i,
|
|
217
|
+
pass_duration: pass_duration.to_i,
|
|
218
|
+
dist_track: dist_track,
|
|
219
|
+
nopc: nopc.to_i,
|
|
220
|
+
frequency: frequency,
|
|
221
|
+
altitude: altitude,
|
|
222
|
+
sensor_data: sensor_data,
|
|
223
|
+
technology: "argos",
|
|
224
|
+
type: type,
|
|
225
|
+
filename: filename,
|
|
226
|
+
source: "#{sha1}"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
idbase = diag.clone
|
|
230
|
+
idbase.delete :filename
|
|
231
|
+
id = Digest::SHA1.hexdigest(idbase.to_json)
|
|
232
|
+
|
|
233
|
+
diag[:parser] = Argos.library_version
|
|
234
|
+
diag[:id] = id
|
|
235
|
+
diag
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def coordinate_conv (co)
|
|
240
|
+
if co =~ /\?+/
|
|
241
|
+
co = nil
|
|
242
|
+
elsif co =~/N$/ || co =~/E$/
|
|
243
|
+
co=co.chop.to_f
|
|
244
|
+
elsif co =~/S$/ || co =~/W$/
|
|
245
|
+
co = co.chop.to_f
|
|
246
|
+
co = co * -1
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def convert_date(date)
|
|
252
|
+
timestamp = DateTime.strptime(date, '%d.%m.%y %H:%M:%S').iso8601.to_s
|
|
253
|
+
timestamp['+00:00'] = "Z"
|
|
254
|
+
timestamp
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def type
|
|
258
|
+
"diag"
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def messages
|
|
262
|
+
self
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def programs
|
|
266
|
+
@programs ||= []
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def start
|
|
270
|
+
first[:measured]
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def stop
|
|
274
|
+
last[:measured]
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def source
|
|
279
|
+
sha1
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
#52061 Date : 03.10.09 08:41:12 LC : 0 IQ : 58
|
|
287
|
+
# Lat1 : 76.651N Lon1 : 20.930W Lat2 : 76.168N Lon2 : 18.539W
|
|
288
|
+
# Nb mes : 006 Nb mes>-120dB : 000 Best level : -123 dB
|
|
289
|
+
# Pass duration : 441s NOPC : 2
|
|
290
|
+
# Calcul freq : 401 677543.2 Hz Altitude : 0 m
|
|
291
|
+
# 40 47 00 00
|
|
292
|
+
# 00 00 00 240
|
|
293
|
+
# 00 00 00 00
|
|
294
|
+
# 00 00 185
|
|
295
|
+
#52061 Date : 03.10.09 09:47:05 LC : Z IQ : 38
|
|
296
|
+
# Lat1 : 76.998N Lon1 : 22.398W Lat2 : 74.370N Lon2 : 10.000
|
|
297
|
+
# Nb mes : 003 Nb mes>-120dB : 000 Best level : -129 dB
|
|
298
|
+
# Pass duration : 100s NOPC : 0
|
|
299
|
+
# Calcul freq : 401 677501.2 Hz Altitude : 0 m
|
|
300
|
+
# 40 35 00 00
|
|
301
|
+
# 00 00 00 240
|
|
302
|
+
# 00 00 00 00
|
|
303
|
+
# 64 00 197
|
|
304
|
+
#52061 Date : 03.10.09 10:23:35 LC : Z IQ : 00
|
|
305
|
+
# Lat1 : ??????? Lon1 : ???????? Lat2 : ??????? Lon2 : ????????
|
|
306
|
+
# Nb mes : 001 Nb mes>-120dB : 000 Best level : -125 dB
|
|
307
|
+
# Pass duration : ???s NOPC : ?
|
|
308
|
+
# Calcul freq : 401 677531.1 Hz Altitude : 0 m
|
|
309
|
+
# 168 64 30
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
#200910Oct.DIA
|
|
315
|
+
#: Line: 26132 Invalid format:
|
|
316
|
+
#52061 Date : 03.10.09 09:47:05 LC : Z IQ : 38 Lat1 : 76.998N Lon1 : 22.398W Lat2 : 74.370N Lon2 : 10.000 Nb mes : 003 Nb mes>-120dB : 000 Best level : -129 dB Pass duration : 100s NOPC : 0 Calcul freq : 401 677501.2 Hz Altitude : 0 m 40 35 00 00 00 00 00 240 00 00 00 00 64 00 197
|