gps_pvt 0.6.3 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,6 +22,7 @@
22
22
  #include "navigation/QZSS.h"
23
23
  #include "navigation/GLONASS.h"
24
24
  #include "navigation/RINEX.h"
25
+ #include "navigation/RINEX_Clock.h"
25
26
  #include "navigation/SP3.h"
26
27
  #include "navigation/ANTEX.h"
27
28
 
@@ -228,12 +229,10 @@ struct GPS_Ionospheric_UTC_Parameters : public GPS_SpaceNode<FloatT>::Ionospheri
228
229
  %}
229
230
  %extend GPS_Ionospheric_UTC_Parameters {
230
231
  %fragment(SWIG_Traits_frag(FloatT));
231
- %typemap(in,numinputs=0) FloatT values[4] (FloatT temp[4]) %{
232
- $1 = temp;
233
- %}
234
- %typemap(argout) FloatT values[4] {
232
+ %typemap(in,numinputs=0) const FloatT *values[4] (FloatT *temp) "$1 = &temp;"
233
+ %typemap(argout) const FloatT *values[4] {
235
234
  for(int i(0); i < 4; ++i){
236
- %append_output(swig::from($1[i]));
235
+ %append_output(swig::from((*$1)[i]));
237
236
  }
238
237
  }
239
238
  MAKE_ARRAY_INPUT(const FloatT, values, swig::asval);
@@ -245,11 +244,7 @@ struct GPS_Ionospheric_UTC_Parameters : public GPS_SpaceNode<FloatT>::Ionospheri
245
244
  }
246
245
  }
247
246
  %rename("alpha") get_alpha;
248
- void get_alpha(FloatT values[4]) const {
249
- for(int i(0); i < 4; ++i){
250
- values[i] = self->alpha[i];
251
- }
252
- }
247
+ void get_alpha(const FloatT *values[4]) const {*values = self->alpha;}
253
248
  %rename("beta=") set_beta;
254
249
  void set_beta(const FloatT values[4]){
255
250
  for(int i(0); i < 4; ++i){
@@ -257,11 +252,7 @@ struct GPS_Ionospheric_UTC_Parameters : public GPS_SpaceNode<FloatT>::Ionospheri
257
252
  }
258
253
  }
259
254
  %rename("beta") get_beta;
260
- void get_beta(FloatT values[4]) const {
261
- for(int i(0); i < 4; ++i){
262
- values[i] = self->beta[i];
263
- }
264
- }
255
+ void get_beta(const FloatT *values[4]) const {*values = self->beta;}
265
256
  MAKE_ACCESSOR(A1, FloatT);
266
257
  MAKE_ACCESSOR(A0, FloatT);
267
258
  MAKE_ACCESSOR(t_ot, unsigned int);
@@ -1006,6 +997,7 @@ const type &get_ ## name () const {
1006
997
  %inline %{
1007
998
  template <class FloatT>
1008
999
  struct GPS_SolverOptions_Common {
1000
+ virtual ~GPS_SolverOptions_Common() {}
1009
1001
  virtual GPS_Solver_GeneralOptions<FloatT> *cast_general() = 0;
1010
1002
  virtual const GPS_Solver_GeneralOptions<FloatT> *cast_general() const = 0;
1011
1003
  };
@@ -1206,7 +1198,10 @@ struct GPS_RangeCorrector
1206
1198
  if(!res.is_available()){
1207
1199
  static const VALUE key(ID2SYM(rb_intern("relative_property")));
1208
1200
  VALUE hook(rb_hash_lookup(hooks, key));
1209
- if(!NIL_P(hook)){res.impl = this;}
1201
+ if(!NIL_P(hook)){
1202
+ if(!res.impl_xyz){res.impl_xyz = this;}
1203
+ if(!res.impl_t){res.impl_t = this;}
1204
+ }
1210
1205
  }
1211
1206
  #endif
1212
1207
  return res;
@@ -1361,6 +1356,28 @@ struct GPS_RangeCorrector
1361
1356
  return self->update_correction(true, hash);
1362
1357
  }
