Use simulation datasets ******************************* Huxon applications can be simulated offline to check the expected behavior by providing custom datasets for every declared **sensor**. A **simulation dataset** can be declared using the :c:macro:`HUX_DECLARE_SIMULATION_DATA` construct: .. code-block:: cpp /* * simulation_dataset : the simulation_dataset label * data : a hux::tuple of std::vector containing the custom dataset */ HUX_DECLARE_SIMULATION_DATA(simulation_dataset, hux::tuple< std::vector<...>, ...> data); The **data** parameter is expected to be a :cpp:class:`hux::tuple` consisting of one or more std::vector. Each std::vector represents a data series of a given type. This flexibility is required since every sensor needs a specific number and types of data series, (e.g. one for acceleration on X axis, one for acceleration on Y axis, etc..). As an example, for sensor :ref:`IIS2DLPC` we need to provide a :cpp:class:`hux::tuple` containing, in order, the following vectors: - std::vector: Acceleration on the X axis in g units - std::vector: Acceleration on the Y axis in g units - std::vector: Acceleration on the Z axis in g units - std::vector: Unix timestamp in milliseconds of the data generated by the sensor .. note:: To know the simulation data type required by a specific sensor, check the :ref:`sensors` documentation. There are different ways to specify the actual simulation **data**. The first possibility is to construct the simulation data directly using :cpp:member:`hux::make_tuple` as: .. code-block:: cpp HUX_DECLARE_SIMULATION_DATA(simulation_dataset, hux::make_tuple( std::vector{1.0, -0.5, 0.3}, /* Acceleration on X axis */ std::vector{2.1, -1.5, 1.2}, /* Acceleration on Y axis */ std::vector{1.1, 1.0, -0.9}, /* Acceleration on Z axis */ std::vector{1656684224000, 1656684225000, 1656684226000} /* Timestamp */ )); This approach is useful for simple tests, however, for more complex applications it is usually more convenient to load simulation data from a CSV file using the :cpp:member:`hux::simulation::load_csv` method: .. code-block:: cpp /* * <...> : template parameters indicating the type of each CSV file column * "./dataset.csv" : the CSV file with its relative path * ";" : the separator used inside the CSV file */ HUX_DECLARE_SIMULATION_DATA(simulation_dataset, hux::simulation::load_csv("./dataset.csv", ";") ); The :cpp:member:`hux::simulation::load_csv` returns a :cpp:class:`hux::tuple` of std::vectors by loading the dataset from a CSV file ("./dataset.csv") using a specific column separator (";"). The template parameter of the :cpp:member:`hux::simulation::load_csv` method specifies how many columns to read and what is the type of each column. Each column from the CSV file corresponds to a vector of the tuple in the same order. In the previous code snippet, the columns of the CSV file will be treated as: - column 1: std::vector< **float** > - column 2: std::vector< **float** > - column 3: std::vector< **float** > - column 4: std::vector< :cpp:member:`hux::uint64_t` > The first row of the CSV file is completely ignored and can be used by the programmer to specify column names for reference. An example of a valid CSV file that could be loaded by the previous code is: .. code-block:: txt X; Y; Z; timestamp 1.0; 0.3; 0.5; 1656684224000 -0.5; 0.8; 0.4; 1656684225000 -1.1; 1.1; 0.6; 1656684226000 Acceleration norm example =========================== The following example shows how to write a simple application that computes the squared norm of the acceleration from an inertial sensor with simulation data. Note that in this example we have introduced two new channel logics: "zip_latest" and "on_change": - A *zip_latest channel* outputs a :cpp:class:`hux::tuple` that combines (in order) the most recent samples from each input only when **ALL** inputs have produced at least a new sample - An *on_change channel* forwards the input data as output only when it differs from its previous value Notice also the use of the :cpp:class:`hux::get` method to retrieve an element from a :cpp:class:`hux::tuple`. .. code-block:: cpp /* Import Huxon language headers */ #include #include /* Import other libraries */ #include /* Set a namespace alias to ease constants and methods retrieval from vendor's namespace. */ namespace STM = hux::sensors::STMicroelectronics; /* Declare a dataset to simulate the algorithm with huxc. * The dataset is loaded from the CSV file "./dataset.csv" using semicolon separators. * The CSV file is expected to have 4 columns of types: * float | float | float | hux::uint64_t * */ HUX_DECLARE_SIMULATION_DATA(simulation_dataset, hux::simulation::load_csv("./dataset.csv", ";") ); /* Declare a new sensor called "my_sensor" */ HUX_DECLARE_SENSOR(my_sensor, STM::IIS2DLPC, simulation_dataset); /* Declare a zip_latest channel with inputs: * X, Y and Z acceleration sources from "my_sensor". * A zip_latest channel outputs an hux::tuple that combines (in order) the most recent * samples from each input only when ALL inputs have produced at least a new sample. * Here, the output of the channel will be of type: hux::tuple * */ HUX_DECLARE_CHANNEL(my_sensor_ch, zip_latest, my_sensor.get_accX(), my_sensor.get_accY(), my_sensor.get_accZ() ); /* Declare a processing node to compute the squared norm of the acceleration. * The processing node will be called every time "my_sensor_data" produces an output. * The data from "my_sensor_data" is provided by the "hux_input" variable, that in this * case is of type: hux::tuple. * To retrieve a specific field of the tuple we can use: hux::get(hux_input) * */ HUX_DECLARE_PROCESSING(squared_norm, my_sensor_ch, { float acc_x = hux::get<0>(hux_input); float acc_y = hux::get<1>(hux_input); float acc_z = hux::get<2>(hux_input); return pow(acc_x, 2) + pow(acc_y, 2) + pow(acc_z, 2); }); /* Declare a channel with "on_change" logic that forwards the norm_squared * data only when it changes from its previous value. * */ HUX_DECLARE_CHANNEL(squared_norm_changed_ch, on_change, squared_norm); /* Declare a processing node to prepare the output data for the algorithm. * the output data of the algorithm must be declared using "HUX_DECLARE_OUTPUT_VALUE". * */ HUX_DECLARE_PROCESSING(app_output, squared_norm_changed_ch, { HUX_DECLARE_OUTPUT_VALUE(result, Float, "acceleration_norm", hux_input); return result; }); /* Set the data produced by "app_output" as the result of the application */ HUX_REGISTER_OUTPUT(app_output); Check simulation results ========================= To check the result of the simulation, simply run the following command from the development container terminal: .. code-block:: bash huxc simulate -n YOUR_APP_NAME The output of the simulation will look similar to the following: .. code-block:: txt [INFO] Capturing virtual sensor output: { "acceleration_norm":1.07432234 } { "acceleration_norm":1.42203546 } [INFO] Simulation completed successfully!