diff --git a/ephemeris.cc b/ephemeris.cc index b22487f..cd11348 100644 --- a/ephemeris.cc +++ b/ephemeris.cc @@ -48,3 +48,47 @@ std::pair getLongLat(double x, double y, double z) return std::make_pair(longitude, latitude); } + + +double getElevationDeg(const Point& sat, const Point& our) +{ + + Point core{0,0,0}; + + Vector core2us(core, our); + Vector dx(our, sat); // = x-ourx, dy = y-oury, dz = z-ourz; + + // https://ds9a.nl/articles/ + + double elev = acos ( core2us.inner(dx) / (core2us.length() * dx.length())); + double deg = 180.0* (elev/M_PI); + return 90.0 - deg; +} + +// https://gis.stackexchange.com/questions/58923/calculating-view-angle + +double getAzimuthDeg(const Point& sat, const Point& our) +{ + Point core{0,0,0}; + + Vector north{ + -our.z*our.x, + -our.z*our.y, + our.x*our.x + our.y * our.y}; + + Vector east{-our.y, our.x, 0}; + + Vector dx(our, sat); // = x-ourx, dy = y-oury, dz = z-ourz; + + // https://ds9a.nl/articles/ + + double azicos = ( north.inner(dx) / (north.length() * dx.length())); + double azisin = ( east.inner(dx) / (east.length() * dx.length())); + + double azi = atan2(azisin, azicos); + + double deg = 180.0* (azi/M_PI); + if(deg < 0) + deg += 360; + return deg; +} diff --git a/ephemeris.hh b/ephemeris.hh index 64b1f19..94a96cf 100644 --- a/ephemeris.hh +++ b/ephemeris.hh @@ -5,7 +5,7 @@ int ephAge(int tow, int t0e); template -void getCoordinates(int wn, double tow, const T& iod, Point* p, bool quiet=true) +void getCoordinates(double tow, const T& iod, Point* p, bool quiet=true) { using namespace std; // here goes @@ -165,25 +165,25 @@ struct DopplerData }; template -void getSpeed(int wn, double tow, const T& eph, Vector* v) +void getSpeed(double tow, const T& eph, Vector* v) { Point a, b; - getCoordinates(wn, tow-0.5, eph, &a); - getCoordinates(wn, tow+0.5, eph, &b); + getCoordinates(tow-0.5, eph, &a); + getCoordinates(tow+0.5, eph, &b); *v = Vector(a, b); } template -DopplerData doDoppler(int wn, int tow, const Point& us, const T& eph, double freq) +DopplerData doDoppler(double tow, const Point& us, const T& eph, double freq) { DopplerData ret; // be careful with time here - we need to evaluate at the timestamp of this RFDataType update // which might be newer than .tow in g_svstats - getCoordinates(wn, tow, eph, &ret.sat); + getCoordinates(tow, eph, &ret.sat); Point core; Vector us2sat(us, ret.sat); - getSpeed(wn, tow, eph, &ret.speed); + getSpeed(tow, eph, &ret.speed); Vector core2us(core, us); Vector dx(us, ret.sat); // = x-ourx, dy = y-oury, dz = z-ourz; @@ -201,3 +201,5 @@ DopplerData doDoppler(int wn, int tow, const Point& us, const T& eph, double fre } std::pair getLongLat(double x, double y, double z); +double getElevationDeg(const Point& sat, const Point& our); +double getAzimuthDeg(const Point& sat, const Point& our); diff --git a/html/almanac.js b/html/almanac.js index ceeaa32..3dec536 100644 --- a/html/almanac.js +++ b/html/almanac.js @@ -14,7 +14,7 @@ function maketable(str, arr) enter(). append("tr"); - var columns = ["sv", "best-tle", "best-tle-dist", "best-tle-norad", "best-tle-int-desig", "e1bhs", "e5bhs", "health", "inclination", "eph-ecefX", "eph-ecefY", "eph-ecefZ", "tle-ecefX", "tle-ecefY", "tle-ecefZ", "eph-latitude", "eph-longitude", "tle-latitude", "tle-longitude", "t0e", "t"]; // , "tle-eciX", "tle-eciY", "tle-eciZ" + var columns = ["sv", "best-tle", "best-tle-dist", "best-tle-norad", "best-tle-int-desig", "eph-ecefX", "eph-ecefY", "eph-ecefZ", "tle-ecefX", "tle-ecefY", "tle-ecefZ", "eph-latitude", "eph-longitude", "tle-latitude", "tle-longitude", "tle-eciX", "tle-eciY", "tle-eciZ", "t0e", "t"]; // append the header row thead.append("tr") @@ -23,10 +23,8 @@ function maketable(str, arr) .enter() .append("th") .text(function(column) { - if(column == "best-tle-dist") - return "tle-dist"; - if(column == "best-tle-int-desig") - return "int-desig"; + if(column == "delta_hz_corr") + return "ΔHz"; else return column; }); @@ -37,9 +35,7 @@ function maketable(str, arr) var ret={}; ret.column = column; ret.color=null; - if(row[column] != null && column != "sv" && column != "best-tle" && - column != "best-tle-norad" && column != "best-tle-int-desig" && column != "e1bhs" && - column != "e5bhs" && column!="health") + if(row[column] != null && column != "sv" && column != "best-tle" && column != "best-tle-norad" && column != "best-tle-int-desig") ret.value = row[column].toFixed(1); else ret.value = row[column]; @@ -90,6 +86,9 @@ function update() var livearr=[]; for(n = 0 ; n < arr.length; n++) { + if(arr[n].sv[0]!='G') + continue; + livearr.push(arr[n]); } diff --git a/html/doalles.js b/html/doalles.js index 5102cac..bd73606 100644 --- a/html/doalles.js +++ b/html/doalles.js @@ -200,6 +200,7 @@ function update() var livearr=[], stalearr=[]; for(n = 0 ; n < arr.length; n++) { +// if(arr[n]["gnssid"]) continue; if(arr[n]["last-seen-s"] < 600) livearr.push(arr[n]); else @@ -212,6 +213,6 @@ function update() }); } -update(); +repeat=update(); diff --git a/html/geo/geo.js b/html/geo/geo.js index 7777e71..1f1354d 100644 --- a/html/geo/geo.js +++ b/html/geo/geo.js @@ -80,7 +80,8 @@ function update() .attr("cx", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[0]) .attr("cy", d => aProjection([d["eph-longitude"],d["eph-latitude"]])[1]) .attr("fill", function(d) { if(d.gnssid==2) return "blue"; - if(d.gnssid==3) return "red"; + else if(d.gnssid==3) return "red"; + else if(d.gnssid==6) return "yellow"; else return "green"; }); svg.selectAll("text").data(arr) @@ -88,7 +89,9 @@ function update() .append("text") .attr("dx", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[0]) .attr("dy", d => 5+aProjection([d["eph-longitude"],d["eph-latitude"]])[1]) - .text(d => d.sv); + .text(d => d.sv) + .attr("fill", function(d) { if(d.observed==true) return "black"; return "#666666"; }) + .attr("font-weight", function(d) { if(d.observed==true) return "bold"; return null; }); svg.selectAll("rect").data(results[1]) .enter() diff --git a/navdump.cc b/navdump.cc index bed8234..8a38840 100644 --- a/navdump.cc +++ b/navdump.cc @@ -26,6 +26,8 @@ #include using namespace std; +Point g_ourpos; + string beidouHealth(int in) { string ret; @@ -108,7 +110,7 @@ try cout< oldgs1s; gpswn = gs.wn; @@ -218,20 +221,21 @@ try cout <<"iod "<= 25 && gs.gpsalma.sv <= 32) || gs.gpsalma.sv==57 ) { // see table 20-V of the GPS ICD cout << " data-id "< using namespace std; -std::map g_srcpos; +struct ObserverPosition +{ + Point pos; + time_t lastSeen{0}; +}; +std::map g_srcpos; template class GetterSetter @@ -399,16 +404,27 @@ void SVStat::addGalileoWord(std::basic_string_view page) } } -typedef std::map, SVStat> svstats_t; +struct SatID +{ + uint32_t gnss{255}; // these could all be 'int16_t' but leads to howling numbers of warnings with protobuf + uint32_t sv{0}; + uint32_t sigid{0}; + bool operator<(const SatID& rhs) const + { + return tie(gnss, sv, sigid) < tie(rhs.gnss, rhs.sv, rhs.sigid); + } +}; + +typedef std::map svstats_t; svstats_t g_svstats; -GetterSetter, SVStat>> g_statskeeper; +GetterSetter g_statskeeper; int latestWN(int gnssid, const svstats_t& stats) { - map> ages; + map ages; for(const auto& s: stats) - if(s.first.first == gnssid) + if(s.first.gnss == (unsigned int)gnssid) ages[7*s.second.wn*86400 + s.second.tow]= s.first; if(ages.empty()) throw runtime_error("Asked for latest WN for "+to_string(gnssid)+": we don't know it yet"); @@ -418,9 +434,9 @@ int latestWN(int gnssid, const svstats_t& stats) int latestTow(int gnssid, const svstats_t& stats) { - map> ages; + map ages; for(const auto& s: stats) - if(s.first.first == gnssid) + if(s.first.gnss == (unsigned int) gnssid) ages[7*s.second.wn*86400 + s.second.tow]= s.first; if(ages.empty()) throw runtime_error("Asked for latest TOW for "+to_string(gnssid)+": we don't know it yet"); @@ -428,7 +444,7 @@ int latestTow(int gnssid, const svstats_t& stats) } -uint64_t nanoTime(int gnssid, int wn, int tow) +int64_t nanoTime(int gnssid, int wn, double tow) { int offset; if(gnssid == 0) // GPS @@ -460,33 +476,89 @@ struct InfluxPusher } template - void addValue( const pair,SVStat>& ent, string_view name, const T& value) + void addValue( const pair& ent, string_view name, const T& value) { if(d_mute) return; - d_buffer+= string(name)+",gnssid="+to_string(ent.first.first)+ +",sv=" +to_string(ent.first.second)+" value="+to_string(value)+ - " "+to_string(nanoTime(ent.first.first, ent.second.wn, ent.second.tow))+"\n"; + if(nanoTime (ent.first.gnss, ent.second.wn, ent.second.tow)/1000000000 > 2000000000) { + cerr<<"Unable to store item "< - void addValue(pair id, string_view name, const T& value, std::optional src = std::optional()) + void addValueObserver(int src, string_view name, const T& value, time_t t) + { + if(d_mute) + return; + d_buffer+= string(name)+",src="+to_string(src)+ " value="+to_string(value)+ + " "+to_string(t*1000000000)+"\n"; + checkSend(); + } + + + template + void addValue(const SatID& id, string_view name, const T& value, std::optional src = std::optional()) { if(d_mute) return; + if(nanoTime (id.gnss, g_svstats[id].wn, g_svstats[id].tow)/1000000000 > 2000000000) { + cerr<<"Unable to store item "< " <>& values, std::optional src = std::optional()) + { + if(d_mute) + return; + + if(nanotime/1000000000 > 2000000000) { + cerr<<"Unable to store item "< 1000000 || (time(0) - d_lastsent) > 10) { @@ -546,11 +618,11 @@ std::optional getHzCorrection(time_t now, const svstats_t svstats) if(now - s.second.deltaHz.first < 60) { alltot+=s.second.deltaHz.second; allcount++; - if(s.first.first == 0) { + if(s.first.gnss == 0) { gpstot+=s.second.deltaHz.second; gpscount++; } - else if(s.first.first == 2) { + else if(s.first.gnss == 2 && s.first.sigid == 1) { // focus on E1 galtot+=s.second.deltaHz.second; galcount++; } @@ -583,20 +655,6 @@ char getGNSSChar(int id) return '0'+id; } -double getElevationDeg(const Point& p, int sourceid) -{ - Point our = g_srcpos[sourceid]; - Point core{0,0,0}; - - Vector core2us(core, our); - Vector dx(our, p); // = x-ourx, dy = y-oury, dz = z-ourz; - - // https://ds9a.nl/articles/ - - double elev = acos ( core2us.inner(dx) / (core2us.length() * dx.length())); - double deg = 180.0* (elev/M_PI); - return 90.0 - deg; -} std::string humanBhs(int bhs) { @@ -631,7 +689,7 @@ try catch(...) {} - map utcstats, gpsgststats, gpsutcstats; + map utcstats, gpsgststats, gpsutcstats; for(const auto& s: svstats) { if(!s.second.wn) // this will suck in 20 years @@ -640,41 +698,40 @@ try //Galileo-UTC offset: 3.22 ns, Galileo-GPS offset: 7.67 ns, 18 leap seconds - if(s.first.first == 0) { // GPS - int sv = s.first.second; - int dw = (uint8_t)svstats[{0,sv}].wn - svstats[{0,sv}].wn0t; - int age = dw * 7 * 86400 + svstats[{0,sv}].tow - svstats[{0,sv}].t0t; // t0t is PRESCALED + if(s.first.gnss == 0) { // GPS + int dw = (uint8_t)s.second.wn - s.second.wn0t; + int age = dw * 7 * 86400 + s.second.tow - s.second.t0t; // t0t is PRESCALED // XXX changed this, - gpsutcstats[age]=s.first.second; + gpsutcstats[age]=s.first; continue; } int dw = (uint8_t)s.second.wn - s.second.wn0t; int age = dw * 7 * 86400 + s.second.tow - s.second.t0t; // t0t is pre-scaled - utcstats[age]=s.first.second; + utcstats[age]=s.first; uint8_t wn0g = s.second.wn0t; int dwg = (((uint8_t)s.second.wn)&(1+2+4+8+16+32)) - wn0g; age = dwg*7*86400 + s.second.tow - s.second.t0g * 3600; - gpsgststats[age]=s.first.second; + gpsgststats[age]=s.first; } if(utcstats.empty()) { ret["utc-offset-ns"]=nullptr; } else { - int sv = utcstats.begin()->second; // freshest SV - long shift = svstats[{2,sv}].a0 * (1LL<<20) + svstats[{2,sv}].a1 * utcstats.begin()->first; // in 2^-50 seconds units + auto satid = utcstats.begin()->second; // freshest SV + long shift = svstats[{2,satid.sv,satid.sigid}].a0 * (1LL<<20) + svstats[{2,satid.sv,satid.sigid}].a1 * utcstats.begin()->first; // in 2^-50 seconds units ret["utc-offset-ns"] = 1.073741824*ldexp(1.0*shift, -20); - ret["leap-second-planned"] = (svstats[{2,sv}].dtLSF != svstats[{2,sv}].dtLS); + ret["leap-second-planned"] = (svstats[satid].dtLSF != svstats[satid].dtLS); } if(gpsgststats.empty()) { ret["gps-offset-ns"]=nullptr; } else { - int sv = gpsgststats.begin()->second; // freshest SV - long shift = svstats[{2,sv}].a0g * (1L<<16) + svstats[{2,sv}].a1g * gpsgststats.begin()->first; // in 2^-51 seconds units + auto satid = gpsgststats.begin()->second; // freshest SV + long shift = svstats[{2,satid.sv, satid.sigid}].a0g * (1L<<16) + svstats[{2,satid.sv, satid.sigid}].a1g * gpsgststats.begin()->first; // in 2^-51 seconds units ret["gps-offset-ns"] = 1.073741824*ldexp(shift, -21); } @@ -683,8 +740,8 @@ try ret["gps-utc-offset-ns"]=nullptr; } else { - int sv = gpsutcstats.begin()->second; // freshest SV - long shift = svstats[{0,sv}].a0 * (1LL<<20) + svstats[{0,sv}].a1 * gpsutcstats.begin()->first; // In 2^-50 seconds units + auto satid = gpsutcstats.begin()->second; // freshest SV + long shift = svstats[{0,satid.sv,satid.sigid}].a0 * (1LL<<20) + svstats[{0,satid.sv,satid.sigid}].a1 * gpsutcstats.begin()->first; // In 2^-50 seconds units ret["gps-utc-offset-ns"] = 1.073741824*ldexp(shift, -20); } @@ -705,7 +762,7 @@ try if(ae.second.alma.getT0e() > 7*86400) continue; Point sat; - getCoordinates(0, latestTow(3, svstats), ae.second.alma, &sat); + getCoordinates(latestTow(3, svstats), ae.second.alma, &sat); item["eph-ecefX"]= sat.x/1000; item["eph-ecefY"]= sat.y/1000; item["eph-ecefZ"]= sat.z/1000; @@ -716,6 +773,13 @@ try item["t0e"] = ae.second.alma.getT0e(); item["t"]= ephAge(ae.second.alma.getT0e(), latestTow(3, svstats))/86400.0; item["inclination"] = 180 * ae.second.alma.getI0() /M_PI; + + item["observed"]=false; + if(auto iter = svstats.find({3, (uint32_t)ae.first, 0}); iter != svstats.end()) { + if(time(0) - nanoTime(3, iter->second.wn, iter->second.tow)/1000000000 < 300) + item["observed"] = true; + } + if(ephAge(ae.second.alma.getT0e(), latestTow(3, svstats)) < 0) { auto match = g_tles.getBestMatch(nanoTime(3, latestWN(3, svstats), latestTow(3, svstats))/1000000000.0, sat.x, sat.y, sat.z); @@ -756,6 +820,22 @@ try item["lambdana"] = ae.second.second.getLambdaNaDeg(); item["hna"] = ae.second.second.hna; + item["observed"] = false; + for(uint32_t sigid : {0,1,2}) { // XXX SIGIDS + if(auto iter = svstats.find({6, (uint32_t)ae.first, sigid}); iter != svstats.end()) { + if(time(0) - nanoTime(6, iter->second.wn, iter->second.tow)/1000000000 < 300) { + item["observed"] = true; + auto longlat = getLongLat(iter->second.glonassMessage.x, iter->second.glonassMessage.y, iter->second.glonassMessage.z); + item["eph-longitude"] = 180*longlat.first/M_PI; + item["eph-latitude"]= 180*longlat.second/M_PI; + break; + } + + } + } + + + ret[fmt::sprintf("R%02d", ae.first)] = item; } @@ -772,7 +852,7 @@ try item["i0"] = 180.0 * ae.second.getI0()/ M_PI; item["inclination"] = 180 * ae.second.getI0() /M_PI; Point sat; - getCoordinates(0, latestTow(2, svstats), ae.second, &sat); + getCoordinates(latestTow(2, svstats), ae.second, &sat); item["eph-ecefX"]= sat.x/1000; item["eph-ecefY"]= sat.y/1000; item["eph-ecefZ"]= sat.z/1000; @@ -781,6 +861,16 @@ try item["eph-longitude"] = 180*longlat.first/M_PI; item["eph-latitude"]= 180*longlat.second/M_PI; + + item["observed"] = false; + for(uint32_t sigid : {0,1,5}) { + if(auto iter = svstats.find({2, (uint32_t)ae.first, sigid}); iter != svstats.end()) { + if(time(0) - nanoTime(2, iter->second.wn, iter->second.tow)/1000000000 < 300) + item["observed"] = true; + } + } + + auto match = g_tles.getBestMatch(nanoTime(2, latestWN(2, svstats), latestTow(2, svstats))/1000000000.0, sat.x, sat.y, sat.z); @@ -817,7 +907,7 @@ try item["i0"] = 180.0 * ae.second.getI0()/ M_PI; item["inclination"] = 180 * ae.second.getI0() /M_PI; Point sat; - getCoordinates(0, latestTow(0, svstats), ae.second, &sat); + getCoordinates(latestTow(0, svstats), ae.second, &sat); item["eph-ecefX"]= sat.x/1000; item["eph-ecefY"]= sat.y/1000; item["eph-ecefZ"]= sat.z/1000; @@ -826,6 +916,15 @@ try item["eph-longitude"] = 180*longlat.first/M_PI; item["eph-latitude"]= 180*longlat.second/M_PI; + item["observed"] = false; + for(uint32_t sigid : {0,1,4}) { + if(auto iter = svstats.find({0, (uint32_t)ae.first, sigid}); iter != svstats.end()) { + if(time(0) - nanoTime(0, iter->second.wn, iter->second.tow)/1000000000 < 300) + item["observed"] = true; + } + } + + auto match = g_tles.getBestMatch(nanoTime(0, latestWN(0, svstats), latestTow(0, svstats))/1000000000.0, sat.x, sat.y, sat.z); @@ -858,13 +957,14 @@ try for(const auto& src : g_srcpos) { nlohmann::json obj; obj["id"] = src.first; - auto longlat = getLongLat(src.second.x, src.second.y, src.second.z); + auto longlat = getLongLat(src.second.pos.x, src.second.pos.y, src.second.pos.z); longlat.first *= 180.0/M_PI; longlat.second *= 180.0/M_PI; longlat.first = ((int)(10*longlat.first))/10.0; longlat.second = ((int)(10*longlat.second))/10.0; obj["longitude"] = longlat.first; obj["latitude"] = longlat.second; + obj["last-seen"] = src.second.lastSeen; ret.push_back(obj); } return ret; @@ -881,11 +981,12 @@ try if(!s.second.tow) // I know, I know, will suck briefly continue; - item["gnssid"] = s.first.first; - item["svid"] = s.first.second; + item["gnssid"] = s.first.gnss; + item["svid"] = s.first.sv; + item["sigid"] = s.first.sigid; // perhaps check oldBeidouMessage for sow >=0 as 'completeIOD'? - if(s.first.first == 3) { // beidou + if(s.first.gnss == 3) { // beidou item["sisa"]=humanUra(s.second.ura); if(s.second.t0eMSB >= 0 && s.second.t0eLSB >=0) item["eph-age-m"] = ephAge(s.second.tow, 8.0*((s.second.t0eMSB<<15) + s.second.t0eLSB))/60.0; @@ -902,15 +1003,15 @@ try item["best-tle-int-desig"] = s.second.tleMatch.internat; } Point p; - getCoordinates(0, s.second.tow, s.second.oldBeidouMessage, &p); + getCoordinates(s.second.tow, s.second.oldBeidouMessage, &p); auto beidoualma = g_beidoualmakeeper.get(); - if(auto iter = beidoualma.find(s.first.second); iter != beidoualma.end()) { + if(auto iter = beidoualma.find(s.first.sv); iter != beidoualma.end()) { Point almapos; - getCoordinates(0, s.second.tow, iter->second.alma, &almapos); + getCoordinates(s.second.tow, iter->second.alma, &almapos); item["alma-dist"] = Vector(almapos, p).length()/1000.0; } } - else if(s.first.first == 6) { // glonass + else if(s.first.gnss == 6) { // glonass if(s.second.glonassMessage.FT < 16) item["sisa"] = humanFt(s.second.glonassMessage.FT); item["aode"] = s.second.aode; @@ -933,7 +1034,7 @@ try } if(s.second.completeIOD()) { item["iod"]=s.second.getIOD(); - if(s.first.first == 0 || s.first.first == 3) { + if(s.first.gnss == 0 || s.first.gnss == 3) { item["sisa"]=humanUra(s.second.ura); // cout<<"Asked to convert "<second, &almapos); + getCoordinates(s.second.tow, iter->second, &almapos); item["alma-dist"] = Vector(almapos, p).length()/1000.0; } } - if(s.first.first == 2) { + if(s.first.gnss == 2) { auto galileoalma = g_galileoalmakeeper.get(); - if(auto iter = galileoalma.find(s.first.second); iter != galileoalma.end()) { + if(auto iter = galileoalma.find(s.first.sv); iter != galileoalma.end()) { Point almapos; - getCoordinates(0, s.second.tow, iter->second, &almapos); + getCoordinates(s.second.tow, iter->second, &almapos); item["alma-dist"] = Vector(almapos, p).length()/1000.0; } } @@ -993,13 +1094,13 @@ try item["a0"]=s.second.a0; item["a1"]=s.second.a1; - if(s.first.first == 0) { // GPS + if(s.first.gnss == 0) { // GPS auto deltaUTC = getGPSUTCOffset(s.second.tow, s.second.wn, s.second); item["delta-utc"] = fmt::sprintf("%.1f %+.1f/d", deltaUTC.first, deltaUTC.second * 86400); item["t0t"] = s.second.t0t; item["wn0t"] = s.second.wn0t; } - if(s.first.first == 2) { + if(s.first.gnss == 2) { auto deltaUTC = s.second.galmsg.getUTCOffset(s.second.tow, s.second.wn); item["delta-utc"] = fmt::sprintf("%.1f %+.1f/d", deltaUTC.first, deltaUTC.second * 86400); auto deltaGPS = s.second.galmsg.getGPSOffset(s.second.tow, s.second.wn); @@ -1007,7 +1108,7 @@ try item["t0t"] = s.second.galmsg.t0t; item["wn0t"] = s.second.galmsg.wn0t; } - if(s.first.first == 3) { + if(s.first.gnss == 3) { auto deltaUTC = s.second.oldBeidouMessage.getUTCOffset(s.second.oldBeidouMessage.sow); item["delta-utc"] = fmt::sprintf("%.1f %+.1f/d", deltaUTC.first, deltaUTC.second * 86400); @@ -1024,7 +1125,7 @@ try item["dtLS"]=s.second.dtLS; - if(s.first.first == 3) { // beidou + if(s.first.gnss == 3) { // beidou item["a0g"]=s.second.a0g; item["a1g"]=s.second.a1g; if(s.second.aode >= 0) @@ -1035,7 +1136,7 @@ try } - if(s.first.first == 2) { // galileo + if(s.first.gnss == 2) { // galileo item["a0g"]=s.second.a0g; item["a1g"]=s.second.a1g; item["t0g"]=s.second.t0g; @@ -1059,23 +1160,25 @@ try item["healthissue"] = 2; } - else if(s.first.first == 0 || s.first.first == 3 || s.first.first == 6) {// gps or beidou or GLONASS + else if(s.first.gnss == 0 || s.first.gnss == 3 || s.first.gnss == 6) {// gps or beidou or GLONASS item["health"]= s.second.gpshealth ? ("NOT OK: "+to_string(s.second.gpshealth)) : string("OK"); item["healthissue"]= 2* !!s.second.gpshealth; } nlohmann::json perrecv = nlohmann::json::object(); for(const auto& pr : s.second.perrecv) { - if(pr.second.el > 0 && pr.second.el <= 90) { + if(pr.second.db > 0) { nlohmann::json det = nlohmann::json::object(); det["elev"] = pr.second.el; Point sat; - if((s.first.first == 0 || s.first.first == 2) && s.second.completeIOD()) - getCoordinates(0, latestTow(s.first.first, svstats), s.second.liveIOD(), & sat); + if((s.first.gnss == 0 || s.first.gnss == 2) && s.second.completeIOD()) + getCoordinates(latestTow(s.first.gnss, svstats), s.second.liveIOD(), & sat); if(sat.x) { - det["elev"] = getElevationDeg(sat, pr.first); + Point our = g_srcpos[pr.first].pos; + det["elev"] = getElevationDeg(sat, our); + det["azi"] = getAzimuthDeg(sat, our); } else det["elev"] = pr.second.el; @@ -1087,7 +1190,8 @@ try } item["perrecv"]=perrecv; - item["last-seen-s"] = time(0) - nanoTime(s.first.first, s.second.wn, s.second.tow)/1000000000; + item["last-seen-s"] = time(0) - nanoTime(s.first.gnss, s.second.wn, s.second.tow)/1000000000; + if(s.second.latestDisco >=0) { item["latest-disco"]= s.second.latestDisco; } @@ -1098,7 +1202,7 @@ try item["wn"] = s.second.wn; item["tow"] = s.second.tow; - ret[fmt::sprintf("%c%02d", getGNSSChar(s.first.first), s.first.second)] = item; + ret[fmt::sprintf("%c%02d@%d", getGNSSChar(s.first.gnss), s.first.sv, s.first.sigid)] = item; } return ret; }); @@ -1144,22 +1248,43 @@ try if(nmm.type() == NavMonMessage::ReceptionDataType) { int gnssid = nmm.rd().gnssid(); int sv = nmm.rd().gnsssv(); - pair id{gnssid, sv}; + int sigid = nmm.rd().sigid(); + if(gnssid==2 && sigid == 0) + sigid = 1; + + SatID id{(uint32_t)gnssid, (uint32_t)sv, (uint32_t)sigid}; g_svstats[id].perrecv[nmm.sourceid()].db = nmm.rd().db(); g_svstats[id].perrecv[nmm.sourceid()].el = nmm.rd().el(); g_svstats[id].perrecv[nmm.sourceid()].azi = nmm.rd().azi(); - // THIS HAS TO SPLIT OUT PER SOURCE - idb.addValue(id, "db", nmm.rd().db(), nmm.sourceid()); - if(nmm.rd().el() <= 90 && nmm.rd().el() > 0) - idb.addValue(id, "elev", nmm.rd().el(), nmm.sourceid()); - idb.addValue(id, "azi", nmm.rd().azi(), nmm.sourceid()); - idb.addValue(id, "prres", nmm.rd().prres(), nmm.sourceid()); + Point sat{0,0,0}; + //cout<<"Got recdata for "< inav((uint8_t*)nmm.gi().contents().c_str(), nmm.gi().contents().size()); int sv = nmm.gi().gnsssv(); - pair id={2,sv}; + int sigid; + if(nmm.gi().has_sigid()) + sigid = nmm.gi().sigid(); + else + sigid = 1; // default to E1B + SatID id={2,(uint32_t)sv,(uint32_t)sigid}; g_svstats[id].wn = nmm.gi().gnsswn(); auto& svstat = g_svstats[id]; auto oldgm = svstat.galmsg; @@ -1175,7 +1300,7 @@ try const auto& old5gm = svstat.galmsgTyped[5]; if(make_tuple(old5gm.e5bhs, old5gm.e1bhs, old5gm.e5bdvs, old5gm.e1bdvs) != make_tuple(gm.e5bhs, gm.e1bhs, gm.e5bdvs, gm.e1bdvs)) { - cout< ["<< humanBhs(gm.e5bhs)<<", "<< humanBhs(gm.e1bhs)<<", "<< (int)gm.e5bdvs <<", " << (int)gm.e1bdvs<<"], lastseen "< ["<< humanBhs(gm.e5bhs)<<", "<< humanBhs(gm.e1bhs)<<", "<< (int)gm.e5bdvs <<", " << (int)gm.e1bdvs<<"], lastseen "< id{nmm.rfd().gnssid(), nmm.rfd().gnsssv()}; - if(id.first == 3 && g_svstats[id].oldBeidouMessage.sow >= 0 && g_svstats[id].oldBeidouMessage.sqrtA != 0) { - auto res = doDoppler(nmm.rfd().rcvwn(), nmm.rfd().rcvtow(), g_srcpos[nmm.sourceid()], g_svstats[id].oldBeidouMessage, 1561.098 * 1000000); + SatID id{nmm.rfd().gnssid(), nmm.rfd().gnsssv(), nmm.rfd().sigid()}; + idb.addValue(id, nanoTime(0, nmm.rfd().rcvwn(), nmm.rfd().rcvtow()), "rfdata", + {{"carrierphase", nmm.rfd().carrierphase()}, + {"doppler", nmm.rfd().doppler()}, + {"locktime", nmm.rfd().locktimems()}, + {"pseudorange", nmm.rfd().pseudorange()}}); + if(id.gnss == 3 && g_svstats[id].oldBeidouMessage.sow >= 0 && g_svstats[id].oldBeidouMessage.sqrtA != 0) { + auto res = doDoppler(nmm.rfd().rcvtow(), g_srcpos[nmm.sourceid()].pos, g_svstats[id].oldBeidouMessage, 1561.098 * 1000000); if(isnan(res.preddop)) { - cerr<<"Problem with doppler calculation for C"< 10) { @@ -1381,8 +1524,12 @@ try } } else if(nmm.type()== NavMonMessage::GPSInavType) { + if(nmm.gpsi().sigid()) { + cout<<"ignoring sigid "<((uint8_t*)nmm.gpsi().contents().c_str(), nmm.gpsi().contents().size())); - pair id{nmm.gpsi().gnssid(), nmm.gpsi().gnsssv()}; + SatID id{nmm.gpsi().gnssid(), nmm.gpsi().gnsssv(), nmm.gpsi().sigid()}; g_svstats[id].perrecv[nmm.sourceid()].t = nmm.localutcseconds(); @@ -1399,11 +1546,11 @@ try idb.addValue(id, "ura", svstat.ura); if(oldsvstat.af0 && oldsvstat.ura != svstat.ura && svstat.ura > 1) { // XX find better way to check - cout< [" << humanUra(svstat.ura)<<"] "<<(int)svstat.ura<<", lastseen "< [" << humanUra(svstat.ura)<<"] "<<(int)svstat.ura<<", lastseen "< [" << (int)svstat.gpshealth <<"], lastseen "< [" << (int)svstat.gpshealth <<"], lastseen "< ["<< (int)svstat.gpshealth<<"] , lastseen "< ["<< (int)svstat.gpshealth<<"] , lastseen "< id{nmm.bid1().gnssid(), nmm.bid1().gnsssv()}; + SatID id{nmm.bid1().gnssid(), nmm.bid1().gnsssv(), nmm.bid1().sigid()}; g_svstats[id].perrecv[nmm.sourceid()].t = nmm.localutcseconds(); @@ -1466,7 +1613,7 @@ try svstat.aodc = bm.aodc; if(oldbm.sath1 != bm.sath1) { - cout<= 0) { - getCoordinates(svstat.wn, svstat.tow, bm, &newpoint); + getCoordinates(svstat.tow, bm, &newpoint); if(fabs(svstat.lastTLELookupX - newpoint.x) > 300000) { // cout<<"fraid 3 lookup, delta " << fabs(svstat.lastTLELookupX - newpoint.x) << endl; @@ -1501,7 +1648,7 @@ try } if(svstat.oldBeidouMessage.getT0e() != svstat.beidouMessage.getT0e()) { - getCoordinates(svstat.wn, svstat.tow, svstat.oldBeidouMessage, &oldpoint); + getCoordinates(svstat.tow, svstat.oldBeidouMessage, &oldpoint); Vector jump(oldpoint ,newpoint); /* cout< (%f, %f, %f), jump: %f, seconds: %f\n", id.second, oldpoint.x, oldpoint.y, oldpoint.z, @@ -1559,7 +1706,7 @@ try */ } else if(nmm.type()== NavMonMessage::GlonassInavType) { - pair id{nmm.gloi().gnssid(), nmm.gloi().gnsssv()}; + SatID id{nmm.gloi().gnssid(), nmm.gloi().gnsssv(), nmm.gloi().sigid()}; auto& svstat = g_svstats[id]; auto& gm = svstat.glonassMessage; @@ -1574,7 +1721,7 @@ try } else if(strno == 2) { if(oldgm.Bn != gm.Bn) { - cout< %.4f or %d:%f -> delta = %.4fs\n", tm.tm_hour, tm.tm_min, seconds, ourutc, timestamp.tv_sec, 1.0*timestamp.tv_usec, ourutc - satutc); } } - else if(msg.getClass() == 0x02 && msg.getType() == 0x15) { // RAWX + else if(msg.getClass() == 0x02 && msg.getType() == 0x15) { // RAWX, the doppler stuff // cerr<<"Got "<<(int)payload[11] <<" measurements "<set_gnssid(gnssid); nmm.mutable_rfd()->set_gnsssv(sv); + nmm.mutable_rfd()->set_sigid(sigid); nmm.mutable_rfd()->set_rcvtow(rcvTow); nmm.mutable_rfd()->set_rcvwn(rcvWn); nmm.mutable_rfd()->set_doppler(doppler); @@ -655,7 +683,7 @@ int main(int argc, char** argv) nmm.mutable_op()->set_x(p.ecefX /100.0); nmm.mutable_op()->set_y(p.ecefY /100.0); nmm.mutable_op()->set_z(p.ecefZ /100.0); - nmm.mutable_op()->set_acccm(p.pAcc /100.0); + nmm.mutable_op()->set_acc(p.pAcc /100.0); emitNMM(1, nmm); } else if(msg.getClass() == 2 && msg.getType() == 0x13) { // SFRBX @@ -666,21 +694,22 @@ int main(int argc, char** argv) try { pair id = make_pair(payload[0], payload[1]); - static set> svseen; + int sigid = payload[2]; + static set> svseen; static time_t lastStat; - svseen.insert(id); + svseen.insert({id.first, id.second, payload[2]}); if(time(0)- lastStat > 30) { cerr<<"src "<(s)<<","<(s)<<"@"<(s)<<" "; } cerr<set_gnsswn(wn); // XXX this sucks + nmm.mutable_gpsi()->set_sigid(sigid); nmm.mutable_gpsi()->set_gnsstow(tow); // "with 6 second increments" -- needs to be adjusted nmm.mutable_gpsi()->set_gnssid(id.first); nmm.mutable_gpsi()->set_gnsssv(id.second); @@ -706,6 +736,8 @@ int main(int argc, char** argv) continue; } else if(id.first ==2) { + // cerr<<"gal nav sv "<set_gnsswn(g_wn); + nmm.mutable_gi()->set_gnsstow(msgTOW); nmm.mutable_gi()->set_gnssid(id.first); nmm.mutable_gi()->set_gnsssv(id.second); + nmm.mutable_gi()->set_sigid(sigid); nmm.mutable_gi()->set_contents((const char*)&inav[0], inav.size()); emitNMM(1, nmm); @@ -771,7 +805,7 @@ int main(int argc, char** argv) bm.parse(cond, &pageno); if(bm.wn < 0) { - cerr<<"BeiDou C"<set_gnsstow(bm.sow); nmm.mutable_bid1()->set_gnssid(id.first); nmm.mutable_bid1()->set_gnsssv(id.second); + nmm.mutable_bid1()->set_sigid(sigid); nmm.mutable_bid1()->set_contents(string((char*)gstr.c_str(), gstr.size())); } else { @@ -793,6 +828,7 @@ int main(int argc, char** argv) nmm.mutable_bid2()->set_gnsstow(bm.sow); nmm.mutable_bid2()->set_gnssid(id.first); nmm.mutable_bid2()->set_gnsssv(id.second); + nmm.mutable_bid2()->set_sigid(sigid); nmm.mutable_bid2()->set_contents(string((char*)gstr.c_str(), gstr.size())); } emitNMM(1, nmm); @@ -815,12 +851,14 @@ int main(int argc, char** argv) nmm.mutable_gloi()->set_freq(payload[3]); nmm.mutable_gloi()->set_gnssid(id.first); nmm.mutable_gloi()->set_gnsssv(id.second); + nmm.mutable_gloi()->set_sigid(sigid); nmm.mutable_gloi()->set_contents(string((char*)gstr.c_str(), gstr.size())); + emitNMM(1, nmm); } } else - cerr<<"SFRBX from unsupported GNSSID "<set_gnssid(gnssid); + nmm.mutable_rd()->set_gnsssv(sv); + nmm.mutable_rd()->set_db(db); + nmm.mutable_rd()->set_prres(*((int16_t*)(payload.c_str()+ 12 +16*n)) *0.1); // ENDIANISM + nmm.mutable_rd()->set_sigid(sigid); + nmm.mutable_rd()->set_el(0); + nmm.mutable_rd()->set_azi(0); + + emitNMM(1, nmm); + } + + } // writen2(1, payload.d_raw.c_str(),msg.d_raw.size()); }