1363
1358
  #endif
1359
+ #ifdef SWIGRUBY
1360
+ %typemap(out) typename super_t::options_t {
1361
+ VALUE res(rb_hash_new());
1362
+ rb_hash_aset(res, ID2SYM(rb_intern("skip_exclusion")), SWIG_From(bool)($1.skip_exclusion));
1363
+ %set_output(res);
1364
+ }
1365
+ #endif
1366
+ %rename("options") get_options;
1367
+ typename super_t::options_t get_options() const {
1368
+ return self->available_options();
1369
+ }
1370
+ %rename("options=") set_options;
1371
+ typename super_t::options_t set_options(SWIG_Object obj) {
1372
+ GPS_Solver<FloatT>::super_t::options_t opt(self->available_options());
1373
+ #ifdef SWIGRUBY
1374
+ if(!RB_TYPE_P(obj, T_HASH)){SWIG_exception(SWIG_TypeError, "Hash is expected");}
1375
+ SWIG_AsVal(bool)(
1376
+ rb_hash_lookup(obj, ID2SYM(rb_intern("skip_exclusion"))),
1377
+ &opt.skip_exclusion);
1378
+ #endif
1379
+ return self->update_options(opt);
1380
+ }
1364
1381
  }
1365
1382
  %inline {
1366
1383
  template <class FloatT>
@@ -1653,31 +1670,8 @@ template <class FloatT>
1653
1670
  struct RINEX_Observation {};
1654
1671
  }
1655
1672
 
