示例#1
0
def run_glabng_session(logger: logging.Logger):
    """
    run_glabng_session runs gLAB (v6.x) using provided configuration file
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    # uncompress the RINEX OBS file
    runGLABNG = '{prog:s} -input:cfg {cfg:s}'.format(
        prog=amc.dRTK['progs']['glabng'],
        cfg=os.path.join(amc.dRTK['proc']['dir_glab'],
                         amc.dRTK['proc']['glab_cfg']))
    logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName,
                                                     cmd=colored(
                                                         runGLABNG, 'green')))

    # run the program
    exeprogram.subProcessDisplayStdOut(cmd=runGLABNG, verbose=True)

    # compress the resulting "out" file
    runGZIP = '{prog:s} -f {zip:s}'.format(prog=amc.dRTK['progs']['gzip'],
                                           zip=os.path.join(
                                               amc.dRTK['proc']['dir_glab'],
                                               amc.dRTK['proc']['glab_out']))
    logger.info('{func:s}: compressing {out:s} file by:\n{cmd:s}'.format(
        out=amc.dRTK['proc']['glab_out'],
        func=cFuncName,
        cmd=colored(runGZIP, 'green')))
    # run the program
    exeprogram.subProcessDisplayStdErr(cmd=runGZIP, verbose=True)

    runGZIP
示例#2
0
def doNcFTPDownload(logger: logging.Logger):
    """
    doNcFTPDownload downloads remote files using 'ncftget' program
    """
    cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green')

    # locate 'ncftpget' program
    exeNCFTPGET = location.locateProg('ncftpget', logger)

    # create and change to download directory
    amc.dRTK['local']['YYDOY'] = '{YY:s}{DOY:s}'.format(YY=amc.dRTK['date']['YY'], DOY=amc.dRTK['date']['DoY'])
    amc.dRTK['local']['dir'] = os.path.join(amc.dRTK['local']['root'], amc.dRTK['local']['YYDOY'])
    amutils.mkdir_p(amc.dRTK['local']['dir'])
    amutils.changeDir(amc.dRTK['local']['dir'])
    logger.info('{func:s}: changed to local directory {dir:s}'.format(dir=amc.dRTK['local']['dir'], func=cFuncName))

    for gnss in amc.dRTK['remote'].keys():
        logger.info('{func:s}: downloading for {gnss:s} RINEX Nav {nav:s}'.format(gnss=gnss, nav=amc.dRTK['remote'][gnss]['rfile'], func=cFuncName))

        cmdNCFTPGET = '{prog:s} -u {user:s} -p {passwd:s} -v  ftp://{host:s}/{rpath}/{rfile:s}'.format(prog=exeNCFTPGET, user=amc.dRTK['ftp']['user'], passwd=amc.dRTK['ftp']['passwd'], host=amc.dRTK['ftp']['server'], rpath=amc.dRTK['remote'][gnss]['rpath'], rfile=amc.dRTK['remote'][gnss]['rfile'])

        logger.info('{func:s}: ... running {cmd:s}'.format(cmd=cmdNCFTPGET, func=cFuncName))

        # run the program
        exeprogram.subProcessDisplayStdErr(cmd=cmdNCFTPGET, verbose=True)
示例#3
0
def rnxobs_parse_prns(dArgs: dict, dProgs: dict, logger: logging.Logger) -> list:
    """
    rnxobs_parse_prns gets th elist of PRNs in observation file
    """
    cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green')

    prns_name = os.path.join(tempfile.gettempdir(), '{tmpname:s}.prns'.format(tmpname=uuid.uuid4().hex))

    cmdGFZRNX = '{prog:s} -stk_epo {interval:d} -finp {obs:s} -fout {prns:s}'.format(prog=dProgs['gfzrnx'], interval=dArgs['interval'], obs=dArgs['obs_name'], prns=prns_name)
    logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName, cmd=colored(cmdGFZRNX, 'blue')))

    # run the program
    # gfzrnx -stk_epo 300-finp data/P1710171.20O
    exeprogram.subProcessDisplayStdErr(cmd=cmdGFZRNX, verbose=False)

    # extract the PRNs which are last elements in lines starting with STE
    lstPRNS = []
    logger.info('{func:s}: display of observation time span'.format(func=cFuncName))
    with open(prns_name) as f:
        for line in f:
            # print('{line:s} -- {STE!s}'.format(line=line, STE=line.startswith(' STE')))
            if line.startswith(' STE'):
                lstPRNS.append(line.split('|')[-1].strip())
            logger.info(line[:-1])

    logger.info('{func:s}: list of PRNs with observations\n   {prns!s}'.format(prns=', '.join(lstPRNS), func=cFuncName))

    # remove the temporary json file
    os.remove(prns_name)

    return lstPRNS
示例#4
0
def uncompress_rnx_files(logger: logging.Logger):
    """
    uncompress_rnx_files uncompresses RINEX OBS & NAV files
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    # uncompress the RINEX OBS file
    runCRZ2RNX = '{prog:s} -f {crz:s}'.format(
        prog=amc.dRTK['progs']['crz2rnx'],
        crz=os.path.join(amc.dRTK['proc']['dir_rnx'],
                         amc.dRTK['proc']['cmp_obs']))
    logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName,
                                                     cmd=colored(
                                                         runCRZ2RNX, 'green')))

    # run the program
    exeprogram.subProcessDisplayStdErr(cmd=runCRZ2RNX, verbose=True)

    # get name of uncompressed file
    amc.dRTK['proc']['obs'] = amc.dRTK['proc']['cmp_obs'][:-3] + 'O'

    # check if this decompressed file exists
    path = pathlib.Path(
        os.path.join(amc.dRTK['proc']['dir_rnx'], amc.dRTK['proc']['obs']))
    if not path.is_file():
        logger.info(
            '{func:s}: Failed creating decompressed RINEX observation file {obs:s}'
            .format(obs=colored(amc.dRTK['proc']['obs'], 'green'),
                    func=cFuncName))

    # decompress allnavigation files
    amc.dRTK['proc']['nav'] = []
    for cmp_nav in amc.dRTK['proc']['cmp_nav']:
        runGUNZIP = '{prog:s} -f {zip:s}'.format(
            prog=amc.dRTK['progs']['gunzip'],
            zip=os.path.join(amc.dRTK['proc']['dir_igs'], cmp_nav))
        logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName,
                                                         cmd=colored(
                                                             runGUNZIP,
                                                             'green')))

        # run the program
        exeprogram.subProcessDisplayStdErr(cmd=runGUNZIP, verbose=True)

        # get name of uncompressed file
        amc.dRTK['proc']['nav'].append(cmp_nav[:-3])

        # check if this decompressed file exists
        path = pathlib.Path(
            os.path.join(amc.dRTK['proc']['dir_igs'],
                         amc.dRTK['proc']['nav'][-1]))
        if not path.is_file():
            logger.info(
                '{func:s}: Failed creating decompressed RINEX navigation file {nav:s}'
                .format(nav=colored(amc.dRTK['proc']['nav'], 'green'),
                        func=cFuncName))
