File: gnssResiduals2Skyplot.cpp

package info (click to toggle)
groops 0%2Bgit20250907%2Bds-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 11,140 kB
  • sloc: cpp: 135,607; fortran: 1,603; makefile: 20
file content (167 lines) | stat: -rw-r--r-- 7,229 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/***********************************************/
/**
* @file gnssResiduals2Skyplot.cpp
*
* @brief Convert residuals into griddedData format for plotting.
*
* @author Torsten Mayer-Guerr
* @date 2013-07-12
*/
/***********************************************/

// Latex documentation
#define DOCSTRING docstring
static const char *docstring = R"(
Write GNSS residuals together with azimuth and elevation to be plotted with \program{PlotMap}.
Azimuth and elevation are written as ellipsoidal longitude and latitude in a \file{griddedData file}{griddedData}.
The choosen ellipsoid parameters \config{R} and \config{inverseFlattening} are arbitrary but should be the same
as in \program{PlotMap}. If with \configClass{typeTransmitter}{gnssType} (e.g. '\verb|***G18|')
a single transmitter is selected the azimuth and elevation are computed from the transmitter point of view.

For each GNSS \configClass{type}{gnssType} an extra data column is created.

A \file{GNSS residual file}{instrument} includes additional information
besides the residuals, which can also be selected with \configClass{type}{gnssType}
\begin{itemize}
\item \verb|A1*|, \verb|E1*|: azimuth and elevation at receiver
\item \verb|A2*|, \verb|E2*|: azimuth and elevation at transmitter
\item \verb|I**|: Estimated slant total electron content (STEC)
\end{itemize}

Furthermore these files may include for each residual \configClass{type}{gnssType}
information about the redundancy and the accuracy relation $\sigma/\sigma_0$
of the estimated $\sigma$ versus the apriori $\sigma_0$ from the least squares adjustment.
The 3 values (residuals, redundancy, $\sigma/\sigma_0$) are coded with the same type.
To get access to all values the corresponding type must be repeated in \configClass{type}{gnssType}.

\fig{!hb}{0.5}{gnssResiduals2Skyplot}{fig:gnssResiduals2Skyplot}{GPS C2W residuals of GRAZ station at 2012-01-01}
)";

/***********************************************/

#include "programs/program.h"
#include "inputOutput/system.h"
#include "files/fileInstrument.h"
#include "files/fileGriddedData.h"
#include "misc/miscGriddedData.h"

/***** CLASS ***********************************/

/** @brief Convert residuals into griddedData format for plotting.
* @ingroup programsGroup */
class GnssResiduals2Skyplot
{
public:
  void run(Config &config, Parallel::CommunicatorPtr comm);
};

GROOPS_REGISTER_PROGRAM(GnssResiduals2Skyplot, SINGLEPROCESS, "Convert residuals into griddedData format for plotting", Gnss, Grid)
GROOPS_RENAMED_PROGRAM(GnssResiduals2GriddedData, GnssResiduals2Skyplot, date2time(2019, 9, 9))

/***********************************************/

void GnssResiduals2Skyplot::run(Config &config, Parallel::CommunicatorPtr /*comm*/)
{
  try
  {
    FileName              fileNameGriddedData;
    std::vector<FileName> fileNameResiduals;
    std::vector<GnssType> types;
    GnssType              typeTransmitter;
    Double                a, f;

    readConfig(config, "outputfileGriddedData", fileNameGriddedData, Config::MUSTSET,  "", "");
    readConfig(config, "type",                  types,               Config::MUSTSET,  "", "");
    readConfig(config, "typeTransmitter",       typeTransmitter,     Config::OPTIONAL, "", "choose transmitter view, e.g. '***G18'");
    readConfig(config, "inputfileResiduals",    fileNameResiduals,   Config::MUSTSET,  "", "GNSS receiver residuals");
    readConfig(config, "R",                     a,                   Config::DEFAULT,  STRING_DEFAULT_GRS80_a, "reference radius for ellipsoidal coordinates");
    readConfig(config, "inverseFlattening",     f,                   Config::DEFAULT,  STRING_DEFAULT_GRS80_f, "reference flattening for ellipsoidal coordinates");
    if(isCreateSchema(config)) return;

    // ============================

    Ellipsoid                        ellipsoid(a, f);
    std::vector<Vector3d>            points;
    std::vector<std::vector<Double>> values(types.size());
    for(const FileName &fileName : fileNameResiduals)
    {
      logStatus<<"read GNSS residuals <"<<fileName<<">"<<Log::endl;
      if(!System::exists(fileName))
      {
        logWarning<<"file not exist -> continue"<<Log::endl;
        continue;
      }

      InstrumentFile fileReceiver(fileName);
      for(UInt arcNo=0; arcNo<fileReceiver.arcCount(); arcNo++)
      {
        GnssReceiverArc arc = fileReceiver.readArc(arcNo);
        for(auto &epoch : arc)
        {
          UInt idObs = 0;
          for(GnssType satType : epoch.satellite)
          {
            // find type for the satellite system
            UInt idType = std::distance(epoch.obsType.begin(), std::find(epoch.obsType.begin(), epoch.obsType.end(), satType));

            // azimuth and elevation
            if((epoch.obsType.at(idType+0) != (GnssType::AZIMUT    + GnssType::L1)) ||
               (epoch.obsType.at(idType+1) != (GnssType::ELEVATION + GnssType::L1)) ||
               (epoch.obsType.at(idType+2) != (GnssType::AZIMUT    + GnssType::L2)) ||
               (epoch.obsType.at(idType+3) != (GnssType::ELEVATION + GnssType::L2)))
              throw(Exception("azimuth and elevation expected"));

            Double azimuth   = epoch.observation.at(idObs+0);
            Double elevation = epoch.observation.at(idObs+1);
            if(!typeTransmitter.hasWildcard(GnssType::PRN)) // isTransmitter
            {
              azimuth   = epoch.observation.at(idObs+2);
              elevation = epoch.observation.at(idObs+3);
            }
            const Vector3d point = ellipsoid(Angle(azimuth), Angle(elevation), 0);

            idObs  += 4;  // skip azimuth and elevation
            idType += 4;

            Bool                  found = FALSE;
            std::vector<Double>   valuesPerPoint(types.size(), NAN_EXPR);
            std::vector<GnssType> typesTmp = types;
            while((idType<epoch.obsType.size()) && (idObs<epoch.observation.size()) && (epoch.obsType.at(idType) == satType))
            {
              const GnssType type  = epoch.obsType.at(idType++) + satType;
              const Double   value = epoch.observation.at(idObs++);
              const UInt     idx   = GnssType::index(typesTmp, type);
              if((idx != NULLINDEX) && (type == typeTransmitter) && value)
              {
                valuesPerPoint.at(idx) = value;
                typesTmp.at(idx) = GnssType(static_cast<UInt64>(-1));
                found = TRUE;
              }
            } // while()

            if(found)
            {
              points.push_back(point);
              for(UInt i=0; i<values.size(); i++)
                values.at(i).push_back(valuesPerPoint.at(i));
            }
          } // for(satType)
        } // for(epoch)
      } // for(arcNo)
    } // for(idFile)

    // ============================

    logStatus<<"save values to file <"<<fileNameGriddedData<<">"<<Log::endl;
    GriddedData griddedData(ellipsoid, points, std::vector<Double>(points.size(), 1), values);
    writeFileGriddedData(fileNameGriddedData, griddedData);
    MiscGriddedData::printStatistics(griddedData);
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/
/***********************************************/