1656
- %extend SP3 {
1657
- %typemap(in,numinputs=0) int count[ANY] (int temp[$1_dim0]) "$1 = temp;"
1658
- %typemap(argout) int count[ANY] {
1659
- for(int i(0); i < $1_dim0; ++i){
1660
- %append_output(SWIG_From(int)($1[i]));
1661
- }
1662
- }
1663
- void satellites(int count[SP3::SYS_SYSTEMS]) const {
1664
- typename SP3_Product<FloatT>::satellite_count_t x(self->satellite_count());
1665
- count[SP3<FloatT>::SYS_GPS] = x.gps;
1666
- count[SP3<FloatT>::SYS_SBAS] = x.sbas;
1667
- count[SP3<FloatT>::SYS_QZSS] = x.qzss;
1668
- count[SP3<FloatT>::SYS_GLONASS] = x.glonass;
1669
- count[SP3<FloatT>::SYS_GALILEO] = x.galileo;
1670
- count[SP3<FloatT>::SYS_BEIDOU] = x.beidou;
1671
- }
1672
-
1673
- }
1674
1673
  %inline {
1675
- template <class FloatT>
1676
- struct SP3 : public SP3_Product<FloatT> {
1677
- int read(const char *fname) {
1678
- std::fstream fin(fname, std::ios::in | std::ios::binary);
1679
- return SP3_Reader<FloatT>::read_all(fin, *this);
1680
- }
1674
+ struct PushableData {
1681
1675
  enum system_t {
1682
1676
  SYS_GPS,
1683
1677
  SYS_SBAS,
@@ -1687,20 +1681,21 @@ struct SP3 : public SP3_Product<FloatT> {
1687
1681
  SYS_BEIDOU,
1688
1682
  SYS_SYSTEMS,
1689
1683
  };
1690
- bool push(GPS_Solver<FloatT> &solver, const system_t &sys) const {
1684
+ template <class DataT, class FloatT>
1685
+ static bool push(DataT &data, GPS_Solver<FloatT> &solver, const system_t &sys){
1691
1686
  switch(sys){
1692
1687
  case SYS_GPS:
1693
- return SP3_Product<FloatT>::push(
1694
- solver.gps.ephemeris_proxy.gps, SP3_Product<FloatT>::SYSTEM_GPS);
1688
+ return data.push(
1689
+ solver.gps.ephemeris_proxy.gps, DataT::SYSTEM_GPS);
1695
1690
  case SYS_SBAS:
1696
- return SP3_Product<FloatT>::push(
1697
- solver.sbas.solver.satellites, SP3_Product<FloatT>::SYSTEM_SBAS);
1691
+ return data.push(
1692
+ solver.sbas.solver.satellites, DataT::SYSTEM_SBAS);
1698
1693
  case SYS_QZSS:
1699
- return SP3_Product<FloatT>::push(
1700
- solver.gps.ephemeris_proxy.qzss, SP3_Product<FloatT>::SYSTEM_QZSS);
1694
+ return data.push(
1695
+ solver.gps.ephemeris_proxy.qzss, DataT::SYSTEM_QZSS);
1701
1696
  case SYS_GLONASS:
1702
- return SP3_Product<FloatT>::push(
1703
- solver.glonass.solver.satellites, SP3_Product<FloatT>::SYSTEM_GLONASS);
1697
+ return data.push(
1698
+ solver.glonass.solver.satellites, DataT::SYSTEM_GLONASS);
1704
1699
  case SYS_GALILEO:
1705
1700
  case SYS_BEIDOU:
1706
1701
  default:
@@ -1708,7 +1703,8 @@ struct SP3 : public SP3_Product<FloatT> {
1708
1703
  }
1709
1704
  return false;
1710
1705
  }
1711
- bool push(GPS_Solver<FloatT> &solver) const {
1706
+ template <class DataT, class FloatT>
1707
+ static bool push(DataT &data, GPS_Solver<FloatT> &solver){
1712
1708
  system_t target[] = {
1713
1709
  SYS_GPS,
1714
1710
  SYS_SBAS,
@@ -1718,10 +1714,39 @@ struct SP3 : public SP3_Product<FloatT> {
1718
1714
  //SYS_BEIDOU,
1719
1715
  };
1720
1716
  for(std::size_t i(0); i < sizeof(target) / sizeof(target[0]); ++i){
1721
- if(!push(solver, target[i])){return false;}
1717
+ if(!push(data, solver, target[i])){return false;}
1722
1718
  }
1723
1719
  return true;
1724
1720
  }
1721
+ };
1722
+ }
1723
+
1724
+ %extend SP3 {
1725
+ %typemap(out) typename SP3_Product<FloatT>::satellite_count_t {
1726
+ %append_output(SWIG_From(int)($1.gps));
1727
+ %append_output(SWIG_From(int)($1.sbas));
1728
+ %append_output(SWIG_From(int)($1.qzss));
1729
+ %append_output(SWIG_From(int)($1.glonass));
1730
+ %append_output(SWIG_From(int)($1.galileo));
1731
+ %append_output(SWIG_From(int)($1.beidou));
1732
+ }
1733
+ }
1734
+ %inline {
1735
+ template <class FloatT>
1736
+ struct SP3 : public SP3_Product<FloatT>, PushableData {
1737
+ int read(const char *fname) {
1738
+ std::fstream fin(fname, std::ios::in | std::ios::binary);
1739
+ return SP3_Reader<FloatT>::read_all(fin, *this);
1740
+ }
1741
+ typename SP3_Product<FloatT>::satellite_count_t satellites() const {
1742
+ return SP3_Product<FloatT>::satellite_count();
1743
+ }
1744
+ bool push(GPS_Solver<FloatT> &solver, const PushableData::system_t &sys) const {
1745
+ return PushableData::push((SP3_Product<FloatT> &)*this, solver, sys);
1746
+ }
1747
+ bool push(GPS_Solver<FloatT> &solver) const {
1748
+ return PushableData::push((SP3_Product<FloatT> &)*this, solver);
1749
+ }
1725
1750
  System_XYZ<FloatT, WGS84> position(
1726
1751
  const int &sat_id, const GPS_Time<FloatT> &t) const {
1727
1752
  return SP3_Product<FloatT>::select(sat_id, t).position(t);
@@ -1748,6 +1773,46 @@ struct SP3 : public SP3_Product<FloatT> {
1748
1773
  };
1749
1774
  }
1750
1775
 
1776
+ %extend RINEX_Clock {
1777
+ %typemap(out) typename RINEX_CLK<FloatT>::satellites_t::count_t {
1778
+ %append_output(SWIG_From(int)($1.gps));
1779
+ %append_output(SWIG_From(int)($1.sbas));
1780
+ %append_output(SWIG_From(int)($1.qzss));
1781
+ %append_output(SWIG_From(int)($1.glonass));
1782
+ %append_output(SWIG_From(int)($1.galileo));
1783
+ %append_output(SWIG_From(int)($1.beidou));
1784
+ }
1785
+ }
1786
+ %inline {
1787
+ template <class FloatT>
1788
+ struct RINEX_Clock : public RINEX_CLK<FloatT>::satellites_t, PushableData {
1789
+ typedef typename RINEX_CLK<FloatT>::satellites_t super_t;
1790
+ int read(const char *fname) {
1791
+ std::fstream fin(fname, std::ios::in | std::ios::binary);
1792
+ return RINEX_CLK_Reader<FloatT>::read_all(fin, *this);
1793
+ }
1794
+ typename RINEX_CLK<FloatT>::satellites_t::count_t satellites() const {
1795
+ return RINEX_CLK<FloatT>::satellites_t::count();
1796
+ }
1797
+ bool push(GPS_Solver<FloatT> &solver, const PushableData::system_t &sys) const {
1798
+ return PushableData::push((typename RINEX_CLK<FloatT>::satellites_t &)*this, solver, sys);
1799
+ }
1800
+ bool push(GPS_Solver<FloatT> &solver) const {
1801
+ return PushableData::push((typename RINEX_CLK<FloatT>::satellites_t &)*this, solver);
1802
+ }
1803
+ FloatT clock_error(const int &sat_id, const GPS_Time<FloatT> &t) const {
1804
+ typename super_t::buf_t::const_iterator it(this->buf.find(sat_id));
1805
+ if(it == this->buf.end()){return super_t::sat_t::unavailable().clock_error(t);}
1806
+ return it->second.clock_error(t);
1807
+ }
1808
+ FloatT clock_error_dot(const int &sat_id, const GPS_Time<FloatT> &t) const {
1809
+ typename super_t::buf_t::const_iterator it(this->buf.find(sat_id));
1810
+ if(it == this->buf.end()){return super_t::sat_t::unavailable().clock_error(t);}
1811
+ return it->second.clock_error_dot(t);
1812
+ }
1813
+ };
1814
+ }
1815
+
1751
1816
  #undef MAKE_ACCESSOR
1752
1817
  #undef MAKE_VECTOR2ARRAY
1753
1818
  #undef MAKE_ARRAY_INPUT
@@ -1776,6 +1841,7 @@ struct SP3 : public SP3_Product<FloatT> {
1776
1841
 
1777
1842
  %template(RINEX_Observation) RINEX_Observation<type>;
1778
1843
  %template(SP3) SP3<type>;
1844
+ %template(RINEX_Clock) RINEX_Clock<type>;
1779
1845
  %enddef
1780
1846
 
1781
1847
  CONCRETIZE(double);
@@ -592,7 +592,6 @@ struct MatrixUtil {
592
592
  }
593
593
  static VALUE read(
594
594
  const VALUE &v, const unsigned int &row = 0, const unsigned int &column = 0) {
595
- int state;
596
595
  VALUE values[3] = {v, UINT2NUM(row), UINT2NUM(column)};
597
596
  return funcall_throw_if_error(run, reinterpret_cast<VALUE>(values));
598
597
  }
@@ -865,7 +864,7 @@ struct MatrixUtil {
865
864
  static const ID with_index[] = {
866
865
  rb_intern("map_with_index"), rb_intern("map_with_index!"),
867
866
  rb_intern("collect_with_index"), rb_intern("collect_with_index!")};
868
- for(int i(0); i < sizeof(with_index) / sizeof(with_index[0]); ++i){
867
+ for(std::size_t i(0); i < sizeof(with_index) / sizeof(with_index[0]); ++i){
869
868
  if(id_callee == with_index[i]){
870
869
  return matrix_yield_get_with_index;
871
870
  }
@@ -658,6 +658,73 @@ __ANTEX_TEXT__
658
658
  # https://files.igs.org/pub/station/general/igs14.atx
659
659
  f.path
660
660
  },
661
+ :rinex_clk => Tempfile::open{|f|
662
+ f.write(<<-__RINEX_CLK_TEXT__)
663
+ 3.00 C RINEX VERSION / TYPE
664
+ CCLOCK IGSACC @ NOAA NGS PGM / RUN BY / DATE
665
+ GPS week: 1849 Day: 2 MJD: 57189 COMMENT
666
+ THE COMBINED CLOCKS ARE A WEIGHTED AVERAGE OF: COMMENT
667
+ cod emr esa gfz grg jpl COMMENT
668
+ THE FOLLOWING REFERENCE CLOCKS WERE USED BY ACs: COMMENT
669
+ WSRT AMC2 BRUX HRAO COMMENT
670
+ THE COMBINED CLOCKS ARE ALIGNED TO GPS TIME COMMENT
671
+ USING THE SATELLITE BROADCAST EPHEMERIDES COMMENT
672
+ All clocks have been re-aligned to the IGS time scale: IGST COMMENT
673
+ 16 LEAP SECONDS
674
+ 1 AS # / TYPES OF DATA
675
+ IGS IGSACC @ NOAA NGS ANALYSIS CENTER
676
+ 6 # OF SOLN SATS
677
+ G12 G18 G24 G25 G29 G31 PRN LIST
678
+ G igs08_1848.atx SYS / PCVS APPLIED
679
+ END OF HEADER
680
+ AS G12 2015 06 15 23 45 0.000000 2 3.017937472687e-04 1.069824072610e-11
681
+ AS G18 2015 06 15 23 45 0.000000 2 4.096815344517e-04 9.225410060960e-12
682
+ AS G24 2015 06 15 23 45 0.000000 2 -4.998574751545e-05 2.372704308220e-11
683
+ AS G25 2015 06 15 23 45 0.000000 2 -2.290169594092e-06 1.683218228880e-11
684
+ AS G29 2015 06 15 23 45 0.000000 2 6.168866864097e-04 1.206217360840e-11
685
+ AS G31 2015 06 15 23 45 0.000000 2 3.128244102077e-04 2.173867579920e-11
686
+ AS G12 2015 06 15 23 50 0.000000 2 3.017948525918e-04 1.300769315700e-11
687
+ AS G18 2015 06 15 23 50 0.000000 2 4.096823340968e-04 8.242414325510e-12
688
+ AS G24 2015 06 15 23 50 0.000000 2 -4.998578937856e-05 3.095238106380e-11
689
+ AS G25 2015 06 15 23 50 0.000000 2 -2.291410963946e-06 2.242880773880e-11
690
+ AS G29 2015 06 15 23 50 0.000000 2 6.168873857128e-04 1.695910016600e-11
691
+ AS G31 2015 06 15 23 50 0.000000 2 3.128241216228e-04 1.904362802980e-11
692
+ AS G12 2015 06 15 23 55 0.000000 2 3.017958412577e-04 1.171495359430e-11
693
+ AS G18 2015 06 15 23 55 0.000000 2 4.096833491457e-04 1.008770038860e-11
694
+ AS G24 2015 06 15 23 55 0.000000 2 -4.998596967628e-05 2.600074192880e-11
695
+ AS G25 2015 06 15 23 55 0.000000 2 -2.292650290468e-06 2.671557682290e-11
696
+ AS G29 2015 06 15 23 55 0.000000 2 6.168880208367e-04 1.729095211710e-11
697
+ AS G31 2015 06 15 23 55 0.000000 2 3.128236493567e-04 1.807462018720e-11
698
+ AS G12 2015 06 16 00 00 0.000000 2 3.017967728708e-04 1.000801049580e-11
699
+ AS G18 2015 06 16 00 00 0.000000 2 4.096840539308e-04 1.041670195750e-11
700
+ AS G24 2015 06 16 00 00 0.000000 2 -4.998614775959e-05 1.699628132880e-11
701
+ AS G25 2015 06 16 00 00 0.000000 2 -2.293760646361e-06 1.805118466830e-11
702
+ AS G29 2015 06 16 00 00 0.000000 2 6.168886213338e-04 2.220055594770e-11
703
+ AS G31 2015 06 16 00 00 0.000000 2 3.128233311248e-04 1.215284180360e-11
704
+ AS G12 2015 06 16 00 05 0.000000 2 3.017980078016e-04 1.152529430320e-11
705
+ AS G18 2015 06 16 00 05 0.000000 2 4.096851745816e-04 1.517949585220e-11
706
+ AS G24 2015 06 16 00 05 0.000000 2 -4.998569129850e-05 1.987308774570e-11
707
+ AS G25 2015 06 16 00 05 0.000000 2 -2.295014987154e-06 1.568891027900e-11
708
+ AS G29 2015 06 16 00 05 0.000000 2 6.168894672506e-04 1.906237292480e-11
709
+ AS G31 2015 06 16 00 05 0.000000 2 3.128231387506e-04 1.007829428500e-11
710
+ AS G12 2015 06 16 00 10 0.000000 2 3.017987334831e-04 8.726251168980e-12
711
+ AS G18 2015 06 16 00 10 0.000000 2 4.096859333261e-04 1.403166740100e-11
712
+ AS G24 2015 06 16 00 10 0.000000 2 -4.998597422529e-05 1.727695888430e-11
713
+ AS G25 2015 06 16 00 10 0.000000 2 -2.296262879345e-06 1.460867818340e-11
714
+ AS G29 2015 06 16 00 10 0.000000 2 6.168900483001e-04 1.556536485070e-11
715
+ AS G31 2015 06 16 00 10 0.000000 2 3.128226535741e-04 1.258498073020e-11
716
+ AS G12 2015 06 16 00 15 0.000000 2 3.017999301583e-04 1.006627990480e-11
717
+ AS G18 2015 06 16 00 15 0.000000 2 4.096864636193e-04 1.460541676660e-11
718
+ AS G24 2015 06 16 00 15 0.000000 2 -4.998605241609e-05 1.970841363000e-11
719
+ AS G25 2015 06 16 00 15 0.000000 2 -2.297477664413e-06 1.598459869060e-11
720
+ AS G29 2015 06 16 00 15 0.000000 2 6.168906691983e-04 1.729396319140e-11
721
+ AS G31 2015 06 16 00 15 0.000000 2 3.128222195893e-04 1.358710059900e-11
722
+ __RINEX_CLK_TEXT__
723
+ # modified version. original data are
724
+ # https://cddis.nasa.gov/archive/gnss/products/1849/igs1849[12].clk.Z
725
+ # mirrored: ftp://garner.ucsd.edu/pub/products/1849/igs1849[12].clk.Z
726
+ f.path
727
+ },
661
728
  }}
662
729
  let(:solver){
663
730
  res = GPS::Solver::new
@@ -778,6 +845,10 @@ __ANTEX_TEXT__
778
845
 
779
846
  it 'can be modified through hooks' do
780
847
  sn = solver.gps_space_node
848
+ expect(solver.options).to be_a_kind_of(Hash)
849
+ expect(solver.options.keys).to include(:skip_exclusion)
850
+ expect{solver.options = {:skip_exclusion => true}}.not_to raise_error
851
+ expect(solver.options[:skip_exclusion]).to eq(true)
781
852
  expect(solver.correction[:gps_ionospheric]).to include(:klobuchar)
782
853
  expect(solver.correction[:gps_tropospheric]).to include(:hopfield)
783
854
  expect{solver.correction = nil}.to raise_error(RuntimeError)
@@ -937,5 +1008,55 @@ __ANTEX_TEXT__
937
1008
  puts ([:lat, :lng].collect{|f| pvt.llh.send(f) / Math::PI * 180} + [pvt.llh.alt]).inspect
938
1009
  }
939
1010
  end
1011
+ it 'calculates satellite clock error based on RINEX clock' do
1012
+ clk, sn = [GPS::RINEX_Clock::new, solver.gps_space_node]
1013
+ expect(clk.read(input[:rinex_clk])).to eq(6 * 7)
1014
+ proc{|sats|
1015
+ expect(sats.kind_of?(Array)).to eq(true)
1016
+ expect(sats[clk.class::SYS_GPS]).to eq(6)
1017
+ }.call(clk.satellites)
1018
+ sn.read(input[:rinex_nav])
1019
+ t0 = GPS::Time::new(1849, 172800)
1020
+ sn.update_all_ephemeris(t0)
1021
+ (-5..5).step(1){|dt_min|
1022
+ t = t0 + (dt_min * 60)
1023
+ [12, 18, 24, 25, 29, 31].each{|sat_id|
1024
+ eph = sn.ephemeris(sat_id).constellation(t)
1025
+ expect(clk.clock_error(sat_id, t)).to be_within(1E-7).of(eph[2]) # 100 ns
1026
+ expect(clk.clock_error_dot(sat_id, t)).to be_within(1E-10).of(eph[3]) # 100 ps
1027
+ }
1028
+ }
1029
+ end
1030
+ it 'calculates position without any error with RINEX NAV and CLK' do
1031
+ sn = solver.gps_space_node
1032
+ sn.read(input[:rinex_nav])
1033
+ clk = GPS::RINEX_Clock::new
1034
+ clk.read(input[:rinex_clk])
1035
+ expect(clk.push(solver, clk.class::SYS_GPS)).to eq(true)
1036
+ GPS::RINEX_Observation::read(input[:rinex_obs]){|item|
1037
+ t_meas = item[:time]
1038
+ sn.update_all_ephemeris(t_meas)
1039
+ meas = GPS::Measurement::new
1040
+ types = (item[:meas_types]['G'] || item[:meas_types][' ']).collect.with_index{|type_, i|
1041
+ type_ = {
1042
+ "C1" => :L1_PSEUDORANGE,
1043
+ "D1" => :L1_RANGE_RATE,
1044
+ }[type_]
1045
+ type_ && [i, GPS::Measurement::const_get(type_)]
1046
+ }.compact
1047
+ item[:meas].each{|k, v|
1048
+ sys, prn = k
1049
+ next unless sys == 'G' # GPS only
1050
+ types.each{|i, type_|
1051
+ meas.add(prn, type_, v[i][0]) if v[i]
1052
+ }
1053
+ }
1054
+ pvt = solver.solve(meas, t_meas)
1055
+ expect(pvt.position_solved?).to eq(true)
1056
+ [-3952590.4754, 3360273.8926, 3697987.2632].zip(pvt.xyz.to_a).each{|a, b|
1057
+ expect(a).to be_within(1E+2).of(b) # 10 m
1058
+ }
1059
+ }
1060
+ end
940
1061
  end
941
1062
  end
@@ -19,6 +19,7 @@ class Receiver
19
19
  opt = {
20
20
  :system => [[:GPS, 1..32]],
21
21
  :satellites => (1..32).to_a,
22
+ :FDE => true,
22
23
  }.merge(opt)
23
24
  [[
24
25
  [:week, :itow_rcv, :year, :month, :mday, :hour, :min, :sec_rcv_UTC],
@@ -106,7 +107,7 @@ class Receiver
106
107
  el_deg = [4, 6].collect{|i| pvt.elevation[fd[i]] / Math::PI * 180}
107
108
  fd[0..4] + [el_deg[0]] + fd[5..6] + [el_deg[1]]
108
109
  }
109
- ]] + [[
110
+ ]] + (opt[:FDE] ? [[
110
111
  [:wssr_FDE_min, :wssr_FDE_min_PRN, :wssr_FDE_2nd, :wssr_FDE_2nd_PRN],
111
112
  proc{|pvt|
112
113
  [:fde_min, :fde_2nd].collect{|f|
@@ -115,7 +116,7 @@ class Receiver
115
116
  [info[0], info[-3]]
116
117
  }.flatten
117
118
  }
118
- ]]
119
+ ]] : [])
119
120
  end
120
121
 
121
122
  def self.meas_items(opt = {})
@@ -153,6 +154,9 @@ class Receiver
153
154
  rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1
154
155
  rel_prop
155
156
  }
157
+ @solver.options = {
158
+ :skip_exclusion => true, # default is to skip fault exclusion calculation
159
+ }
156
160
  @debug = {}
157
161
  solver_opts = [:gps_options, :sbas_options, :glonass_options].collect{|target|
158
162
  @solver.send(target)
@@ -165,8 +169,10 @@ class Receiver
165
169
  output_options = {
166
170
  :system => [[:GPS, 1..32], [:QZSS, 193..202]],
167
171
  :satellites => (1..32).to_a + (193..202).to_a, # [idx, ...] or [[idx, label], ...] is acceptable
172
+ :FDE => false,
168
173
  }
169
174
  options = options.reject{|k, v|
175
+ def v.to_b; !(self =~ /^(?:false|0|f|off)$/i); end
170
176
  case k
171
177
  when :debug
172
178
  v = v.split(/,/)
@@ -280,6 +286,9 @@ class Receiver
280
286
  $stderr.puts "#{mode.capitalize} satellite: #{[sys, svid].compact.join(':')}"
281
287
  }
282
288
  next true
289
+ when :fault_exclusion
290
+ @solver.options = {:skip_exclusion => !(output_options[:FDE] = v.to_b)}
291
+ next true
283
292
  end
284
293
  false
285
294
  }
@@ -651,5 +660,21 @@ class Receiver
651
660
  raise "Format error! (Not ANTEX) #{src}" unless applied_items >= 0
652
661
  $stderr.puts "SP3 correction with ANTEX file (%s): %d items have been processed."%[src, applied_items]
653
662
  end
663
+
664
+ def attach_rinex_clk(src)
665
+ fname = Util::get_txt(src)
666
+ @clk ||= GPS::RINEX_Clock::new
667
+ read_items = @clk.read(fname)
668
+ raise "Format error! (Not RINEX clock) #{src}" if read_items < 0
669
+ $stderr.puts "Read RINEX clock file (%s): %d items."%[src, read_items]
670
+ sats = @clk.satellites
671
+ @clk.class.constants.each{|sys|
672
+ next unless /^SYS_(?!SYSTEMS)(.*)/ =~ sys.to_s
673
+ idx, sys_name = [@clk.class.const_get(sys), $1]
674
+ next unless sats[idx] > 0
675
+ next unless @clk.push(@solver, idx)
676
+ $stderr.puts "Change clock error source of #{sys_name} to RINEX clock"
677
+ }
678
+ end
654
679
  end
655
680
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GPS_PVT
4
- VERSION = "0.6.3"
4
+ VERSION = "0.7.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gps_pvt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - fenrir(M.Naruoka)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-19 00:00:00.000000000 Z
11
+ date: 2022-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -78,6 +78,7 @@ files:
78
78
  - ext/ninja-scan-light/tool/navigation/NTCM.h
79
79
  - ext/ninja-scan-light/tool/navigation/QZSS.h
80
80
  - ext/ninja-scan-light/tool/navigation/RINEX.h
81
+ - ext/ninja-scan-light/tool/navigation/RINEX_Clock.h
81
82
  - ext/ninja-scan-light/tool/navigation/SBAS.h
82
83
  - ext/ninja-scan-light/tool/navigation/SBAS_Solver.h
83
84
  - ext/ninja-scan-light/tool/navigation/SP3.h