示例#5
0
def roverobs_decomp(logger: logging.Logger):
    """
    roverobs_decomp decompresses the hatanake/compressed file
    """
    cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green')

    # check the end of roverObs filename
    if amc.dRTK['roverObs'].endswith('D.Z'):
        logger.info('{func:s}: decompressing {comp:s}'.format(comp=amc.dRTK['roverObs'], func=cFuncName))

        cmdCRZ2RNX = '{prog:s} -f {comp:s}'.format(prog=amc.dRTK['exeCRZ2RNX'], comp=amc.dRTK['roverObs'])
        logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName, cmd=colored(cmdCRZ2RNX, 'green')))

        # run the program
        exeprogram.subProcessDisplayStdErr(cmd=cmdCRZ2RNX, verbose=True)

    # name the file to use from now on
    amc.dRTK['rover2proc'] = '{base:s}.{ext:s}'.format(base=amc.dRTK['roverObsParts'][0], ext=amc.dRTK['roverObsParts'][1].replace('D', 'O'))

    logger.info('{func:s}: amc.dRTK = \n{json!s}'.format(func=cFuncName, json=json.dumps(amc.dRTK, sort_keys=False, indent=4)))
示例#6
0
def rnxobs_header_metadata(dArgs: dict, dProgs: dict, logger: logging.Logger) -> dict:
    """
    rnxobs_header_metadata reads the rinex observation file header and extracts info
    """
    cFuncName = colored(os.path.basename(__file__), 'yellow') + ' - ' + colored(sys._getframe().f_code.co_name, 'green')

    # extract the header meta data into a json structure
    json_name = os.path.join(tempfile.gettempdir(), '{tmpname:s}.json'.format(tmpname=uuid.uuid4().hex))

    cmdGFZRNX = '{prog:s} -meta basic:jsonp -finp {obs:s} -fout {json:s}'.format(prog=dProgs['gfzrnx'], obs=dArgs['obs_name'], json=json_name)
    logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName, cmd=colored(cmdGFZRNX, 'blue')))

    # run the program
    # gfzrnx -finp data/P1710171.20O -meta basic:jsonp
    exeprogram.subProcessDisplayStdErr(cmd=cmdGFZRNX, verbose=False)

    with open(json_name) as json_file:
        hdr_obs = json.load(json_file)

    # remove the temporary json file
    os.remove(json_name)

    return hdr_obs
