Class: GPS_PVT::Receiver
- Inherits:
-
Object
- Object
- GPS_PVT::Receiver
- Defined in:
- lib/gps_pvt/receiver.rb,
lib/gps_pvt/receiver/agps.rb,
lib/gps_pvt/receiver/rtcm3.rb,
lib/gps_pvt/receiver/almanac.rb,
lib/gps_pvt/receiver/extension.rb
Constant Summary collapse
- YUMA_ITEMS =
[ [proc{|s| s.to_i}, { :ID => :svid, :Health => :SV_health, :week => :WN, }], [proc{|s| Float(s)}, { :Eccentricity => :e, "Time of Applicability" => [:t_oc, :t_oe], "Orbital Inclination" => :i0, "Rate of Right Ascen" => :dot_Omega0, 'SQRT\(A\)' => :sqrt_A, "Right Ascen at Week" => :Omega0, "Argument of Perigee" => :omega, "Mean Anom" => :M0, "Af0" => :a_f0, "Af1" => :a_f1, }], ].collect{|cnv, key_list| key_list.collect{|k1, k2_list| [/#{k1}[^:]*:/, cnv, *([k2_list].flatten(1).collect{|k2| "#{k2}=".to_sym })] } }.flatten(1)
Instance Attribute Summary collapse
-
#base_station ⇒ Object
Returns the value of attribute base_station.
-
#solver ⇒ Object
Returns the value of attribute solver.
Class Method Summary collapse
Instance Method Summary collapse
- #attach_antex(src) ⇒ Object
- #attach_online_ephemeris(uri_template = [nil]) ⇒ Object
- #attach_rinex_clk(src) ⇒ Object
- #attach_sp3(src) ⇒ Object
- #correct_week_sem_yuma_almanac(src, week_rem = 0) ⇒ Object
- #critical(&b) ⇒ Object
-
#ephemeris(t, sys, prn) ⇒ Object
shortcut to access ephemeris registered in receiver.
- #header ⇒ Object
-
#initialize(options = {}) ⇒ Receiver
constructor
A new instance of Receiver.
- #parse_rinex_nav(src) ⇒ Object
- #parse_rinex_obs(src, &b) ⇒ Object
- #parse_rtcm3(src, opt = {}, &b) ⇒ Object
- #parse_sem_almanac(src) ⇒ Object
- #parse_supl(src, opt = {}, &b) ⇒ Object
- #parse_ubx(ubx_fname, &b) ⇒ Object
- #parse_yuma_almanac(src) ⇒ Object
- #register_ephemeris(t_meas, sys, prn, bcast_data, *options) ⇒ Object
- #run(meas, t_meas, ref_pos = @base_station) ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ Receiver
Returns a new instance of Receiver.
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 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/gps_pvt/receiver.rb', line 152 def initialize( = {}) @solver = GPS::Solver::new @solver. = { :skip_exclusion => true, # default is to skip fault exclusion calculation } @debug = {} @semaphore = Mutex::new solver_opts = [:gps_options, :sbas_options, :glonass_options].collect{|target| @solver.send(target) } solver_opts.each{|opt| # default solver options opt.elevation_mask = 0.0 / 180 * Math::PI # 0 deg (use satellite over horizon) opt.residual_mask = 1E4 # 10 km (without residual filter, practically) } = { :system => [[:GPS, 1..32], [:QZSS, 193..202]], :satellites => (1..32).to_a + (193..202).to_a, # [idx, ...] or [[idx, label], ...] is acceptable :FDE => false, } = .reject{|k, v| def v.to_b; !(self =~ /^(?:false|0|f|off)$/i); end case k when :debug v = v.split(/,/) @debug[v[0].upcase.to_sym] = v[1..-1] next true when :weight case v.to_sym when :elevation # (same as underneath C++ library except for ignoring broadcasted/calculated URA) @solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel| if rel_prop[0] > 0 then elv = Coordinate::ENU::relative_rel( Coordinate::XYZ::new(*rel_prop[4..6]), usr_pos).elevation rel_prop[0] = (Math::sin(elv)/0.8)**2 end rel_prop } next true when :identical # treat each satellite range having same accuracy @solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel| rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1 rel_prop } next true end when :elevation_mask_deg raise "Unknown elevation mask angle: #{v}" unless elv_deg = (Float(v) rescue nil) $stderr.puts "Elevation mask: #{elv_deg} deg" solver_opts.each{|opt| opt.elevation_mask = elv_deg / 180 * Math::PI # 0 deg (use satellite over horizon) } next true when :base_station crd, sys = v.split(/ *, */).collect.with_index{|item, i| case item when /^([\+-]?\d+\.?\d*)([XYZNEDU]?)$/ # ex) meter[X], degree[N] [$1.to_f, ($2 + "XY?"[i])[0]] when /^([\+-]?\d+)_(?:(\d+)_(\d+\.?\d*)|(\d+\.?\d*))([NE])$/ # ex) deg_min_secN [$1.to_f + ($2 || $4).to_f / 60 + ($3 || 0).to_f / 3600, $5] else raise "Unknown coordinate spec.: #{item}" end }.transpose raise "Unknown base station: #{v}" if crd.size != 3 @base_station = case (sys = sys.join.to_sym) when :XYZ, :XY? Coordinate::XYZ::new(*crd) when :NED, :ENU, :NE?, :EN? # :NE? => :NEU, :EN? => :ENU (0..1).each{|i| crd[i] *= (Math::PI / 180)} ([:NED, :NE?].include?(sys) ? Coordinate::LLH::new(crd[0], crd[1], crd[2] * (:NED == sys ? -1 : 1)) : Coordinate::LLH::new(crd[1], crd[0], crd[2])).xyz else raise "Unknown coordinate system: #{sys}" end $stderr.puts "Base station (LLH): #{ llh = @base_station.llh.to_a llh[0..1].collect{|rad| rad / Math::PI * 180} + [llh[2]] }" next true when :with, :without [v].flatten.each{|spec| # array is acceptable sys, svid = case spec when Integer [nil, spec] when /^([a-zA-Z]+)(?::(-?\d+))?$/ [$1.upcase.to_sym, (Integer($2) rescue nil)] when /^-?\d+$/ [nil, $&.to_i] else next false end mode = if svid && (svid < 0) then svid *= -1 (k == :with) ? :exclude : :include else (k == :with) ? :include : :exclude end update_output = proc{|sys_target, prns, labels| unless (i = [:system].index{|sys, range| sys == sys_target}) then i = -1 [:system] << [sys_target, []] else [:system][i][1].reject!{|prn| prns.include?(prn)} end [:satellites].reject!{|prn, label| prns.include?(prn)} if mode == :include then [:system][i][1] += prns [:system][i][1].sort! [:satellites] += (labels ? prns.zip(labels) : prns) [:satellites].sort!{|a, b| [a].flatten[0] <=> [b].flatten[0]} end } check_sys_svid = proc{|sys_target, range_in_sys, offset| next range_in_sys.include?(svid - (offset || 0)) unless sys # svid is specified without system next false unless sys == sys_target next true unless svid # All satellites in a target system (svid == nil) range_in_sys.include?(svid) } if check_sys_svid.call(:GPS, 1..32) then [svid || (1..32).to_a].flatten.each{|prn| @solver..send(mode, prn)} elsif check_sys_svid.call(:SBAS, 120..158) then prns = [svid || (120..158).to_a].flatten update_output.call(:SBAS, prns) prns.each{|prn| @solver..send(mode, prn)} elsif check_sys_svid.call(:QZSS, 193..202) then [svid || (193..202).to_a].flatten.each{|prn| @solver..send(mode, prn)} elsif check_sys_svid.call(:GLONASS, 1..24, 0x100) then prns = [svid || (1..24).to_a].flatten.collect{|i| (i & 0xFF) + 0x100} labels = prns.collect{|prn| "GLONASS:#{prn & 0xFF}"} update_output.call(:GLONASS, prns, labels) prns.each{|prn| @solver..send(mode, prn & 0xFF)} else raise "Unknown satellite: #{spec}" end $stderr.puts "#{mode.capitalize} satellite: #{[sys, svid].compact.join(':')}" } next true when :fault_exclusion @solver. = {:skip_exclusion => !([:FDE] = v.to_b)} next true when :use_signal { :GPS_L2C => proc{@solver..exclude_L2C = false}, }[v.to_sym].call rescue next false next true end false } raise "Unknown receiver options: #{.inspect}" unless .empty? @output = { :pvt => Receiver::pvt_items(), :meas => Receiver::meas_items(), } end |
Instance Attribute Details
#base_station ⇒ Object
Returns the value of attribute base_station.
150 151 152 |
# File 'lib/gps_pvt/receiver.rb', line 150 def base_station @base_station end |
#solver ⇒ Object
Returns the value of attribute solver.
149 150 151 |
# File 'lib/gps_pvt/receiver.rb', line 149 def solver @solver end |
Class Method Details
.make_critical(fname) ⇒ Object
318 319 320 321 322 323 |
# File 'lib/gps_pvt/receiver.rb', line 318 def make_critical(fname) f_orig = instance_method(fname) define_method(fname){|*args, &b| critical{f_orig.bind(self).call(*args, &b)} } end |
.meas_items(opt = {}) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/gps_pvt/receiver.rb', line 123 def self.meas_items(opt = {}) opt = { :satellites => (1..32).to_a, }.merge(opt) keys = [:PSEUDORANGE, :RANGE_RATE, :DOPPLER, :FREQUENCY].collect{|k| GPS::Measurement.const_get("L1_#{k}".to_sym) } [[ opt[:satellites].collect{|prn, label| [:L1_range, :L1_rate].collect{|str| "#{str}(#{label || prn})"} }.flatten, proc{|meas| meas_hash = meas.to_hash opt[:satellites].collect{|prn, label| pr, rate, doppler, freq = keys.collect{|k| meas_hash[prn][k] rescue nil} freq ||= GPS::SpaceNode.L1_Frequency [pr, rate || ((-doppler * GPS::SpaceNode::light_speed / freq) rescue nil)] } } ]] end |
.pvt_items(opt = {}) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/gps_pvt/receiver.rb', line 18 def self.pvt_items(opt = {}) opt = { :system => [[:GPS, 1..32]], :satellites => (1..32).to_a, :FDE => true, }.merge(opt) [[ [:week, :itow_rcv, :year, :month, :mday, :hour, :min, :sec_rcv_UTC], proc{|pvt| [:week, :seconds, :utc].collect{|f| pvt.receiver_time.send(f)}.flatten } ]] + [[ [:receiver_clock_error_meter, :longitude, :latitude, :height, :rel_E, :rel_N, :rel_U], proc{|pvt| next [nil] * 7 unless pvt.position_solved? [ pvt.receiver_error, pvt.llh.lng / Math::PI * 180, pvt.llh.lat / Math::PI * 180, pvt.llh.alt, ] + (pvt.rel_ENU.to_a rescue [nil] * 3) } ]] + [proc{ labels = [:g, :p, :h, :v, :t].collect{|k| "#{k}dop".to_sym} \ + [:h, :v, :t].collect{|k| "#{k}sigma".to_sym} [ labels, proc{|pvt| next [nil] * 8 unless pvt.position_solved? labels.collect{|k| pvt.send(k)} } ] }.call] + [[ [:v_north, :v_east, :v_down, :receiver_clock_error_dot_ms, :vel_sigma], proc{|pvt| next [nil] * 5 unless pvt.velocity_solved? [:north, :east, :down].collect{|k| pvt.velocity.send(k)} \ + [pvt.receiver_error_rate, pvt.vel_sigma] } ]] + [ [:used_satellites, proc{|pvt| pvt.used_satellites}], ] + opt[:system].collect{|sys, range| range = range.kind_of?(Array) ? proc{ # check whether inputs can be converted to Range next nil if range.empty? a, b = range.minmax ((b - a) == (range.length - 1)) ? (a..b) : range }.call : range next nil unless range bit_flip, label = case range when Array [proc{|res, i| res[i] = "1" if i = range.index(i) res }, range.collect{|pen| pen & 0xFF}.reverse.join('+')] when Range base_prn = range.min [proc{|res, i| res[i - base_prn] = "1" if range.include?(i) res }, [:max, :min].collect{|f| range.send(f) & 0xFF}.join('..')] end ["#{sys}_PRN(#{label})", proc{|pvt| pvt.used_satellite_list.inject("0" * range.size, &bit_flip) \ .scan(/.{1,8}/).join('_').reverse }] }.compact + [[ opt[:satellites].collect{|prn, label| [:range_residual, :weight, :azimuth, :elevation, :slopeH, :slopeV].collect{|str| "#{str}(#{label || prn})" } }.flatten, proc{|pvt| next ([nil] * 6 * opt[:satellites].size) unless pvt.position_solved? sats = pvt.used_satellite_list r, w = [:delta_r, :W].collect{|f| pvt.send(f)} opt[:satellites].collect{|prn, label| next ([nil] * 6) unless i2 = sats.index(prn) [r[i2, 0], w[i2, i2]] + [:azimuth, :elevation].collect{|f| pvt.send(f)[prn] / Math::PI * 180 } + [pvt.slopeH[prn], pvt.slopeV[prn]] }.flatten }, ]] + [[ [:wssr, :wssr_sf, :weight_max, :slopeH_max, :slopeH_max_PRN, :slopeH_max_elevation, :slopeV_max, :slopeV_max_PRN, :slopeV_max_elevation], proc{|pvt| next [nil] * 9 unless fd = pvt.fd el_deg = [4, 6].collect{|i| pvt.elevation[fd[i]] / Math::PI * 180} fd[0..4] + [el_deg[0]] + fd[5..6] + [el_deg[1]] } ]] + (opt[:FDE] ? [[ [:wssr_FDE_min, :wssr_FDE_min_PRN, :wssr_FDE_2nd, :wssr_FDE_2nd_PRN], proc{|pvt| [:fde_min, :fde_2nd].collect{|f| info = pvt.send(f) next ([nil] * 2) if (!info) || info.empty? [info[0], info[-3]] }.flatten } ]] : []) end |
Instance Method Details
#attach_antex(src) ⇒ Object
707 708 709 710 711 712 713 |
# File 'lib/gps_pvt/receiver.rb', line 707 def attach_antex(src) fname = Util::get_txt(src) raise "Specify SP3 before ANTEX application!" unless @sp3 applied_items = critical{@sp3.apply_antex(fname)} raise "Format error! (Not ANTEX) #{src}" unless applied_items >= 0 $stderr.puts "SP3 correction with ANTEX file (%s): %d items have been processed."%[src, applied_items] end |
#attach_online_ephemeris(uri_template = [nil]) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/gps_pvt/receiver/extension.rb', line 32 def attach_online_ephemeris(uri_template = [nil]) uri_template = uri_template.collect{|v| if (!v) || (v =~ /^\s*$/) then "ftp://gssc.esa.int/gnss/data/daily/%Y/brdc/BRDC00IGS_R_%Y%j0000_01D_MN.rnx.gz" else v end }.uniq loader = proc{|t_meas| utc = Time::utc(*t_meas.c_tm) uri_template.each{|v| uri = URI::parse(utc.strftime(v)) begin self.parse_rinex_nav(uri) rescue Net::FTPError, Net::HTTPExceptions => e $stderr.puts "Skip to read due to %s (%s)"%[e.inspect.gsub(/[\r\n]/, ' '), uri] end } } run_orig = self.method(:run) eph_list = {} self.define_singleton_method(:run){|meas, t_meas, *args| w_d = [t_meas.week, (t_meas.seconds.to_i / 86400)] eph_list[w_d] ||= loader.call(t_meas) run_orig.call(meas, t_meas, *args) } end |
#attach_rinex_clk(src) ⇒ Object
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
# File 'lib/gps_pvt/receiver.rb', line 715 def attach_rinex_clk(src) fname = Util::get_txt(src) @clk ||= GPS::RINEX_Clock::new read_items = @clk.read(fname) raise "Format error! (Not RINEX clock) #{src}" if read_items < 0 $stderr.puts "Read RINEX clock file (%s): %d items."%[src, read_items] sats = @clk.satellites @clk.class.constants.each{|sys| next unless /^SYS_(?!SYSTEMS)(.*)/ =~ sys.to_s idx, sys_name = [@clk.class.const_get(sys), $1] next unless sats[idx] > 0 next unless critical{@clk.push(@solver, idx)} $stderr.puts "Change clock error source of #{sys_name} to RINEX clock" } end |
#attach_sp3(src) ⇒ Object
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
# File 'lib/gps_pvt/receiver.rb', line 691 def attach_sp3(src) fname = Util::get_txt(src) @sp3 ||= GPS::SP3::new read_items = @sp3.read(fname) raise "Format error! (Not SP3) #{src}" if read_items < 0 $stderr.puts "Read SP3 file (%s): %d items."%[src, read_items] sats = @sp3.satellites @sp3.class.constants.each{|sys| next unless /^SYS_(?!SYSTEMS)(.*)/ =~ sys.to_s idx, sys_name = [@sp3.class.const_get(sys), $1] next unless sats[idx] > 0 next unless critical{@sp3.push(@solver, idx)} $stderr.puts "Change ephemeris source of #{sys_name} to SP3" } end |
#correct_week_sem_yuma_almanac(src, week_rem = 0) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/gps_pvt/receiver/almanac.rb', line 7 def correct_week_sem_yuma_almanac(src, week_rem = 0) t_ref = case src.to_s when /www\.navcen\.uscg\.gov\/.*\/(\d{4})\// # ex) https://www.navcen.uscg.gov/sites/default/files/gps/almanac/20XX/(Sem|Yuma)/003.(al3|alm) GPS_PVT::GPS::Time::new(Time::new($1.to_i).to_a.slice(0, 6).reverse) when /www\.navcen\.uscg\.gov\/.*\/current_(sem|yuma)/ GPS_PVT::GPS::Time::now else raise end q, rem = t_ref.week.divmod(1024) delta = rem - (week_rem % 1024) if delta <= -512 then q -= 1 elsif delta > 512 then q += 1 end q * 1024 + week_rem end |
#critical(&b) ⇒ Object
309 310 311 312 313 314 315 |
# File 'lib/gps_pvt/receiver.rb', line 309 def critical(&b) begin @semaphore.synchronize{b.call} rescue ThreadError # recovery from deadlock b.call end end |
#ephemeris(t, sys, prn) ⇒ Object
shortcut to access ephemeris registered in receiver
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/gps_pvt/receiver/extension.rb', line 9 def ephemeris(t, sys, prn) eph = case sys when :GPS, :QZSS critical{ @solver.gps_space_node.update_all_ephemeris(t) @solver.gps_space_node.ephemeris(prn) } when :SBAS critical{ @solver.sbas_space_node.update_all_ephemeris(t) @solver.sbas_space_node.ephemeris(prn) } when :GLONASS critical{ @solver.glonass_space_node.update_all_ephemeris(t) @solver.glonass_space_node.ephemeris(prn) } else return nil end return (eph.valid?(t) ? eph : nil) end |
#header ⇒ Object
145 146 147 |
# File 'lib/gps_pvt/receiver.rb', line 145 def header (@output[:pvt] + @output[:meas]).transpose[0].flatten.join(',') end |
#parse_rinex_nav(src) ⇒ Object
608 609 610 611 612 613 614 615 616 617 618 619 620 |
# File 'lib/gps_pvt/receiver.rb', line 608 def parse_rinex_nav(src) fname = Util::get_txt(src) items = [ @solver.gps_space_node, @solver.sbas_space_node, @solver.glonass_space_node, ].inject(0){|res, sn| loaded_items = critical{sn.send(:read, fname)} raise "Format error! (Not RINEX) #{src}" if loaded_items < 0 res + loaded_items } $stderr.puts "Read RINEX NAV file (%s): %d items."%[src, items] end |
#parse_rinex_obs(src, &b) ⇒ Object
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 |
# File 'lib/gps_pvt/receiver.rb', line 622 def parse_rinex_obs(src, &b) fname = Util::get_txt(src) after_run = b || proc{|pvt| puts pvt.to_s if pvt} $stderr.print "Reading RINEX observation file (%s)"%[src] types = nil glonass_freq = nil count = 0 GPS::RINEX_Observation::read(fname){|item| $stderr.print '.' if (count += 1) % 1000 == 0 t_meas = item[:time] types ||= Hash[*(item[:meas_types].collect{|sys, values| [sys, values.collect.with_index{|type_, i| sig_obs_type = [case type_[1..-1] when /^1C?$/; :L1 when /^2[XL]$/; :L2CL when /^2S$/; :L2CM else; nil end, { 'C' => :PSEUDORANGE, 'L' => :CARRIER_PHASE, 'D' => :DOPPLER, 'S' => :SIGNAL_STRENGTH_dBHz, }[type_[0]]] next nil unless sig_obs_type.all? [i, sig_obs_type.join('_').to_sym, *sig_obs_type] }.compact] }.flatten(1))] glonass_freq ||= proc{|spec| # frequency channels described in observation file next {} unless spec Hash[*(spec.collect{|line| line[4..-1].scan(/R(\d{2}).([\s+-]\d)./).collect{|prn, ch| [prn.to_i, GPS::SpaceNode_GLONASS::L1_frequency(ch.to_i)] } }.flatten(2))] }.call(item[:header]["GLONASS SLOT / FRQ #"]) meas = GPS::Measurement::new item[:meas].each{|(sys, prn), v| case sys when 'G', ' ' when 'S'; prn += 100 when 'J'; prn += 192 when 'R' freq = (glonass_freq[prn] ||= proc{|sn| # frequency channels saved with ephemeris sn.update_all_ephemeris(t_meas) next nil unless sn.ephemeris(prn).in_range?(t_meas) sn.ephemeris(prn).frequency_L1 }.call(@solver.glonass_space_node)) prn += 0x100 meas.add(prn, :L1_FREQUENCY, freq) if freq else; next end types[sys] = (types[' '] || []) unless types[sys] types[sys].each{|i, type_, sig_type, obs_type| next unless v[i] meas.add(prn, type_, v[i][0]) meas.add(prn, "#{sig_type}_CARRIER_PHASE_AMBIGUITY_SCALE".to_sym, 0.5) \ if (obs_type == :CARRIER_PHASE) && (v[i][1] & 0x2 == 0x2) } } after_run.call(run(meas, t_meas), [meas, t_meas]) } $stderr.puts ", %d epochs."%[count] end |
#parse_rtcm3(src, opt = {}, &b) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 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 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/gps_pvt/receiver/rtcm3.rb', line 7 def parse_rtcm3(src, opt = {}, &b) $stderr.print "Reading RTCM3 stream (%s) "%[src] require_relative '../rtcm3' src_io = Util::open(src) rtcm3 = GPS_PVT::RTCM3::new(src_io) ref_time = case (ref_time = opt[:ref_time]) when GPS::Time; when Time t_array = ref_time.utc.to_a[0..5].reverse GPS::Time::new(t_array, GPS::Time::guess_leap_seconds(t_array)) when nil; GPS::Time::now else; raise "reference time (#{ref_time}) should be GPS::Time or Time" end leap_sec = ref_time.leap_seconds ref_pos = opt[:ref_pos] || if src_io.respond_to?(:property) then Coordinate::LLH::new(*(src_io.property.values_at(:latitude, :longitude).collect{|v| v.to_f / 180 * Math::PI } + [0])).xyz else defined?(@base_station) ? @base_station : nil end after_run = b || proc{|pvt| puts pvt.to_s if pvt} t_meas, meas = [nil, {}] # meas := {msg_num => [[], ...]} due to duplicated observation such as 1074 and 1077 run_proc = proc{ meas_ = GPS::Measurement::new meas.sort.each{|k, values| # larger msg_num entries have higher priority values.each{|prn_k_v| meas_.add(*prn_k_v)} } pvt = nil after_run.call(pvt = run(meas_, t_meas), [meas_, ref_time = t_meas]) if t_meas ref_pos = pvt.xyz if pvt && pvt.position_solved? t_meas, meas = [nil, {}] } dt_threshold = GPS::Time::Seconds_week / 2 tow2t = proc{|tow_sec| dt = tow_sec - ref_time.seconds GPS::Time::new(ref_time.week + if dt <= -dt_threshold then; 1 elsif dt >= dt_threshold then; -1 else; 0; end, tow_sec) } utc2t = proc{|utc_tod| if t_meas then delta = (t_meas.seconds - utc_tod).to_i % (60 * 60 * 24) leap_sec = (delta >= (60 * 60 * 12)) ? delta - (60 * 60 * 12) : delta t_meas else ref_dow, ref_tod = ref_time.seconds.divmod(60 * 60 * 24) tod = utc_tod + leap_sec tod_delta = ref_tod - tod if tod_delta > 12 * 60 * 60 then ref_dow -= 1 elsif tod_delta < -12 * 60 * 60 then ref_dow += 1 end GPS::Time::new(ref_time.week, 0) + tod + 60 * 60 * 24 * ref_dow end } restore_ranges = proc{ c_1ms = 299_792.458 threshold = c_1ms / 10 # 100 us =~ 30 km cache = {} # {[sys, svid] => [range, t], ...} get_rough = proc{|t, sys_svid_list| sn_list = sys_svid_list.collect{|sys, svid| case sys when :GPS, :QZSS; @solver.gps_space_node when :SBAS; @solver.sbas_space_node when :GLONASS; @solver.glonass_space_node end } critical{ sn_list.uniq.compact{|sn| sn.update_all_ephemeris(t)} sys_svid_list.zip(sn_list).each{|(sys, svid), sn| next unless sn eph = sn.ephemeris(svid) cache[[sys, svid]] = [if eph.valid?(t) then sv_pos, clk_err = eph.constellation(t).values_at(0, 2) sv_pos.distance(ref_pos) - (clk_err * c_1ms * 1E3) end, t] } } } per_kind = proc{|t, sys_svid_list, ranges_rem| get_rough.call(t, sys_svid_list.uniq.reject{|sys, svid| next true unless sys range, t2 = cache[[sys, svid]] range && ((t2 - t).abs <= 60) }) ranges_rem.zip(sys_svid_list).collect{|rem_in, (sys, svid)| range_ref, t2 = cache[[sys, svid]] next nil unless range_ref q, rem_ref = range_ref.divmod(c_1ms) delta = rem_in - rem_ref res = if delta.abs <= threshold then q * c_1ms + rem_in elsif -delta + c_1ms <= threshold (q - 1) * c_1ms + rem_in elsif delta + c_1ms <= threshold (q + 1) * c_1ms + rem_in end #p [sys, svid, q, rem_in, rem_ref, res] (cache[[sys, svid]] = [res, t])[0] } } proc{|t, sys_svid_list, ranges| [ :pseudo_range, # for MT 1001/3/9/11, MSM1/3 :phase_range, # for MT 1003/11, MSM2/3 ].each{|k| next if ranges[k] k_rem = "#{k}_rem".to_sym ranges[k] = per_kind.call(t, sys_svid_list, ranges[k_rem]) if ranges[k_rem] } } }.call while packet = rtcm3.read_packet msg_num = packet. parsed = packet.parse t_meas2, meas2 = [nil, []] # per_packet add_proc = proc{ t_meas ||= t_meas2 meas[msg_num] = meas2 unless meas2.empty? } case msg_num when 1001..1004 t_meas2 = tow2t.call(parsed[2][0]) # DF004 ranges = parsed.ranges sys_svid_list = ranges[:sat].collect{|svid| case svid when 1..32; [:GPS, svid] when 40..58; [:SBAS, svid + 80] else; [nil, svid] end } restore_ranges.call(t_meas2, sys_svid_list, ranges) item_size = sys_svid_list.size ([sys_svid_list] + [:pseudo_range, :phase_range, :cn].collect{|k| ranges[k] || ([nil] * item_size) }).transpose.each{|(sys, svid), pr, cpr, cn| next unless sys meas2 << [svid, :L1_PSEUDORANGE, pr] if pr meas2 << [svid, :L1_CARRIER_PHASE, cpr / GPS::SpaceNode.L1_WaveLength] if cpr meas2 << [svid, :L1_SIGNAL_STRENGTH_dBHz, cn] if cn } when 1009..1012 t_meas2 = utc2t.call(parsed[2][0] - 60 * 60 * 3) # DF034 UTC(SU)+3hr, time of day[sec] ranges = parsed.ranges sys_svid_list = ranges[:sat].collect{|svid| case svid when 1..24; [:GLONASS, svid] when 40..58; [:SBAS, svid + 80] else; [nil, svid] end } restore_ranges.call(t_meas2, sys_svid_list, ranges) item_size = sys_svid_list.size ([sys_svid_list] + [:freq_ch, :pseudo_range, :phase_range, :cn].collect{|k| ranges[k] || ([nil] * item_size) }).transpose.each{|(sys, svid), freq_ch, pr, cpr, cn| case sys when :GLONASS svid += 0x100 freq = GPS::SpaceNode_GLONASS::L1_frequency(freq_ch) len = GPS::SpaceNode_GLONASS.light_speed / freq meas2 << [svid, :L1_FREQUENCY, freq] meas2 << [svid, :L1_CARRIER_PHASE, cpr / len] if cpr when :SBAS meas2 << [svid, :L1_CARRIER_PHASE, cpr / GPS::SpaceNode.L1_WaveLength] if cpr else; next end meas2 << [svid, :L1_PSEUDORANGE, pr] if pr meas2 << [svid, :L1_SIGNAL_STRENGTH_dBHz, cn] if cn } when 1013 leap_sec = parsed[5][0] when 1019, 1044 params = parsed.params if msg_num == 1044 params[:svid] += 192 params[:fit_interval] ||= 2 * 60 * 60 end params[:WN] += ((ref_time.week - params[:WN]).to_f / 1024).round * 1024 eph = GPS::Ephemeris::new params.each{|k, v| eph.send("#{k}=".to_sym, v)} critical{ @solver.gps_space_node.register_ephemeris(eph.svid, eph) } when 1020 params = parsed.params eph = GPS::Ephemeris_GLONASS::new eph.F_T = 10 # [m], default to be overwritten params.each{|k, v| next if [:P3, :NA, :N_4].include?(k) eph.send("#{k}=".to_sym, v) } proc{|date_src| eph.set_date(*(date_src.all? \ ? date_src \ : [(ref_time + 3 * 60 * 60).c_tm(leap_sec)])) # UTC -> Moscow time }.call([:N_4, :NA].collect{|k| params[k]}) eph.N_T = params[:NA] || eph.NA unless params[:N_T] # N_T is available only for GLONASS-M eph.rehash(leap_sec) critical{ @solver.glonass_space_node.register_ephemeris(eph.svid, eph) } when 1043 params = parsed.params eph = GPS::Ephemeris_SBAS::new tod_delta = params[:tod] - (ref_time.seconds % (24 * 60 * 60)) if tod_delta > (12 * 60 * 60) then tod_delta -= (24 * 60 * 60) elsif tod_delta < -(12 * 60 * 60) then tod_delta += (24 * 60 * 60) end toe = ref_time + tod_delta eph.WN, eph.t_0 = [:week, :seconds].collect{|k| toe.send(k)} params.each{|k, v| eph.send("#{k}=".to_sym, v) unless [:iodn, :tod].include?(k)} critical{ @solver.sbas_space_node.register_ephemeris(eph.svid, eph) } when 1071..1077, 1081..1087, 1101..1107, 1111..1117 ranges = parsed.ranges glonass_freq = nil case msg_num / 10 # check time of measurement when 107, 110, 111 # GPS, SBAS, QZSS t_meas2 = tow2t.call(parsed[2][0]) # DF004 when 108 # GLONASS t_meas2 = utc2t.call(parsed[3][0] - 60 * 60 * 3) # DF034 UTC(SU)+3hr, time of day[sec] glonass_freq = critical{ @solver.glonass_space_node.update_all_ephemeris(t_meas2) Hash[*(ranges[:sat_sig].collect{|svid, sig| svid}.uniq.collect{|svid| eph = @solver.glonass_space_node.ephemeris(svid) next nil unless eph.in_range?(t_meas2) [svid, {:L1 => eph.frequency_L1}] }.compact.flatten(1))] } end sig_list, sys, svid_offset = case msg_num / 10 when 107 # GPS [{2 => [:L1, GPS::SpaceNode.L1_WaveLength], 15 => [:L2CM, GPS::SpaceNode.L2_WaveLength], 16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, :GPS, 0] when 108 # GLONASS [{2 => [:L1, nil]}, :GLONASS, 0x100] when 110 # SBAS [{2 => [:L1, GPS::SpaceNode.L1_WaveLength]}, :SBAS, 120] when 111 # QZSS [{2 => [:L1, GPS::SpaceNode.L1_WaveLength], 15 => [:L2CM, GPS::SpaceNode.L2_WaveLength], 16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, :QZSS, 192] else; [{}, nil, 0] end sys_svid_list = ranges[:sat_sig].collect{|sat, sig| [sys, (sat + svid_offset) & 0xFF]} restore_ranges.call(t_meas2, sys_svid_list, ranges) item_size = sys_svid_list.size [:sat_sig, :pseudo_range, :phase_range, :phase_range_rate, :cn, :halfc_amb].collect{|k| ranges[k] || ([nil] * item_size) }.transpose.each{|(svid, sig), pr, cpr, dr, cn, amb| prefix, len = sig_list[sig] next unless prefix proc{ next unless freq = (glonass_freq[svid] || {})[prefix] meas2 << [svid, "#{prefix}_FREQUENCY".to_sym, freq] len = GPS::SpaceNode_GLONASS.light_speed / freq }.call if glonass_freq svid += svid_offset meas2 << [svid, "#{prefix}_PSEUDORANGE".to_sym, pr] if pr meas2 << [svid, "#{prefix}_RANGE_RATE".to_sym, dr] if dr meas2 << [svid, "#{prefix}_CARRIER_PHASE".to_sym, cpr / len] if cpr && len meas2 << [svid, "#{prefix}_SIGNAL_STRENGTH_dBHz".to_sym, cn] if cn meas2 << [svid, "#{prefix}_CARRIER_PHASE_AMBIGUITY_SCALE".to_sym, 0.5] if amb && (amb == 1) } else #p({msg_num => parsed}) end run_proc.call if t_meas && t_meas2 && ((t_meas - t_meas2).abs > 1E-3) # fallback for incorrect more_data flag add_proc.call run_proc.call if (1070..1229).include?(msg_num) && (!parsed.more_data?) end end |
#parse_sem_almanac(src) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/gps_pvt/receiver/almanac.rb', line 27 def parse_sem_almanac(src) src_io = open(Util::get_txt(src)) raise unless src_io.readline =~ /(\d+)\s+(\S+)/ # line 1 num, name = [$1.to_i, $2] raise unless src_io.readline =~ /(\d+)\s+(\d+)/ # line 2 week, t_oa = [$1.to_i, $2.to_i] week = correct_week_sem_yuma_almanac(src, week) src_io.readline # line 3 num.times.each{ eph = GPS::Ephemeris::new 9.times{|i| # line R-1..9 case i when 0, 1, 2, 6, 7 # N/A items; 1 => SV reference number, 7 => configuration code k = {0 => :svid, 2 => :URA_index, 6 => :SV_health}[i] v = Integer(src_io.readline) eph.send("#{k}=".to_sym, v) if k when 3..5 res = src_io.readline.scan(/[+-]?\d+(?:\.\d+)?(?:E[+-]\d+)?/).collect{|s| Float(s)} raise unless res.size == 3 res.zip({ 3 => [:e, [:i0, GPS::GPS_SC2RAD], [:dot_Omega0, GPS::GPS_SC2RAD]], 4 => [:sqrt_A, [:Omega0, GPS::GPS_SC2RAD], [:omega, GPS::GPS_SC2RAD]], 5 => [[:M0, GPS::GPS_SC2RAD], :a_f0, :a_f1], }[i]).each{|v, (k, sf)| eph.send("#{k}=".to_sym, sf ? (sf * v) : v) } when 8 src_io.readline end } eph.i0 = GPS::GPS_SC2RAD * 0.3 + eph.i0 eph.WN = week eph.t_oc = eph.t_oe = t_oa [:iodc, :t_GD, :a_f2, :iode, :c_rs, :delta_n, :c_uc, :c_us, :c_ic, :c_is, :c_rc, :dot_i0, :iode_subframe3].each{|k| eph.send("#{k}=", 0) } critical{@solver.gps_space_node.register_ephemeris(eph.svid, eph)} } $stderr.puts "Read SEM Almanac file (%s): %d items."%[src, num] end |
#parse_supl(src, opt = {}, &b) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/gps_pvt/receiver/agps.rb', line 7 def parse_supl(src, opt = {}, &b) $stderr.print "A-GPS (%s) "%[src] opt = { :interval => 60 * 10, # 10 min. }.merge(opt) require_relative '../supl' src_io = Util::open(src) while data = src_io.get_assisted_data data.ephemeris.each{|eph| target = case eph when GPS::Ephemeris; @solver.gps_space_node when GPS::Ephemeris_GLONASS; @solver.glonass_space_node when GPS::Ephemeris_SBAS; @solver.sbas_space_node else nil end critical{target.register_ephemeris(eph.svid, eph)} if target } if data.respond_to?(:ephemeris) critical{ @solver.gps_space_node.update_iono_utc(data.iono_utc) } if data.respond_to?(:iono_utc) sleep(opt[:interval]) end end |
#parse_ubx(ubx_fname, &b) ⇒ Object
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 |
# File 'lib/gps_pvt/receiver.rb', line 467 def parse_ubx(ubx_fname, &b) $stderr.print "Reading UBX file (%s) "%[ubx_fname] require_relative 'ubx' ubx = UBX::new(Util::open(ubx_fname)) ubx_kind = Hash::new(0) after_run = b || proc{|pvt| puts pvt.to_s if pvt} gnss_serial = proc{|svid, sys| if sys then # new numbering sys = [:GPS, :SBAS, :Galileo, :BeiDou, :IMES, :QZSS, :GLONASS][sys] if sys.kind_of?(Integer) case sys when :QZSS; svid += 192 end else # old numbering sys = case svid when 1..32; :GPS when 120..158; :SBAS when 193..202; :QZSS when 65..96; svid -= 64; :GLONASS when 255; :GLONASS end end [sys, svid] } t_meas = nil ubx.each_packet.with_index(1){|packet, i| $stderr.print '.' if i % 1000 == 0 ubx_kind[packet[2..3]] += 1 case packet[2..3] when [0x02, 0x10] # RXM-RAW msec, week = [[0, 4, "V"], [4, 2, "v"]].collect{|offset, len, str| packet.slice(6 + offset, len).pack("C*").unpack(str)[0] } t_meas = GPS::Time::new(week, msec.to_f / 1000) meas = GPS::Measurement::new packet[6 + 6].times{|i| loader = proc{|offset, len, str| ary = packet.slice(6 + offset + (i * 24), len) str ? ary.pack("C*").unpack(str)[0] : ary } prn = loader.call(28, 1)[0] { :L1_PSEUDORANGE => [16, 8, "E"], :L1_DOPPLER => [24, 4, "e"], :L1_CARRIER_PHASE => [8, 8, "E"], :L1_SIGNAL_STRENGTH_dBHz => [30, 1, "c"], }.each{|k, prop| meas.add(prn, k, loader.call(*prop)) } lli = packet[6 + 31 + (i * 24)] # bit 0 of RINEX LLI (loss of lock indicator) shows lost lock # between previous and current observation, which maps negative lock seconds meas.add(prn, :L1_LOCK_SEC, (lli & 0x01 == 0x01) ? -1 : 0) # set bit 1 of LLI represents possibility of half cycle ambiguity meas.add(prn, :L1_CARRIER_PHASE_AMBIGUITY_SCALE, 0.5) if (lli & 0x02 == 0x02) } after_run.call(run(meas, t_meas), [meas, t_meas]) when [0x02, 0x15] # RXM-RAWX sec, week = [[0, 8, "E"], [8, 2, "v"]].collect{|offset, len, str| packet.slice(6 + offset, len).pack("C*").unpack(str)[0] } t_meas = GPS::Time::new(week, sec) meas = GPS::Measurement::new packet[6 + 11].times{|i| loader = proc{|offset, len, str, post| v = packet.slice(6 + offset + (i * 32), len) v = str ? v.pack("C*").unpack(str)[0] : v v = post.call(v) if post v } sys, svid = gnss_serial.call(*loader.call(36, 2).reverse) sigid = (packet[6 + 13] != 0) ? loader.call(38, 1, "C") : 0 # sigID if version(>0); @see UBX-18010854 case sys when :GPS sigid = {0 => :L1, 3 => :L2CL, 4 => :L2CM}[sigid] when :SBAS sigid = :L1 when :QZSS sigid = {0 => :L1, 5 => :L2CL, 4 => :L2CM}[sigid] when :GLONASS svid += 0x100 sigid = {0 => :L1}[sigid] # TODO: to support {2 -> :L2} meas.add(svid, :L1_FREQUENCY, GPS::SpaceNode_GLONASS::L1_frequency(loader.call(39, 1, "C") - 7)) else; next end next unless sigid trk_stat = loader.call(46, 1)[0] { :PSEUDORANGE => [16, 8, "E", proc{|v| (trk_stat & 0x1 == 0x1) ? v : nil}], :PSEUDORANGE_SIGMA => [43, 1, nil, proc{|v| (trk_stat & 0x1 == 0x1) ? (1E-2 * (1 << (v[0] & 0xF))) : nil }], :DOPPLER => [32, 4, "e"], :DOPPLER_SIGMA => [45, 1, nil, proc{|v| 2E-3 * (1 << (v[0] & 0xF))}], :CARRIER_PHASE => [24, 8, "E", proc{|v| case (trk_stat & 0x6) when 0x6; (trk_stat & 0x8 == 0x8) ? (v + 0.5) : v when 0x2; meas.add(svid, "#{sigid}_CARRIER_PHASE_AMBIGUITY_SCALE".to_sym, 0.5); v else; nil end }], :CARRIER_PHASE_SIGMA => [44, 1, nil, proc{|v| (trk_stat & 0x2 == 0x2) ? (0.004 * (v[0] & 0xF)) : nil }], :SIGNAL_STRENGTH_dBHz => [42, 1, "C"], :LOCK_SEC => [40, 2, "v", proc{|v| 1E-3 * v}], }.each{|k, prop| next unless v = loader.call(*prop) meas.add(svid, "#{sigid}_#{k}".to_sym, v) rescue nil # unsupported signal } } after_run.call(run(meas, t_meas), [meas, t_meas]) when [0x02, 0x11] # RXM-SFRB sys, svid = gnss_serial.call(packet[6 + 1]) register_ephemeris( t_meas, sys, svid, proc{|data| case sys # adjust padding when :GPS; data.collect!{|v| (v & 0xFFFFFF) << 6} when :SBAS; data[7] <<= 6 end data }.call(packet.slice(6 + 2, 40).pack("C*").unpack("V*"))) when [0x02, 0x13] # RXM-SFRBX sys, svid = gnss_serial.call(packet[6 + 1], packet[6]) opt = {} opt[:freq_ch] = packet[6 + 3] - 7 if sys == :GLONASS register_ephemeris( t_meas, sys, svid, packet.slice(6 + 8, 4 * packet[6 + 4]).pack("C*").unpack("V*"), opt) end } $stderr.puts ", found packets are %s"%[ubx_kind.inspect] end |
#parse_yuma_almanac(src) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/gps_pvt/receiver/almanac.rb', line 99 def parse_yuma_almanac(src) src_io = open(Util::get_txt(src)) num = 0 idx_line = -1 eph, items = nil while !src_io.eof? line = src_io.readline.chomp if idx_line < 0 then if line =~ /^\*{8}/ then eph = GPS::Ephemeris::new items = YUMA_ITEMS.clone idx_line = 0 end next end raise unless i = items.index{|re, cnv, *k_list| next false unless re =~ line v = cnv.call($') k_list.each{|k| eph.send(k, v)} true } items.delete_at(i) next unless items.empty? [:iodc, :t_GD, :a_f2, :iode, :c_rs, :delta_n, :c_uc, :c_us, :c_ic, :c_is, :c_rc, :dot_i0, :iode_subframe3].each{|k| eph.send("#{k}=", 0) } eph.WN = correct_week_sem_yuma_almanac(src, eph.WN) critical{@solver.gps_space_node.register_ephemeris(eph.svid, eph)} num += 1 idx_line = -1 end $stderr.puts "Read YUMA Almanac file (%s): %d items."%[src, num] end |
#register_ephemeris(t_meas, sys, prn, bcast_data, *options) ⇒ Object
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
# File 'lib/gps_pvt/receiver.rb', line 412 def register_ephemeris(t_meas, sys, prn, bcast_data, *) @eph_list ||= Hash[*((1..32).to_a + (193..202).to_a).collect{|prn| eph = GPS::Ephemeris::new eph.svid = prn [prn, eph] }.flatten(1)] @eph_glonass_list ||= Hash[*(1..24).collect{|num| eph = GPS::Ephemeris_GLONASS::new eph.svid = num [num, eph] }.flatten(1)] opt = [0] || {} case sys when :GPS, :QZSS return unless bcast_data.size == 10 # 8 for QZSS(SAIF) return unless eph = @eph_list[prn] sn = @solver.gps_space_node subframe, iodc_or_iode = eph.parse(bcast_data) if iodc_or_iode < 0 then begin sn.update_iono_utc( GPS::Ionospheric_UTC_Parameters::parse(bcast_data)) [:alpha, :beta].each{|k| $stderr.puts "Iono #{k}: #{sn.iono_utc.send(k)}" } if false rescue end return end if t_meas and eph.consistent? then eph.WN = ((t_meas.week / 1024).to_i * 1024) + (eph.WN % 1024) sn.register_ephemeris(prn, eph) eph.invalidate end when :SBAS case @solver.sbas_space_node.(bcast_data[0..7], prn, t_meas) when 26 ['', "IGP broadcasted by PRN#{prn} @ #{Time::utc(*t_meas.c_tm)}", @solver.sbas_space_node.ionospheric_grid_points(prn)].each{|str| $stderr.puts str } if @debug[:SBAS_IGP] end if t_meas when :GLONASS return unless eph = @eph_glonass_list[prn] leap_sec = @solver.gps_space_node.is_valid_utc ? @solver.gps_space_node.iono_utc.delta_t_LS : GPS::Time::guess_leap_seconds(t_meas) return unless eph.parse(bcast_data[0..3], leap_sec) eph.freq_ch = opt[:freq_ch] || 0 @solver.glonass_space_node.register_ephemeris(prn, eph) eph.invalidate end end |
#run(meas, t_meas, ref_pos = @base_station) ⇒ Object
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/gps_pvt/receiver.rb', line 355 def run(meas, t_meas, ref_pos = @base_station) =begin $stderr.puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %d:%d:%d UTC"%[*t_meas.c_tm]})" meas.to_a.collect{|prn, k, v| prn}.uniq.each{|prn| eph = @solver.gps_space_node.ephemeris(prn) $stderr.puts "XYZ(PRN:#{prn}): #{eph.constellation(t_meas)[0].to_a} (iodc: #{eph.iodc}, iode: #{eph.iode})" } =end #@solver.gps_space_node.update_all_ephemeris(t_meas) # internally called in the following solver.solve pvt = critical{@solver.solve(meas, t_meas)} pvt.define_singleton_method(:rel_ENU){ Coordinate::ENU::relative(xyz, ref_pos) } if (ref_pos && pvt.position_solved?) output = @output pvt.define_singleton_method(:to_s){ (output[:pvt].transpose[1].collect{|task| task.call(pvt) } + output[:meas].transpose[1].collect{|task| task.call(meas) }).flatten.join(',') } pvt end |