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 HUX_DECLARE_SIMULATION_DATA
construct:
/*
* 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 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 IIS2DLPC we need to provide a hux::tuple
containing, in order, the following vectors:
std::vector<float>: Acceleration on the X axis in g units
std::vector<float>: Acceleration on the Y axis in g units
std::vector<float>: Acceleration on the Z axis in g units
std::vector<hux::uint64_t>: 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 Sensors documentation.
There are different ways to specify the actual simulation data.
The first possibility is to construct the simulation data directly using hux::make_tuple
as:
HUX_DECLARE_SIMULATION_DATA(simulation_dataset, hux::make_tuple(
std::vector<float>{1.0, -0.5, 0.3}, /* Acceleration on X axis */
std::vector<float>{2.1, -1.5, 1.2}, /* Acceleration on Y axis */
std::vector<float>{1.1, 1.0, -0.9}, /* Acceleration on Z axis */
std::vector<hux::uint64_t>{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 hux::simulation::load_csv
method:
/*
* <...> : 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<float, float, float, hux::uint64_t>("./dataset.csv", ";")
);
The hux::simulation::load_csv
returns a 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 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<
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:
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
hux::tuple
that combines (in order) the most recent samples from each input only when ALL inputs have produced at least a new sampleAn on_change channel forwards the input data as output only when it differs from its previous value
Notice also the use of the hux::get
method to retrieve an element from a hux::tuple
.
/* Import Huxon language headers */
#include <huxon/lang.hpp>
#include <huxon/sensors/STMicroelectronics.hpp>
/* Import other libraries */
#include <math.h>
/* 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<float, float, float, hux::uint64_t>("./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<float, float, float>
* */
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<float, float, float>.
* To retrieve a specific field of the tuple we can use: hux::get<index>(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:
huxc simulate -n YOUR_APP_NAME
The output of the simulation will look similar to the following:
[INFO] Capturing virtual sensor output:
{
"acceleration_norm":1.07432234
}
{
"acceleration_norm":1.42203546
}
[INFO] Simulation completed successfully!