示例#7
0
def cleanup_rnx_files(logger: logging.Logger):
    """
    cleanup_rnx_files cleans up the uncompressed RINEX obs & nav files (restoring original state)
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    # remove obs rinex file used
    logger.info('{func:s}: removal of OBS file {obs:s}'.format(
        obs=amc.dRTK['proc']['obs'], func=cFuncName))
    os.remove(
        os.path.join(amc.dRTK['proc']['dir_rnx'], amc.dRTK['proc']['obs']))

    # recompress the navigation files
    for nav_file in amc.dRTK['proc']['nav']:
        runGZIP = '{prog:s} -f {zip:s}'.format(prog=amc.dRTK['progs']['gzip'],
                                               zip=os.path.join(
                                                   amc.dRTK['proc']['dir_igs'],
                                                   nav_file))
        logger.info('{func:s}: compressing {nav:s} file by:\n{cmd:s}'.format(
            nav=nav_file, func=cFuncName, cmd=colored(runGZIP, 'green')))
        # run the program
        exeprogram.subProcessDisplayStdErr(cmd=runGZIP, verbose=True)
示例#8
0
def main(argv):
    """
    pyRnxProc processes RINEX data using 'amrnx2rtkp'

    """
    amc.cBaseName = colored(os.path.basename(__file__), 'yellow')
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    # pandas options
    pd.options.display.max_rows = 40
    pd.options.display.max_columns = 36
    pd.options.display.width = 2000

    # limit float precision
    encoder.FLOAT_REPR = lambda o: format(o, '.3f')

    # treat command line options
    rootDir, roverObs, posMode, freq, cutOff, baseObs, ephemeris, gnss, typeEphem, tropo, iono, template, overwrite, logLevels = treatCmdOpts(
        argv)

    # create logging for better debugging
    logger = amc.createLoggers(baseName=os.path.basename(__file__),
                               dir=rootDir,
                               logLevels=logLevels)

    # store cli parameters
    amc.dRTK = {}
    amc.dRTK['rootDir'] = rootDir
    amc.dRTK['roverObs'] = roverObs
    amc.dRTK['posMode'] = posMode
    amc.dRTK['freq'] = [v for k, v in rtkc.dFreq.items() if k == freq][0]
    amc.dRTK['cutOff'] = cutOff
    amc.dRTK['baseObs'] = baseObs
    amc.dRTK['ephems'] = ephemeris
    amc.dRTK['GNSS'] = gnss
    amc.dRTK['typeEphem'] = typeEphem
    amc.dRTK['Tropo'] = tropo
    amc.dRTK['Iono'] = iono
    amc.dRTK['template'] = template

    # check validity of passed arguments
    retCode = checkValidityArgs(logger=logger)
    if retCode != amc.E_SUCCESS:
        logger.error('{func:s}: Program exits with code {error:s}'.format(
            func=cFuncName, error=colored('{!s}'.format(retCode), 'red')))
        sys.exit(retCode)

    # create the configuration file for the GNSSs to process
    amc.dRTK['config'] = os.path.join(
        amc.dRTK['rtkDir'], '{rover:s}-{syst:s}.conf'.format(
            rover=amc.dRTK['roverObs'].split('.')[0],
            syst=amc.dRTK['GNSS'].upper()))

    logger.info(
        '{func:s}: Creating {syst:s} configuration file {conf:s}'.format(
            func=cFuncName,
            syst=colored(gnss, 'green'),
            conf=colored(amc.dRTK['config'], 'green')))

    # create the settings used for replacing the fields in the template file
    template_rnx2rtkp.create_rnx2rtkp_settings(overwrite=overwrite,
                                               logger=logger)

    template_rnx2rtkp.create_rnx2rtkp_template(cfgFile=amc.dRTK['config'],
                                               overwrite=overwrite,
                                               logger=logger)

    logger.info('{func:s}: amc.dRTK = \n{json!s}'.format(func=cFuncName,
                                                         json=json.dumps(
                                                             amc.dRTK,
                                                             sort_keys=False,
                                                             indent=4)))

    # locate the rnx2rtkp program used for execution
    exeRNX2RTKP = location.locateProg('rnx2rtkp', logger)

    cmdRNX2RTKP = '{prog:s} -k {conf:s} -o {pos:s} {rover:s} {base:s} {nav:s}'.format(
        prog=exeRNX2RTKP,
        conf=amc.dRTK['config'],
        pos=amc.dRTK['filePos'],
        rover=amc.dRTK['roverObs'],
        base=amc.dRTK['baseObs'],
        nav=' '.join(amc.dRTK['ephems']))

    logger.info('{func:s}: Running:\n{cmd:s}'.format(func=cFuncName,
                                                     cmd=colored(
                                                         cmdRNX2RTKP,
                                                         'green')))

    # run the program
    if amc.dLogLevel[logLevels[0]] >= amc.dLogLevel['INFO']:
        exeprogram.subProcessDisplayStdErr(cmd=cmdRNX2RTKP, verbose=True)
    else:
        exeprogram.subProcessDisplayStdErr(cmd=cmdRNX2RTKP, verbose=False)

    # inform user
    logger.info('{func:s}: Created position file: {pos:s}'.format(
        func=cFuncName, pos=colored(amc.dRTK['filePos'], 'blue')))
    logger.info('{func:s}: Created statistics file: {stat:s}'.format(
        func=cFuncName, stat=colored(amc.dRTK['fileStat'], 'blue')))
示例#9
0
def main(argv) -> bool:
    """
    glabplotposn plots data from gLAB (v6) OUTPUT messages

    """
    amc.cBaseName = colored(os.path.basename(__file__), 'yellow')
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    # limit float precision
    # encoder.FLOAT_REPR = lambda o: format(o, '.3f')
    # pd.options.display.float_format = "{:,.3f}".format

    # treat command line options
    dir_root, glab_cmp_out, scale_enu, center_enu, db_cvs, show_plot, log_levels = treatCmdOpts(
        argv)

    # create logging for better debugging
    logger, log_name = amc.createLoggers(os.path.basename(__file__),
                                         dir=dir_root,
                                         logLevels=log_levels)

    # store cli parameters
    amc.dRTK = {}
    amc.dRTK['dir_root'] = dir_root
    amc.dRTK['glab_cmp_out'] = glab_cmp_out

    # create sub dict for gLAB related info
    dgLABng = {}
    dgLABng['dir_glab'] = 'glabng'
    dgLABng['db'] = db_cvs

    amc.dRTK['dgLABng'] = dgLABng

    # check some arguments
    ret_val = check_arguments(logger=logger)
    if ret_val != amc.E_SUCCESS:
        sys.exit(ret_val)

    # open or create the database file for storing the statistics
    glab_updatedb.open_database(db_name=amc.dRTK['dgLABng']['db'],
                                logger=logger)

    # glab_updatedb.db_update_line(db_name=amc.dRTK['dgLABng']['db'], line_id='2019,134', info_line='2019,134,new thing whole line for ', logger=logger)

    # get location of progs used
    amc.dRTK['progs'] = {}
    amc.dRTK['progs']['gunzip'] = location.locateProg('gunzip', logger)
    amc.dRTK['progs']['gzip'] = location.locateProg('gzip', logger)

    # uncompress the "out" file
    runGUNZIP = '{prog:s} -f -v {zip:s}'.format(
        prog=amc.dRTK['progs']['gunzip'],
        zip=os.path.join(amc.dRTK['dir_root'], amc.dRTK['glab_cmp_out']))
    logger.info('{func:s}: Uncompressing file {cmp:s}:\n{cmd:s}'.format(
        func=cFuncName,
        cmd=colored(runGUNZIP, 'green'),
        cmp=colored(amc.dRTK['glab_cmp_out'], 'green')))

    # run the program
    exeprogram.subProcessDisplayStdErr(cmd=runGUNZIP, verbose=True)

    # get name of uncompressed file
    amc.dRTK['glab_out'] = amc.dRTK['glab_cmp_out'][:-3]

    # split gLABs out file in parts
    glab_msgs = glc.dgLab['messages'][0:2]  # INFO & OUTPUT messages needed
    dglab_tmpfiles = glab_split_outfile.split_glab_outfile(
        msgs=glab_msgs, glab_outfile=amc.dRTK['glab_out'], logger=logger)

    # read in the INFO messages from INFO temp file
    amc.dRTK['INFO'] = glab_parser_info.parse_glab_info(
        glab_info=dglab_tmpfiles['INFO'], logger=logger)
    # write the identification to the database file for glabng output messages
    # glab_updatedb.db_update_line(db_name=amc.dRTK['dgLABng']['db'], line_id=amc.dRTK['INFO']['db_lineID'], info_line=amc.dRTK['INFO']['db_lineID'], logger=logger)

    # read in the OUTPUT messages from OUTPUT temp file
    df_output = glab_parser_output.parse_glab_output(
        glab_output=dglab_tmpfiles['OUTPUT'], logger=logger)
    # save df_output as CSV file
    amc.dRTK['dgLABng']['pos'] = store_to_cvs(df=df_output,
                                              ext='pos',
                                              logger=logger,
                                              index=False)

    # compress the stored CVS file
    runGZIP = '{prog:s} -f -v {zip:s}'.format(
        prog=amc.dRTK['progs']['gzip'],
        zip=os.path.join(amc.dRTK['dir_root'], amc.dRTK['dgLABng']['dir_glab'],
                         amc.dRTK['dgLABng']['pos']))
    logger.info('{func:s}: Compressing file {cmp:s}:\n{cmd:s}'.format(
        func=cFuncName,
        cmd=colored(runGZIP, 'green'),
        cmp=colored(amc.dRTK['dgLABng']['pos'], 'green')))
    # run the program
    exeprogram.subProcessDisplayStdErr(cmd=runGZIP, verbose=True)

    # calculate statitics gLAB OUTPUT messages
    amc.dRTK['dgLABng'][
        'stats'], dDB_crds = glab_statistics.statistics_glab_outfile(
            df_outp=df_output, logger=logger)

    for key, val in dDB_crds.items():
        glab_updatedb.db_update_line(
            db_name=amc.dRTK['dgLABng']['db'],
            line_id='{id:s},{crd:s}'.format(id=amc.dRTK['INFO']['db_lineID'],
                                            crd=key),
            info_line='{id:s},{val:s}'.format(id=amc.dRTK['INFO']['db_lineID'],
                                              val=val),
            logger=logger)

    # sort the glab_output_db
    glab_updatedb.db_sort(db_name=amc.dRTK['dgLABng']['db'], logger=logger)
    # sys.exit(2)

    # plot the gLABs OUTPUT messages
    # - position ENU and PDOP plots
    glab_plot_output_enu.plot_glab_position(dfCrd=df_output,
                                            scale=scale_enu,
                                            showplot=show_plot,
                                            logger=logger)
    # - scatter plot of EN per dop bind
    glab_plot_output_enu.plot_glab_scatter(dfCrd=df_output,
                                           scale=scale_enu,
                                           center=center_enu,
                                           showplot=show_plot,
                                           logger=logger)
    # - scatter plot of EN per dop bind (separate)
    glab_plot_output_enu.plot_glab_scatter_bin(dfCrd=df_output,
                                               scale=scale_enu,
                                               center=center_enu,
                                               showplot=show_plot,
                                               logger=logger)
    # - plot the DOP parameters
    glab_plot_output_enu.plot_glab_xdop(dfCrd=df_output,
                                        showplot=show_plot,
                                        logger=logger)
    # - plot the ENU box plots per DOP bin
    glab_plot_output_stats.plot_glab_statistics(
        df_dopenu=df_output[glc.dgLab['OUTPUT']['XDOP'] +
                            glc.dgLab['OUTPUT']['dENU']],
        scale=scale_enu,
        showplot=show_plot,
        logger=logger)

    # report to the user
    logger.info('{func:s}: Project information =\n{json!s}'.format(
        func=cFuncName,
        json=json.dumps(amc.dRTK,
                        sort_keys=False,
                        indent=4,
                        default=amutils.DT_convertor)))

    # sort the glab_output_db
    glab_updatedb.db_sort(db_name=amc.dRTK['dgLABng']['db'], logger=logger)

    # recompress the "out" file
    runGZIP = '{prog:s} -f -v {zip:s}'.format(prog=amc.dRTK['progs']['gzip'],
                                              zip=os.path.join(
                                                  amc.dRTK['dir_root'],
                                                  amc.dRTK['glab_out']))
    logger.info('{func:s}: Compressing file {cmp:s}:\n{cmd:s}'.format(
        func=cFuncName,
        cmd=colored(runGZIP, 'green'),
        cmp=colored(amc.dRTK['glab_out'], 'green')))
    # run the program
    exeprogram.subProcessDisplayStdErr(cmd=runGZIP, verbose=True)

    # store the json structure
    json_out = amc.dRTK['glab_out'].split('.')[0] + '.json'
    with open(json_out, 'w') as f:
        json.dump(amc.dRTK,
                  f,
                  ensure_ascii=False,
                  indent=4,
                  default=amutils.DT_convertor)
    logger.info('{func:s}: created json file {json:s}'.format(func=cFuncName,
                                                              json=colored(
                                                                  json_out,
                                                                  'green')))

    # copy temp log file to the YYDOY directory
    copyfile(
        log_name,
        os.path.join(
            amc.dRTK['dir_root'],
            '{obs:s}-{prog:s}'.format(obs=amc.dRTK['glab_out'].split('.')[0],
                                      prog='output.log')))
    os.remove(log_name)

    return amc.E_SUCCESS
示例#10
0
def rnxobs_dataframe(rnx_file: str, prn: str, dPRNSysObs: dict, dProgs: dict,
                     logger: logging.Logger) -> dict:
    """
    rnxobs_dataframe selects the observations for a PRN and returns observation dataframe
    """
    cFuncName = colored(os.path.basename(__file__),
                        'yellow') + ' - ' + colored(
                            sys._getframe().f_code.co_name, 'green')

    logger.info(
        '{func:s}: creating dataframe for PRN {prn:s} with observations {obs:s}'
        .format(prn=prn, obs=', '.join(dPRNSysObs), func=cFuncName))

    # create tabular output for this PRN
    tab_name = os.path.join(tempfile.gettempdir(),
                            '{tmpname:s}.tab'.format(tmpname=uuid.uuid4().hex))

    cmdGFZRNX = '{prog:s} -finp {rnx:s} -fout {out:s} -tab_obs -tab_sep "," -prn {prn:s} -obs_types={obs:s}'.format(
        prog=dProgs['gfzrnx'],
        rnx=rnx_file,
        out=tab_name,
        prn=prn,
        obs=','.join(dPRNSysObs))

    logger.info('{func:s}: Running:\n{prog:s}'.format(prog=colored(
        cmdGFZRNX, 'blue'),
                                                      func=cFuncName))

    # run the program
    # gfzrnx -finp P1710171.20O -tab_obs -fout P1710171_20O.tab -prn E09 -obs_types C1C,C5Q -tab_sep ','
    exeprogram.subProcessDisplayStdErr(cmd=cmdGFZRNX, verbose=False)

    # find the header lines that don't belong to this GNSS system and remove that line
    hdlookup = '#HD,'
    gnsslookup = '#HD,{gnss:s}'.format(gnss=prn[0])

    hd_lines = []
    gnss_lines = []
    with open(tab_name) as f:
        for num, line in enumerate(f, 1):
            if hdlookup in line:
                # print('found at line: ', num)
                hd_lines.append(num)
            if gnsslookup in line:
                # print('found at line: ', num)
                gnss_lines.append(num)

    # print('hd_lines = {!s}'.format(hd_lines))
    # print('gnss_lines = {!s}'.format(gnss_lines))

    remove_lines = [linenr for linenr in hd_lines if linenr not in gnss_lines]
    # print('remove_lines = {!s}'.format(remove_lines))

    # remove the lines that are not related to current GNSS
    amutils.delete_lines(original_file=tab_name, lst_line_number=remove_lines)

    # read the CSV created file into a panda dataframe
    dfPrn = pd.read_csv(tab_name, delimiter=',')
    # add datetime columns
    sDT = dfPrn.apply(lambda x: DT_from_DTstr(x['DATE'], x['TIME']), axis=1)
    dfPrn.insert(loc=4, column='DT', value=sDT)

    amutils.logHeadTailDataFrame(
        logger=logger,
        callerName=cFuncName,
        df=dfPrn,
        dfName='{tab:s}'.format(tab='{prn:s} with observables = {obs!s}'.
                                format(prn=prn, obs=', '.join(dPRNSysObs))))

    # remove the temporary tabular file
    os.remove(tab_name)

    return dfPrn