mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-01-07 07:50:32 +00:00
Add Geohash of PVT solution to internal logs
This commit is contained in:
parent
723cddc6d2
commit
1b2087944e
@ -111,6 +111,8 @@ All notable changes to GNSS-SDR will be documented in this file.
|
|||||||
- New configuration parameter `PVT.use_unhealthy_sats`, set by default to
|
- New configuration parameter `PVT.use_unhealthy_sats`, set by default to
|
||||||
`false`, allows processing observables of satellites that report an unhealthy
|
`false`, allows processing observables of satellites that report an unhealthy
|
||||||
status in the navigation message if set to `true`.
|
status in the navigation message if set to `true`.
|
||||||
|
- Added the [Geohash](https://en.wikipedia.org/wiki/Geohash) of the PVT solution
|
||||||
|
in the internal logs.
|
||||||
- Allowed the CMake project to be a sub-project.
|
- Allowed the CMake project to be a sub-project.
|
||||||
|
|
||||||
See the definitions of concepts and metrics at
|
See the definitions of concepts and metrics at
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "galileo_has_data.h"
|
#include "galileo_has_data.h"
|
||||||
#include "galileo_iono.h"
|
#include "galileo_iono.h"
|
||||||
#include "galileo_utc_model.h"
|
#include "galileo_utc_model.h"
|
||||||
|
#include "geohash.h"
|
||||||
#include "geojson_printer.h"
|
#include "geojson_printer.h"
|
||||||
#include "glonass_gnav_almanac.h"
|
#include "glonass_gnav_almanac.h"
|
||||||
#include "glonass_gnav_ephemeris.h"
|
#include "glonass_gnav_ephemeris.h"
|
||||||
@ -124,6 +125,7 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels,
|
|||||||
gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)),
|
gr::io_signature::make(nchannels, nchannels, sizeof(Gnss_Synchro)),
|
||||||
gr::io_signature::make(0, 0, 0)),
|
gr::io_signature::make(0, 0, 0)),
|
||||||
d_dump_filename(conf_.dump_filename),
|
d_dump_filename(conf_.dump_filename),
|
||||||
|
d_geohash(std::make_unique<Geohash>()),
|
||||||
d_gps_ephemeris_sptr_type_hash_code(typeid(std::shared_ptr<Gps_Ephemeris>).hash_code()),
|
d_gps_ephemeris_sptr_type_hash_code(typeid(std::shared_ptr<Gps_Ephemeris>).hash_code()),
|
||||||
d_gps_iono_sptr_type_hash_code(typeid(std::shared_ptr<Gps_Iono>).hash_code()),
|
d_gps_iono_sptr_type_hash_code(typeid(std::shared_ptr<Gps_Iono>).hash_code()),
|
||||||
d_gps_utc_model_sptr_type_hash_code(typeid(std::shared_ptr<Gps_Utc_Model>).hash_code()),
|
d_gps_utc_model_sptr_type_hash_code(typeid(std::shared_ptr<Gps_Utc_Model>).hash_code()),
|
||||||
@ -2432,7 +2434,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item
|
|||||||
LOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time())
|
LOG(INFO) << "Position at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time())
|
||||||
<< " UTC using " << d_user_pvt_solver->get_num_valid_observations() << " observations is Lat = " << d_user_pvt_solver->get_latitude() << " [deg], Long = " << d_user_pvt_solver->get_longitude()
|
<< " UTC using " << d_user_pvt_solver->get_num_valid_observations() << " observations is Lat = " << d_user_pvt_solver->get_latitude() << " [deg], Long = " << d_user_pvt_solver->get_longitude()
|
||||||
<< " [deg], Height = " << d_user_pvt_solver->get_height() << " [m]";
|
<< " [deg], Height = " << d_user_pvt_solver->get_height() << " [m]";
|
||||||
|
LOG(INFO) << "geohash: " << d_geohash->encode(d_user_pvt_solver->get_latitude(), d_user_pvt_solver->get_longitude());
|
||||||
/* std::cout << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time())
|
/* std::cout << "Dilution of Precision at " << boost::posix_time::to_simple_string(d_user_pvt_solver->get_position_UTC_time())
|
||||||
<< " UTC using "<< d_user_pvt_solver->get_num_valid_observations() <<" observations is HDOP = " << d_user_pvt_solver->get_hdop() << " VDOP = "
|
<< " UTC using "<< d_user_pvt_solver->get_num_valid_observations() <<" observations is HDOP = " << d_user_pvt_solver->get_hdop() << " VDOP = "
|
||||||
<< d_user_pvt_solver->get_vdop()
|
<< d_user_pvt_solver->get_vdop()
|
||||||
|
@ -50,6 +50,7 @@ class Beidou_Dnav_Ephemeris;
|
|||||||
class Galileo_Almanac;
|
class Galileo_Almanac;
|
||||||
class Galileo_Ephemeris;
|
class Galileo_Ephemeris;
|
||||||
class Galileo_HAS_data;
|
class Galileo_HAS_data;
|
||||||
|
class Geohash;
|
||||||
class GeoJSON_Printer;
|
class GeoJSON_Printer;
|
||||||
class Gps_Almanac;
|
class Gps_Almanac;
|
||||||
class Gps_Ephemeris;
|
class Gps_Ephemeris;
|
||||||
@ -204,6 +205,7 @@ private:
|
|||||||
std::queue<GnssTime> d_TimeChannelTagTimestamps;
|
std::queue<GnssTime> d_TimeChannelTagTimestamps;
|
||||||
|
|
||||||
boost::posix_time::time_duration d_utc_diff_time;
|
boost::posix_time::time_duration d_utc_diff_time;
|
||||||
|
std::unique_ptr<Geohash> d_geohash;
|
||||||
|
|
||||||
size_t d_gps_ephemeris_sptr_type_hash_code;
|
size_t d_gps_ephemeris_sptr_type_hash_code;
|
||||||
size_t d_gps_iono_sptr_type_hash_code;
|
size_t d_gps_iono_sptr_type_hash_code;
|
||||||
|
@ -22,6 +22,7 @@ set(PVT_LIB_SOURCES
|
|||||||
monitor_pvt_udp_sink.cc
|
monitor_pvt_udp_sink.cc
|
||||||
monitor_ephemeris_udp_sink.cc
|
monitor_ephemeris_udp_sink.cc
|
||||||
has_simple_printer.cc
|
has_simple_printer.cc
|
||||||
|
geohash.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PVT_LIB_HEADERS
|
set(PVT_LIB_HEADERS
|
||||||
@ -43,6 +44,7 @@ set(PVT_LIB_HEADERS
|
|||||||
serdes_gps_eph.h
|
serdes_gps_eph.h
|
||||||
monitor_ephemeris_udp_sink.h
|
monitor_ephemeris_udp_sink.h
|
||||||
has_simple_printer.h
|
has_simple_printer.h
|
||||||
|
geohash.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(SORT PVT_LIB_HEADERS)
|
list(SORT PVT_LIB_HEADERS)
|
||||||
|
195
src/algorithms/PVT/libs/geohash.cc
Normal file
195
src/algorithms/PVT/libs/geohash.cc
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*!
|
||||||
|
* \file geohash.cc
|
||||||
|
* \brief Implementation of a class for geohash encoding / decoding
|
||||||
|
* \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||||
|
* This file is part of GNSS-SDR.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "geohash.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
Geohash::Geohash()
|
||||||
|
{
|
||||||
|
base32 = "0123456789bcdefghjkmnpqrstuvwxyz";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Geohash::encode(double lat, double lon, int precision) const
|
||||||
|
{
|
||||||
|
// infer precision?
|
||||||
|
if (precision == -1)
|
||||||
|
{
|
||||||
|
// refine geohash until it matches precision of supplied lat/lon
|
||||||
|
for (int p = 1; p <= 12; ++p)
|
||||||
|
{
|
||||||
|
const auto hash = Geohash::encode(lat, lon, p);
|
||||||
|
const auto posn = Geohash::decode(hash);
|
||||||
|
|
||||||
|
if ((std::fabs(posn[0] - lat) < std::numeric_limits<double>::epsilon()) &&
|
||||||
|
(std::fabs(posn[1] - lon) < std::numeric_limits<double>::epsilon()))
|
||||||
|
{
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
precision = 12; // set to maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::isnan(lat) || std::isnan(lon) || precision < 1)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Invalid geohash");
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = 0; // index into base32 map
|
||||||
|
int bit = 0; // each char holds 5 bits
|
||||||
|
bool evenBit = true;
|
||||||
|
std::string geohash = "";
|
||||||
|
|
||||||
|
double latMin = -90.0;
|
||||||
|
double latMax = 90.0;
|
||||||
|
double lonMin = -180.0;
|
||||||
|
double lonMax = 180.0;
|
||||||
|
|
||||||
|
while (geohash.length() < static_cast<size_t>(precision))
|
||||||
|
{
|
||||||
|
if (evenBit)
|
||||||
|
{
|
||||||
|
// bisect E-W longitude
|
||||||
|
const double lonMid = (lonMin + lonMax) / 2.0;
|
||||||
|
if (lon >= lonMid)
|
||||||
|
{
|
||||||
|
idx = idx * 2 + 1;
|
||||||
|
lonMin = lonMid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = idx * 2;
|
||||||
|
lonMax = lonMid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// bisect N-S latitude
|
||||||
|
const double latMid = (latMin + latMax) / 2.0;
|
||||||
|
if (lat >= latMid)
|
||||||
|
{
|
||||||
|
idx = idx * 2 + 1;
|
||||||
|
latMin = latMid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = idx * 2;
|
||||||
|
latMax = latMid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evenBit = !evenBit;
|
||||||
|
|
||||||
|
if (++bit == 5)
|
||||||
|
{
|
||||||
|
// 5 bits gives us a character: append it and start over
|
||||||
|
geohash += base32[idx];
|
||||||
|
bit = 0;
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return geohash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::array<double, 2> Geohash::decode(std::string geohash) const
|
||||||
|
{
|
||||||
|
const auto bounds = Geohash::bounds(geohash);
|
||||||
|
|
||||||
|
const double latMin = bounds[0];
|
||||||
|
const double lonMin = bounds[1];
|
||||||
|
const double latMax = bounds[2];
|
||||||
|
const double lonMax = bounds[3];
|
||||||
|
|
||||||
|
// cell centre
|
||||||
|
double lat = (latMin + latMax) / 2.0;
|
||||||
|
double lon = (lonMin + lonMax) / 2.0;
|
||||||
|
|
||||||
|
// round to close to centre without excessive precision: ⌊2-log10(Δ°)⌋ decimal places
|
||||||
|
std::array<double, 2> latlon{};
|
||||||
|
latlon[0] = std::floor(lat * std::pow(10, std::floor(2 - std::log10(latMax - latMin))));
|
||||||
|
latlon[1] = std::floor(lon * std::pow(10, std::floor(2 - std::log10(lonMax - lonMin))));
|
||||||
|
|
||||||
|
return latlon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::array<double, 4> Geohash::bounds(std::string geohash) const
|
||||||
|
{
|
||||||
|
if (geohash.length() == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid geohash");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::transform(geohash.begin(), geohash.end(), geohash.begin(),
|
||||||
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
|
bool evenBit = true;
|
||||||
|
double latMin = -90.0;
|
||||||
|
double latMax = 90.0;
|
||||||
|
double lonMin = -180.0;
|
||||||
|
double lonMax = 180.0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < geohash.length(); i++)
|
||||||
|
{
|
||||||
|
char chr = geohash[i];
|
||||||
|
int idx = base32.find(chr);
|
||||||
|
if (idx == -1)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid geohash");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int n = 4; n >= 0; n--)
|
||||||
|
{
|
||||||
|
int bitN = idx >> n & 1;
|
||||||
|
if (evenBit)
|
||||||
|
{
|
||||||
|
// longitude
|
||||||
|
double lonMid = (lonMin + lonMax) / 2;
|
||||||
|
if (bitN == 1)
|
||||||
|
{
|
||||||
|
lonMin = lonMid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lonMax = lonMid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// latitude
|
||||||
|
double latMid = (latMin + latMax) / 2;
|
||||||
|
if (bitN == 1)
|
||||||
|
{
|
||||||
|
latMin = latMid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
latMax = latMid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evenBit = !evenBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {latMin, lonMin, latMax, lonMax};
|
||||||
|
}
|
74
src/algorithms/PVT/libs/geohash.h
Normal file
74
src/algorithms/PVT/libs/geohash.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*!
|
||||||
|
* \file geohash.h
|
||||||
|
* \brief Interface of a class that encodes / decodes geohashes
|
||||||
|
* \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||||
|
* This file is part of GNSS-SDR.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GNSS_SDR_GEOHASH_H
|
||||||
|
#define GNSS_SDR_GEOHASH_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/** \addtogroup PVT
|
||||||
|
* \{ */
|
||||||
|
/** \addtogroup PVT_libs
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Class for geohash encoding / decoding
|
||||||
|
* See https://en.wikipedia.org/wiki/Geohash
|
||||||
|
*/
|
||||||
|
class Geohash
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Geohash();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes latitude/longitude to geohash, either to specified precision or
|
||||||
|
* to automatically evaluated precision.
|
||||||
|
*
|
||||||
|
* @param {double} lat - Latitude in degrees.
|
||||||
|
* @param {double} lon - Longitude in degrees.
|
||||||
|
* @param {int} [precision] - Number of characters in resulting geohash.
|
||||||
|
* @returns {string} Geohash of supplied latitude/longitude.
|
||||||
|
* @throws Invalid geohash.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string encode(double lat, double lon, int precision = -1) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode geohash to latitude/longitude (location is approximate centre of
|
||||||
|
* geohash cell, to reasonable precision).
|
||||||
|
*
|
||||||
|
* @param {string} geohash - Geohash string to be converted to
|
||||||
|
* latitude/longitude.
|
||||||
|
* @returns {lat, lon} (Center of) geohashed location.
|
||||||
|
* @throws Invalid geohash.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::array<double, 2> decode(std::string geohash) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* Returns SW/NE latitude/longitude bounds of specified geohash.
|
||||||
|
*/
|
||||||
|
std::array<double, 4> bounds(std::string geohash) const;
|
||||||
|
std::string base32;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
/** \} */
|
||||||
|
#endif // GNSS_SDR_GEOHASH_H
|
@ -72,6 +72,7 @@ DECLARE_string(log_dir);
|
|||||||
#include "unit-tests/signal-processing-blocks/adapter/adapter_test.cc"
|
#include "unit-tests/signal-processing-blocks/adapter/adapter_test.cc"
|
||||||
#include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc"
|
#include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc"
|
||||||
#include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc"
|
#include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc"
|
||||||
|
#include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc"
|
||||||
#include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc"
|
#include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc"
|
||||||
#include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc"
|
#include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc"
|
||||||
#include "unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc"
|
#include "unit-tests/signal-processing-blocks/pvt/rtcm_printer_test.cc"
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/*!
|
||||||
|
* \file geohash_test.cc
|
||||||
|
* \brief Implements Unit Tests for the Geohash class.
|
||||||
|
* \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
|
||||||
|
* This file is part of GNSS-SDR.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors)
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "geohash.h"
|
||||||
|
|
||||||
|
TEST(Geohash_Test, Encode)
|
||||||
|
{
|
||||||
|
Geohash gh = Geohash();
|
||||||
|
std::string hash;
|
||||||
|
EXPECT_NO_THROW(hash = gh.encode(52.205, 0.119, 7));
|
||||||
|
|
||||||
|
EXPECT_EQ(0, hash.compare("u120fxw"));
|
||||||
|
|
||||||
|
EXPECT_THROW(gh.encode(52.205, 0.119, 0), std::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Geohash_Test, precision)
|
||||||
|
{
|
||||||
|
Geohash gh = Geohash();
|
||||||
|
std::string hash;
|
||||||
|
EXPECT_NO_THROW(hash = gh.encode(52.205, 0.119, 6));
|
||||||
|
EXPECT_EQ(0, hash.compare("u120fx"));
|
||||||
|
EXPECT_NO_THROW(hash = gh.encode(52.205, 0.119, 5));
|
||||||
|
EXPECT_EQ(0, hash.compare("u120f"));
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file nma_printer_test.cc
|
* \file nmea_printer_test.cc
|
||||||
* \brief Implements Unit Tests for the Nmea_Printer class.
|
* \brief Implements Unit Tests for the Nmea_Printer class.
|
||||||
* \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es
|
* \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user