Example: obs_mox_model_rawlog

C++ example source code:

/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2024, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <mrpt/config/CConfigFile.h>
#include <mrpt/io/CFileGZInputStream.h>
#include <mrpt/io/CFileGZOutputStream.h>
#include <mrpt/math/ops_containers.h>
#include <mrpt/obs/CObservationGasSensors.h>
#include <mrpt/serialization/CArchive.h>
#include <mrpt/system/filesystem.h>

#include <iostream>

using namespace mrpt;
using namespace mrpt::system;
using namespace mrpt::obs;
using namespace std;
using namespace mrpt::config;
using namespace mrpt::io;
using namespace mrpt::math;
using namespace mrpt::serialization;

int main(int argc, char** argv)
{
    // Variables
    string rawlog_file, sensorLabel;
    int enoseID, sensorType, indexMonitoredSensor,
        delay_value;  // decimate_value, winNoise_size
    mrpt::obs::CObservationGasSensors::CMOSmodel MOSmodel;
    bool have_estimation, apply_delay;

    // Load configuration:
    if (mrpt::system::fileExists("./CONFIG_MOXmodel.ini"))
    {
        cout << "Using configuration from './CONFIG_MOXmodel.ini'" << endl;
        CConfigFile conf("./CONFIG_MOXmodel.ini");

        rawlog_file = conf.read_string("", "rawlog_file", "", true);
        sensorLabel = conf.read_string("", "sensorLabel", "Full_MCEnose", true);
        enoseID = conf.read_int("", "enoseID", 0, true);
        std::string sensorType_str =
            conf.read_string("", "sensorType", "-1", true);
        stringstream convert(sensorType_str);
        convert >> std::hex >> sensorType;

        // Delays
        apply_delay = conf.read_bool("", "apply_delay", false, true);
        delay_value = conf.read_int("", "delay_value", 0, true);

        // MOX model parameters
        MOSmodel.a_rise = conf.read_float("", "a_rise", 0.0, true);
        MOSmodel.b_rise = conf.read_float("", "b_rise", 0.0, true);
        MOSmodel.a_decay = conf.read_float("", "a_decay", 0.0, true);
        MOSmodel.b_decay = conf.read_float("", "b_decay", 0.0, true);
        MOSmodel.winNoise_size = conf.read_int("", "winNoise_size", 0, true);
        MOSmodel.decimate_value = conf.read_int("", "decimate_value", 0, true);
        // save_maplog = conf.read_bool("","save_maplog",false,true);

        indexMonitoredSensor = -1;
    }
    else
    {
        cout << "Configuration file (ini) cannot be found\n" << endl;
        // If you are in VisualStudio, assure that the working directory in the
        // project properties is correctly set
        return -1;
    }

    // Open Rawlogs
    cout << "Processing Rawlog " << rawlog_file << endl;
    cout << "Obtaining MOXmodel from " << sensorLabel << "(" << enoseID
         << ") - sensor " << sensorType << endl;
    CFileGZInputStream file_input;
    CFileGZOutputStream file_output;

    file_input.open(rawlog_file);
    file_output.open("MOX_model_output.rawlog");

    if (!file_input.fileOpenCorrectly() || !file_output.fileOpenCorrectly())
        cout << "Error opening rawlog file" << endl;

    // Process rawlog
    bool read = true;
    while (read)
    {
        try
        {
            CSerializable::Ptr o;
            archiveFrom(file_input) >> o;

            if (o)  // ASSERT_(o);
            {
                if (IS_CLASS(*o, CObservationGasSensors))
                {
                    CObservationGasSensors::Ptr obs =
                        std::dynamic_pointer_cast<CObservationGasSensors>(o);

                    // Correct delay on gas readings
                    if (apply_delay)
                        obs->timestamp = obs->timestamp -
                            std::chrono::milliseconds(delay_value);

                    if (obs->sensorLabel == sensorLabel)
                    {
                        //------------------------------------------------------
                        // Get reading from CH_i for gas distribution estimation
                        //------------------------------------------------------
                        float raw_reading;

                        if (sensorType == 0)
                        {  // compute the mean
                            raw_reading = math::mean(
                                obs->m_readings[enoseID].readingsVoltage);
                        }
                        else
                        {
                            // Get the reading of the specified sensorID
                            if (indexMonitoredSensor == -1)
                            {
                                // First reading, get the index according to
                                // sensorID
                                for (indexMonitoredSensor = 0;
                                     indexMonitoredSensor <
                                     (int)obs->m_readings[enoseID]
                                         .sensorTypes.size();
                                     indexMonitoredSensor++)
                                {
                                    if (obs->m_readings[enoseID].sensorTypes.at(
                                            indexMonitoredSensor) ==
                                        std::vector<int>::value_type(
                                            sensorType))
                                        break;
                                }
                            }

                            if (indexMonitoredSensor <
                                (int)obs->m_readings[enoseID]
                                    .sensorTypes.size())
                            {
                                raw_reading =
                                    obs->m_readings[enoseID].readingsVoltage.at(
                                        indexMonitoredSensor);
                            }
                            else  // Sensor especified not found, compute
                            // default mean value
                            {
                                cout << "sensorType not found. Computing the "
                                        "mean value"
                                     << endl;
                                raw_reading = math::mean(
                                    obs->m_readings[enoseID].readingsVoltage);
                            }
                        }

                        // Obtain MOX model output
                        TPose3D MOXmodel_pose =
                            obs->m_readings[enoseID].eNosePoseOnTheRobot;
                        float MOXmodel_estimation = raw_reading;
                        mrpt::system::TTimeStamp MOXmodel_timestamp =
                            obs->timestamp;

                        have_estimation =
                            MOSmodel.get_GasDistribution_estimation(
                                MOXmodel_estimation, MOXmodel_timestamp);

                        if (have_estimation)
                        {
                            // Save as new obs
                            mrpt::obs::CObservationGasSensors::TObservationENose
                                gd_est;
                            gd_est.hasTemperature = false;
                            gd_est.temperature = 0.0;
                            gd_est.isActive = false;
                            gd_est.sensorTypes.push_back(
                                0x0001);  // indicates that is a MOXmodel output
                            gd_est.readingsVoltage.push_back(
                                MOXmodel_estimation);
                            gd_est.eNosePoseOnTheRobot = MOXmodel_pose;

                            auto obs_GDM = CObservationGasSensors::Create();
                            obs_GDM->sensorLabel = "GDM";
                            // modify timestamp to deal with the delay of the
                            // model
                            obs_GDM->timestamp = MOXmodel_timestamp;
                            obs_GDM->m_readings.push_back(gd_est);

                            archiveFrom(file_output) << obs_GDM;
                        }
                    }
                }

                // Save current sensor obs to the new Rawlog file
                auto arch = archiveFrom(file_output);
                arch << o;
            }
        }
        catch (exception& e)
        {
            cout << "Exception: " << e.what() << endl;
            file_input.close();
            file_output.close();
            read = false;
        }
    }

    return 0;
}