1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-04-13 06:13:17 +00:00

Added NMEA 2.1 protocol for PVT dump.

This is an experimental release that only supports FILE dump operations.



git-svn-id: https://svn.code.sf.net/p/gnss-sdr/code/trunk@235 64b25241-fba3-4117-9849-534c7e92360d
This commit is contained in:
Javier Arribas 2012-08-28 17:14:18 +00:00
parent 45d7220dae
commit 598512529f
9 changed files with 964 additions and 53 deletions

View File

@ -66,10 +66,19 @@ gps_l1_ca_pvt_cc::gps_l1_ca_pvt_cc(unsigned int nchannels, gr_msg_queue_sptr que
d_dump_filename = dump_filename;
std::string dump_ls_pvt_filename;
dump_ls_pvt_filename=dump_filename;
//initialize kml_printer
std::string kml_dump_filename;
kml_dump_filename = d_dump_filename;
kml_dump_filename.append(".kml");
d_kml_dump.set_headers(kml_dump_filename);
//initialize nmea_printer
std::string nmea_dump_filename;
nmea_dump_filename = d_dump_filename;
nmea_dump_filename.append(".nmea");
d_nmea_printer=new Nmea_Printer(nmea_dump_filename);
d_dump_filename.append("_raw.dat");
dump_ls_pvt_filename.append("_ls_pvt.dat");
d_averaging_depth = averaging_depth;
@ -117,6 +126,7 @@ gps_l1_ca_pvt_cc::~gps_l1_ca_pvt_cc()
d_kml_dump.close_file();
delete d_ls_pvt;
delete rp;
delete d_nmea_printer;
}
@ -204,6 +214,8 @@ int gps_l1_ca_pvt_cc::general_work (int noutput_items, gr_vector_int &ninput_ite
if (d_ls_pvt->get_PVT(gnss_pseudoranges_map,d_tx_time,d_flag_averaging) == true)
{
d_kml_dump.print_position(d_ls_pvt, d_flag_averaging);
d_nmea_printer->Print_Nmea_Line(d_ls_pvt, d_flag_averaging);
if (!b_rinex_header_writen) // & we have utc data in nav message!
{
rp->rinex_nav_header(rp->navFile, d_last_nav_msg);

View File

@ -38,6 +38,7 @@
#include <boost/thread/thread.hpp>
#include "concurrent_queue.h"
#include "gps_navigation_message.h"
#include "nmea_printer.h"
#include "kml_printer.h"
#include "rinex_printer.h"
#include "gps_l1_ca_ls_pvt.h"
@ -81,6 +82,8 @@ private:
Kml_Printer d_kml_dump;
Nmea_Printer *d_nmea_printer;
concurrent_queue<Gps_Navigation_Message> *d_nav_queue; // Navigation ephemeris queue
Gps_Navigation_Message d_last_nav_msg; // Last navigation message

View File

@ -188,7 +188,10 @@ arma::vec gps_l1_ca_ls_pvt::leastSquarePos(arma::mat satpos, arma::vec obs, arma
//--- Correct satellite position (do to earth rotation) --------
Rot_X = e_r_corr(traveltime, X.col(i)); //armadillo
//--- Find the elevation angel of the satellite ----------------
//--- Find the elevation angle of the satellite ----------------
topocent(&d_visible_satellites_Az[i],&d_visible_satellites_El[i],&d_visible_satellites_Distance[i],pos.subvec(0,2), Rot_X - pos.subvec(0,2));
//[az(i), el(i), dist] = topocent(pos(1:3, :), Rot_X - pos(1:3, :));
}
@ -221,11 +224,13 @@ arma::vec gps_l1_ca_ls_pvt::leastSquarePos(arma::mat satpos, arma::vec obs, arma
//-- compute the Dilution Of Precision values
arma::mat Q;
Q = arma::inv(arma::htrans(A)*A);
//std::cout<<Q<<std::endl;
d_GDOP = sqrt(arma::trace(Q)); // GDOP
d_PDOP = sqrt(Q(1,1) + Q(2,2) + Q(3,3)); // PDOP
d_HDOP = sqrt(Q(1,1) + Q(2,2)); // HDOP
d_VDOP = sqrt(Q(3,3)); // VDOP
d_TDOP = sqrt(Q(4,4)); // TDOP
d_PDOP = sqrt(Q(0,0) + Q(1,1) + Q(2,2)); // PDOP
d_HDOP = sqrt(Q(0,0) + Q(1,1)); // HDOP
d_VDOP = sqrt(Q(2,2)); // VDOP
d_TDOP = sqrt(Q(3,3)); // TDOP
}catch(std::exception e)
{
d_GDOP = -1;
@ -250,6 +255,8 @@ bool gps_l1_ca_ls_pvt::get_PVT(std::map<int,Gnss_Synchro> gnss_pseudoranges_map,
double GPS_corrected_time = 0;
double utc = 0;
d_flag_averaging=flag_averaging;
int valid_obs=0; //valid observations counter
for (int i=0; i<d_nchannels; i++)
{
@ -280,6 +287,8 @@ bool gps_l1_ca_ls_pvt::get_PVT(std::map<int,Gnss_Synchro> gnss_pseudoranges_map,
DLOG(INFO) << "ECEF satellite SV ID=" << d_ephemeris[i].i_satellite_PRN <<" X=" << d_ephemeris[i].d_satpos_X
<< " [m] Y=" << d_ephemeris[i].d_satpos_Y << " [m] Z=" << d_ephemeris[i].d_satpos_Z << " [m]" << std::endl;
obs(i) = gnss_pseudoranges_iter->second.Pseudorange_m + d_ephemeris[i].d_satClkCorr*GPS_C_m_s;
d_visible_satellites_IDs[valid_obs]=d_ephemeris[i].i_satellite_PRN;
d_visible_satellites_CN0_dB[valid_obs]=gnss_pseudoranges_iter->second.CN0_dB_hz;
valid_obs++;
}
else
@ -296,7 +305,11 @@ bool gps_l1_ca_ls_pvt::get_PVT(std::map<int,Gnss_Synchro> gnss_pseudoranges_map,
obs(i) = 1; // to avoid algorithm problems (divide by zero)
}
}
d_valid_observations = valid_obs;
DLOG(INFO) <<"PVT: valid observations="<<valid_obs<<std::endl;
if (valid_obs>=4)
{
arma::vec mypos;
@ -471,59 +484,230 @@ void gps_l1_ca_ls_pvt::cart2geo(double X, double Y, double Z, int elipsoid_selec
d_height_m = h;
}
//void gps_l1_ca_ls_pvt::topocent(traveltime, X_sat)
//{
/*
%function [Az, El, D] = topocent(X, dx)
%TOPOCENT Transformation of vector dx into topocentric coordinate
% system with origin at X.
% Both parameters are 3 by 1 vectors.
%
%[Az, El, D] = topocent(X, dx);
%
% Inputs:
% X - vector origin corrdinates (in ECEF system [X; Y; Z;])
% dx - vector ([dX; dY; dZ;]).
%
% Outputs:
% D - vector length. Units like units of the input
% Az - azimuth from north positive clockwise, degrees
% El - elevation angle, degrees
void gps_l1_ca_ls_pvt::togeod(double *dphi, double *dlambda, double *h, double a, double finv, double X, double Y, double Z)
{
//function [dphi, dlambda, h] = togeod(a, finv, X, Y, Z)
//%TOGEOD Subroutine to calculate geodetic coordinates latitude, longitude,
//% height given Cartesian coordinates X,Y,Z, and reference ellipsoid
//% values semi-major axis (a) and the inverse of flattening (finv).
//%
//%[dphi, dlambda, h] = togeod(a, finv, X, Y, Z);
//%
//% The units of linear parameters X,Y,Z,a must all agree (m,km,mi,ft,..etc)
//% The output units of angular quantities will be in decimal degrees
//% (15.5 degrees not 15 deg 30 min). The output units of h will be the
//% same as the units of X,Y,Z,a.
//%
//% Inputs:
//% a - semi-major axis of the reference ellipsoid
//% finv - inverse of flattening of the reference ellipsoid
//% X,Y,Z - Cartesian coordinates
//%
//% Outputs:
//% dphi - latitude
//% dlambda - longitude
//% h - height above reference ellipsoid
//
//% Copyright (C) 1987 C. Goad, Columbus, Ohio
//% Reprinted with permission of author, 1996
//% Fortran code translated into MATLAB
//% Kai Borre 03-30-96
//%
//% CVS record:
//% $Id: togeod.m,v 1.1.1.1.2.4 2006/08/22 13:45:59 dpl Exp $
//%==========================================================================
//
*h = 0;
double tolsq = 1.e-10;
int maxit=10;
// compute radians-to-degree factor
double rtd;
rtd = 180/GPS_PI;
// compute square of eccentricity
double esq;
if (finv < 1.0E-20)
{
esq = 0;
}else
{
esq = (2 - 1/finv) / finv;
}
double oneesq;
oneesq = 1 - esq;
// first guess
// P is distance from spin axis
double P;
P = sqrt(X*X+Y*Y);
//direct calculation of longitude
//
if (P > 1.0E-20)
{
*dlambda = atan2(Y,X) * rtd;
}else
{
*dlambda = 0;
}
if (*dlambda < 0)
{
*dlambda = *dlambda + 360.0;
}
// r is distance from origin (0,0,0)
double r;
r = sqrt(P*P + Z*Z);
double sinphi;
if (r > 1.0E-20)
{
sinphi = Z/r;
} else
{
sinphi = 0;
}
*dphi = asin(sinphi);
// initial value of height = distance from origin minus
// approximate distance from origin to surface of ellipsoid
if (r < 1.0E-20)
{
*h = 0;
return;
}
*h = r - a*(1-sinphi*sinphi/finv);
dtr = pi/180;
// iterate
double cosphi;
double N_phi;
double dP;
double dZ;
for (int i=0; i<maxit; i++)
{
sinphi = sin(*dphi);
cosphi = cos(*dphi);
[phi, lambda, h] = togeod(6378137, 298.257223563, X(1), X(2), X(3));
// compute radius of curvature in prime vertical direction
N_phi = a/sqrt(1-esq*sinphi*sinphi);
cl = cos(lambda * dtr);
sl = sin(lambda * dtr);
cb = cos(phi * dtr);
sb = sin(phi * dtr);
// compute residuals in P and Z
dP = P - (N_phi + (*h)) * cosphi;
dZ = Z - (N_phi*oneesq + (*h)) * sinphi;
//
// update height and latitude
*h = *h + (sinphi*dZ + cosphi*dP);
*dphi = *dphi + (cosphi*dZ - sinphi*dP)/(N_phi + (*h));
F = [-sl -sb*cl cb*cl;
cl -sb*sl cb*sl;
0 cb sb];
// test for convergence
if ((dP*dP + dZ*dZ) < tolsq)
{
break;
}
local_vector = F' * dx;
E = local_vector(1);
N = local_vector(2);
U = local_vector(3);
// Not Converged--Warn user
// if (i == (maxit-1))
// fprintf([' Problem in TOGEOD, did not converge in %2.0f',...
// ' iterations\n'], i);
// end
}
//
*dphi = (*dphi) * rtd;
hor_dis = sqrt(E^2 + N^2);
}
void gps_l1_ca_ls_pvt::topocent(double *Az, double *El, double *D, arma::vec x, arma::vec x_sat)
{
if hor_dis < 1.e-20
Az = 0;
El = 90;
else
Az = atan2(E, N)/dtr;
El = atan2(U, hor_dis)/dtr;
end
//%function [Az, El, D] = topocent(X, dx)
//%TOPOCENT Transformation of vector dx into topocentric coordinate
//% system with origin at X.
//% Both parameters are 3 by 1 vectors.
//%
//%[Az, El, D] = topocent(X, dx);
//%
//% Inputs:
//% X - vector origin corrdinates (in ECEF system [X; Y; Z;])
//% dx - vector ([dX; dY; dZ;]).
//%
//% Outputs:
//% D - vector length. Units like units of the input
//% Az - azimuth from north positive clockwise, degrees
//% El - elevation angle, degrees
if Az < 0
Az = Az + 360;
end
double dtr;
double lambda;
double phi;
double cl;
double sl;
double cb;
double sb;
D = sqrt(dx(1)^2 + dx(2)^2 + dx(3)^2);
%%%%%%%%% end topocent.m %%%%%%%%%
*/
//}
double h;
dtr = GPS_PI/180.0;
//[phi, lambda, h] = togeod(6378137, 298.257223563, X(1), X(2), X(3));
togeod(&phi, &lambda, &h,6378137.0, 298.257223563, x(0), x(1), x(2));
cl = cos(lambda * dtr);
sl = sin(lambda * dtr);
cb = cos(phi * dtr);
sb = sin(phi * dtr);
arma::mat F=arma::zeros(3,3);
F(0,0)=-sl;
F(0,1)=-sb*cl;
F(0,2)=cb*cl;
F(1,0)=cl;
F(1,1)=-sb*sl;
F(1,2)=cb*sl;
F(2,0)=0;
F(2,1)=cb;
F(2,2)=sb;
arma::vec local_vector;
local_vector = arma::htrans(F) * x_sat;
double E;
double N;
double U;
E = local_vector(0);
N = local_vector(1);
U = local_vector(2);
double hor_dis;
hor_dis = sqrt(E*E + N*N);
if (hor_dis < 1.0E-20)
{
*Az = 0;
*El = 90;
}
else
{
*Az = atan2(E, N)/dtr;
*El = atan2(U, hor_dis)/dtr;
}
if (*Az < 0)
{
*Az = *Az + 360.0;
}
*D = sqrt(x_sat(0)*x_sat(0) + x_sat(1)*x_sat(1) + x_sat(2)*x_sat(2));
}

View File

@ -48,6 +48,8 @@
#include "gnss_synchro.h"
#define PVT_MAX_CHANNELS 24
/*!
* \brief This class implements a simple PVT Least Squares solution
*/
@ -56,9 +58,17 @@ class gps_l1_ca_ls_pvt
private:
arma::vec leastSquarePos(arma::mat satpos, arma::vec obs, arma::mat w);
arma::vec e_r_corr(double traveltime, arma::vec X_sat);
//void topocent();
void topocent(double *Az, double *El, double *D, arma::vec x, arma::vec x_sat);
void togeod(double *dphi, double *dlambda, double *h, double a, double finv, double X, double Y, double Z);
public:
int d_nchannels; //! Number of available channels for positioning
int d_valid_observations; //! Number of valid pseudorrange observations (valid satellites)
int d_visible_satellites_IDs[PVT_MAX_CHANNELS]; //! Array with the IDs of the valid satellites
double d_visible_satellites_El[PVT_MAX_CHANNELS]; //! Array with the LOS Elevation of the valid satellites
double d_visible_satellites_Az[PVT_MAX_CHANNELS]; //! Array with the LOS Azimuth of the valid satellites
double d_visible_satellites_Distance[PVT_MAX_CHANNELS]; //! Array with the LOS Distance of the valid satellites
double d_visible_satellites_CN0_dB[PVT_MAX_CHANNELS]; //! Array with the IDs of the valid satellites
Gps_Navigation_Message* d_ephemeris;
double d_GPS_current_time;
boost::posix_time::ptime d_position_UTC_time;
@ -92,6 +102,8 @@ public:
double d_TDOP;
bool d_flag_dump_enabled;
bool d_flag_averaging;
std::string d_dump_filename;
std::ofstream d_dump_file;

View File

@ -2,4 +2,5 @@ project : build-dir ../../../../build ;
obj rinex_printer : rinex_printer.cc ;
obj gps_l1_ca_ls_pvt : gps_l1_ca_ls_pvt.cc ;
obj kml_printer : kml_printer.cc ;
obj kml_printer : kml_printer.cc ;
obj nmea_printer : nmea_printer.cc ;

View File

@ -0,0 +1,617 @@
/*!
* \file kml_printer.cc
* \brief Implementation of a NMEA 2.1 printer for GNSS-SDR
* This class provides a implementation of a subset of the NMEA-0183 standard for interfacing
* marine electronic devices as defined by the National Marine Electronics Association (NMEA).
* See http://www.nmea.org/ for the NMEA 183 standard
*
* \author Javier Arribas, 2012. jarribas(at)cttc.es
*
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <gflags/gflags.h>
#include "boost/date_time/posix_time/posix_time.hpp"
#include "GPS_L1_CA.h"
#include "nmea_printer.h"
using google::LogMessage;
//DEFINE_string(NMEA_version, "2.1", "Specifies the NMEA version (2.1)");
Nmea_Printer::Nmea_Printer(std::string filename)
{
nmea_filename=filename;
nmea_file_descriptor.open(nmea_filename.c_str(), std::ios::out);
if (nmea_file_descriptor.is_open())
{
DLOG(INFO) << "NMEA printer writing on " << nmea_filename.c_str();
}
}
Nmea_Printer::~Nmea_Printer()
{
if (nmea_file_descriptor.is_open())
{
nmea_file_descriptor.close();
}
}
bool Nmea_Printer::Print_Nmea_Line(gps_l1_ca_ls_pvt* pvt_data, bool print_average_values)
{
// set the new PVT data
d_PVT_data=pvt_data;
try{
//GPRMC
nmea_file_descriptor<<get_GPRMC();
//GPGGA (Global Positioning System Fixed Data)
nmea_file_descriptor<<get_GPGGA();
//GPGSA
nmea_file_descriptor<<get_GPGSA();
//GPGSV
nmea_file_descriptor<<get_GPGSV();
}catch(std::exception ex)
{
DLOG(INFO) << "NMEA printer can not write on output file" << nmea_filename.c_str();;
}
return true;
}
char Nmea_Printer::checkSum(std::string sentence) {
char check = 0;
// iterate over the string, XOR each byte with the total sum:
for (unsigned int c = 0; c < sentence.length(); c++) {
check = char(check ^ sentence.at(c));
}
// return the result
return check;
}
std::string Nmea_Printer::latitude_to_hm(double lat)
{
bool north;
if (lat < 0.0)
{
north = false;
lat = -lat ;
}else{
north = true;
}
int deg = (int)lat;
double mins = lat - (double)deg;
mins *= 60.0 ;
std::ostringstream out_string;
out_string.setf(std::ios::fixed, std::ios::floatfield);
out_string.fill('0');
out_string.width(2);
out_string << deg;
out_string.width(6);
out_string.precision(4);
out_string<<mins;
if (north==true)
{
out_string << ",N";
}else{
out_string << ",S";
}
return out_string.str();
}
std::string Nmea_Printer::longitude_to_hm(double longitude)
{
bool east;
if (longitude < 0.0)
{
east = false;
longitude = -longitude ;
}else{
east=true;
}
int deg = (int)longitude;
double mins = longitude - (double)deg;
mins *= 60.0 ;
std::ostringstream out_string;
out_string.setf(std::ios::fixed, std::ios::floatfield);
out_string.width(3);
out_string.fill('0');
out_string << deg;
out_string.width(6);
out_string.precision(4);
out_string<<mins;
if (east==true)
{
out_string << ",E";
}else{
out_string << ",W";
}
return out_string.str();
}
std::string Nmea_Printer::get_UTC_NMEA_time(boost::posix_time::ptime d_position_UTC_time)
{
//UTC Time: hhmmss.sss
std::stringstream sentence_str;
boost::posix_time::time_duration td=d_position_UTC_time.time_of_day();
int utc_hours;
int utc_mins;
int utc_seconds;
int utc_milliseconds;
utc_hours=td.hours();
utc_mins=td.minutes();
utc_seconds=td.seconds();
utc_milliseconds=td.total_milliseconds()-td.total_seconds()*1000;
if (utc_hours < 10) sentence_str << "0"; // two digits for hours
sentence_str << utc_hours;
if (utc_mins < 10) sentence_str << "0"; // two digits for minutes
sentence_str << utc_mins;
if (utc_seconds < 10) sentence_str << "0"; // two digits for seconds
sentence_str << utc_seconds;
if (utc_milliseconds < 10)
{
sentence_str << ".00"; // three digits for ms
sentence_str << utc_milliseconds;
}
else if (utc_milliseconds < 100)
{
sentence_str << ".0"; // three digits for ms
sentence_str << utc_milliseconds;
}else
{
sentence_str << "."; // three digits for ms
sentence_str << utc_milliseconds;
}
return sentence_str.str();
}
std::string Nmea_Printer::get_GPRMC()
{
// Sample -> $GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,*10
bool valid_fix=d_PVT_data->b_valid_position;
// ToDo: Compute speed and course over ground
double speed_over_ground_knots=0;
double course_over_ground_deg=0;
//boost::posix_time::ptime d_position_UTC_time=boost::posix_time::microsec_clock::universal_time();
std::stringstream sentence_str;
//GPRMC (RMC-Recommended,Minimum Specific GNSS Data)
std::string sentence_header;
sentence_header="$GPRMC,";
sentence_str<<sentence_header;
//UTC Time: hhmmss.sss
sentence_str<<get_UTC_NMEA_time(d_PVT_data->d_position_UTC_time);
//Status: A: data valid, V: data NOT valid
if (valid_fix==true)
{
sentence_str<<",A";
}else{
sentence_str<<",V";
};
if (d_PVT_data->d_flag_averaging==true)
{
// Latitude ddmm.mmmm,(N or S)
sentence_str<<","<<latitude_to_hm(d_PVT_data->d_avg_latitude_d);
// longitude dddmm.mmmm,(E or W)
sentence_str<<","<<longitude_to_hm(d_PVT_data->d_avg_longitude_d);
}else{
// Latitude ddmm.mmmm,(N or S)
sentence_str<<","<<latitude_to_hm(d_PVT_data->d_latitude_d);
// longitude dddmm.mmmm,(E or W)
sentence_str<<","<<longitude_to_hm(d_PVT_data->d_longitude_d);
}
//Speed over ground (knots)
sentence_str<<",";
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
sentence_str.precision(2);
sentence_str << speed_over_ground_knots;
//course over ground (degrees)
sentence_str<<",";
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
sentence_str.precision(2);
sentence_str << course_over_ground_deg;
// Date ddmmyy
boost::gregorian::date sentence_date = d_PVT_data->d_position_UTC_time.date();
unsigned int year=sentence_date.year();
unsigned int day=sentence_date.day();
unsigned int month=sentence_date.month();
sentence_str<<",";
sentence_str.width(2);
sentence_str.fill('0');
sentence_str<<day;
sentence_str.width(2);
sentence_str.fill('0');
sentence_str<<month;
std::stringstream year_strs;
year_strs<<std::dec<<year;
sentence_str<<std::dec<<year_strs.str().substr(2);
//Magnetic Variation (degrees)
// ToDo: Implement magnetic compass
sentence_str<<",";
//Magnetic Variation (E or W)
// ToDo: Implement magnetic compass
sentence_str<<",";
// Checksum
char checksum;
std::string tmpstr;
tmpstr=sentence_str.str();
checksum = checkSum(tmpstr.substr(1));
sentence_str<<"*";
sentence_str.width(2);
sentence_str.fill('0');
sentence_str<<std::hex<<(int)checksum;
// end NMEA sentence
sentence_str<<"\r\n";
return sentence_str.str();
}
std::string Nmea_Printer::get_GPGSA()
{
//$GPGSA,A,3,07,02,26,27,09,04,15, , , , , ,1.8,1.0,1.5*33
// GSA-GNSS DOP and Active Satellites
bool valid_fix=d_PVT_data->b_valid_position;
int n_sats_used=d_PVT_data->d_valid_observations;
double pdop=d_PVT_data->d_PDOP;
double hdop=d_PVT_data->d_HDOP;
double vdop=d_PVT_data->d_VDOP;
std::stringstream sentence_str;
std::string sentence_header;
sentence_header="$GPGSA,";
sentence_str<<sentence_header;
// mode1:
// (M) Manual-forced to operate in 2D or 3D mode
// (A) Automatic-allowed to automatically switch 2D/3D
std::string mode1="M";
sentence_str<<mode1;
// mode2:
// 1 fix not available
// 2 fix 2D
// 3 fix 3D
if (valid_fix==true)
{
sentence_str<<",3";
}else{
sentence_str<<",1";
};
// Used satellites
for (int i=0; i<12;i++)
{
sentence_str<<",";
if (i<n_sats_used)
{
sentence_str.width(2);
sentence_str.fill('0');
sentence_str<<d_PVT_data->d_visible_satellites_IDs[i];
}
}
// PDOP
sentence_str<<",";
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
sentence_str.width(2);
sentence_str.precision(1);
sentence_str.fill('0');
sentence_str << pdop;
//HDOP
sentence_str<<",";
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
sentence_str.width(2);
sentence_str.precision(1);
sentence_str.fill('0');
sentence_str << hdop;
//VDOP
sentence_str<<",";
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
sentence_str.width(2);
sentence_str.precision(1);
sentence_str.fill('0');
sentence_str << vdop;
// Checksum
char checksum;
std::string tmpstr;
tmpstr=sentence_str.str();
checksum = checkSum(tmpstr.substr(1));
sentence_str<<"*";
sentence_str.width(2);
sentence_str.fill('0');
sentence_str<<std::hex<<(int)checksum;
// end NMEA sentence
sentence_str<<"\r\n";
return sentence_str.str();
}
std::string Nmea_Printer::get_GPGSV()
{
// GSV-GNSS Satellites in View
// Notice that NMEA 2.1 only supports 12 channels
int n_sats_used=d_PVT_data->d_valid_observations;
std::stringstream sentence_str;
std::stringstream frame_str;
std::string sentence_header;
sentence_header="$GPGSV,";
char checksum;
std::string tmpstr;
// 1st step: How many GPGSV frames we need? (up to 3)
// Each frame countains up to 4 satellites
int n_frames;
n_frames=std::ceil(((double)n_sats_used)/4.0);
// generate the frames
int current_satellite=0;
for (int i=1;i<(n_frames+1);i++)
{
frame_str.str("");
frame_str<<sentence_header;
// number of messages
frame_str<<n_frames;
// message number
frame_str<<",";
frame_str<<i;
// total number of satellites in view
frame_str<<",";
frame_str.width(2);
frame_str.fill('0');
frame_str<<std::dec<<n_sats_used;
//satellites info
for (int j=0;j<4;j++)
{
// write satellite info
frame_str<<",";
frame_str.width(2);
frame_str.fill('0');
frame_str<<std::dec<<d_PVT_data->d_visible_satellites_IDs[current_satellite];
frame_str<<",";
frame_str.width(2);
frame_str.fill('0');
frame_str<<std::dec<<(int)d_PVT_data->d_visible_satellites_El[current_satellite];
frame_str<<",";
frame_str.width(3);
frame_str.fill('0');
frame_str<<std::dec<<(int)d_PVT_data->d_visible_satellites_Az[current_satellite];
frame_str<<",";
frame_str.width(2);
frame_str.fill('0');
frame_str<<std::dec<<(int)d_PVT_data->d_visible_satellites_CN0_dB[current_satellite];
current_satellite++;
if (current_satellite==n_sats_used)
{
break;
}
}
// frame checksum
tmpstr=frame_str.str();
checksum = checkSum(tmpstr.substr(1));
frame_str<<"*";
frame_str.width(2);
frame_str.fill('0');
frame_str<<std::hex<<(int)checksum;
// end NMEA sentence
frame_str<<"\r\n";
//add frame to sentence
sentence_str<<frame_str.str();
}
return sentence_str.str();
//$GPGSV,2,1,07,07,79,048,42,02,51,062,43,26,36,256,42,27,27,138,42*71
}
std::string Nmea_Printer::get_GPGGA()
{
//boost::posix_time::ptime d_position_UTC_time=boost::posix_time::microsec_clock::universal_time();
bool valid_fix=d_PVT_data->b_valid_position;
int n_channels=d_PVT_data->d_valid_observations;//d_nchannels
double hdop=d_PVT_data->d_HDOP;
double MSL_altitude;
if (d_PVT_data->d_flag_averaging==true)
{
MSL_altitude=d_PVT_data->d_avg_height_m;
}else{
MSL_altitude=d_PVT_data->d_height_m;
}
std::stringstream sentence_str;
//GPGGA (Global Positioning System Fixed Data)
std::string sentence_header;
sentence_header="$GPGGA,";
sentence_str<<sentence_header;
//UTC Time: hhmmss.sss
sentence_str<<get_UTC_NMEA_time(d_PVT_data->d_position_UTC_time);
if (d_PVT_data->d_flag_averaging==true)
{
// Latitude ddmm.mmmm,(N or S)
sentence_str<<","<<latitude_to_hm(d_PVT_data->d_avg_latitude_d);
// longitude dddmm.mmmm,(E or W)
sentence_str<<","<<longitude_to_hm(d_PVT_data->d_avg_longitude_d);
}else{
// Latitude ddmm.mmmm,(N or S)
sentence_str<<","<<latitude_to_hm(d_PVT_data->d_latitude_d);
// longitude dddmm.mmmm,(E or W)
sentence_str<<","<<longitude_to_hm(d_PVT_data->d_longitude_d);
}
// Position fix indicator
// 0 - Fix not available or invalid
// 1 - GPS SPS Mode, fix valid
// 2 - Differential GPS, SPS Mode, fix valid
// 3-5 - Not supported
// 6 - Dead Reckoning Mode, fix valid
// ToDo: Update PVT module to identify the fix mode
if (valid_fix==true)
{
sentence_str<<",1";
}else{
sentence_str<<",0";
}
// Number of satellites used in PVT
sentence_str<<",";
if (n_channels<10)
{
sentence_str<<'0'<<n_channels;
}else{
sentence_str<<n_channels;
}
// HDOP
sentence_str<<",";
sentence_str.setf(std::ios::fixed, std::ios::floatfield);
sentence_str.width(2);
sentence_str.precision(1);
sentence_str.fill('0');
sentence_str << hdop;
// MSL Altitude
sentence_str<<",";
sentence_str.precision(1);
sentence_str<<MSL_altitude;
sentence_str<<",M";
// Geoid-to-ellipsoid separation. Ellipsoid altitude = MSL Altitude + Geoid Separation.
// ToDo: Compute this value
sentence_str<<",";
sentence_str<<"0.0";
sentence_str<<",M";
// Age of Diff. Corr. (Seconds) Null fields when DGPS is not used
// Diff. Ref. Station ID (0000)
// ToDo: Implement this fields for Differential GPS
sentence_str<<",";
sentence_str<<"0.0,0000";
// Checksum
char checksum;
std::string tmpstr;
tmpstr=sentence_str.str();
checksum = checkSum(tmpstr.substr(1));
sentence_str<<"*";
sentence_str.width(2);
sentence_str.fill('0');
sentence_str<<std::hex<<(int)checksum;
// end NMEA sentence
sentence_str<<"\r\n";
return sentence_str.str();
//$GPGGA,104427.591,5920.7009,N,01803.2938,E,1,05,3.3,78.2,M,23.2,M,0.0,0000*4A
}

View File

@ -0,0 +1,80 @@
/*!
* \file kml_printer.h
* \brief Implementation of a NMEA 2.1 printer for GNSS-SDR
* This class provides a implementation of a subset of the NMEA-0183 standard for interfacing
* marine electronic devices as defined by the National Marine Electronics Association (NMEA).
* See http://www.nmea.org/ for the NMEA 183 standard
*
* \author Javier Arribas, 2012. jarribas(at)cttc.es
*
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_NMEA_PRINTER_H_
#define GNSS_SDR_NMEA_PRINTER_H_
#include <iostream>
#include <fstream>
#include "gps_l1_ca_ls_pvt.h"
class Nmea_Printer
{
public:
/*!
* \brief Default constructor.
*/
Nmea_Printer(std::string filename);
/*!
* \brief Print NMEA PVT and satellite info to the initialized device
*/
bool Print_Nmea_Line(gps_l1_ca_ls_pvt* position, bool print_average_values);
/*!
* \brief Default destructor.
*/
~Nmea_Printer();
private:
std::string nmea_filename ; //<! String with the NMEA log filename
std::ofstream nmea_file_descriptor ; //<! Output file stream for NMEA log file
gps_l1_ca_ls_pvt* d_PVT_data;
std::string get_GPGGA();
std::string get_GPGSV();
std::string get_GPGSA();
std::string get_GPRMC();
std::string get_UTC_NMEA_time(boost::posix_time::ptime d_position_UTC_time);
std::string longitude_to_hm(double longitude);
std::string latitude_to_hm(double lat);
char checkSum(std::string sentence);
};
#endif

View File

@ -37,6 +37,7 @@ exe gnss-sdr : main.cc
../algorithms/observables/gnuradio_blocks//gps_l1_ca_observables_cc
../algorithms/PVT/libs//rinex_printer
../algorithms/PVT/libs//kml_printer
../algorithms/PVT/libs//nmea_printer
../algorithms/PVT/libs//gps_l1_ca_ls_pvt
../algorithms/output_filter/adapters//file_output_filter
../algorithms/output_filter/adapters//null_sink_output_filter

View File

@ -34,6 +34,7 @@ exe run_tests : test_main.cc
../algorithms/observables/gnuradio_blocks//gps_l1_ca_observables_cc
../algorithms/PVT/libs//rinex_printer
../algorithms/PVT/libs//kml_printer
../algorithms/PVT/libs//nmea_printer
../algorithms/PVT/libs//gps_l1_ca_ls_pvt
../algorithms/output_filter/adapters//file_output_filter
../algorithms/output_filter/adapters//null_sink_output_filter