Data Generator Filter Tutorial

This guide covers creating a simple ADTF Filter that generates data samples and forwards them to a data sink. After reading this guide, you will know how to:

Where are we?

In the Data Filter Processor Tutorial we created a Filter that:

Now we need to create a Filter that:

How to create a simple data generator Filter?

First, create a new Filter project for the data generator Filter using CMake.


cmake_minimum_required (VERSION 3.10)
project (DataGenerator)

set (DATA_GENERATOR_FILTER tutorial_filter_data_generator)

if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tutorial_filter_data_generator.h)
  file(WRITE tutorial_filter_data_generator.h)
endif()
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tutorial_filter_data_generator.cpp)
  file(WRITE tutorial_filter_data_generator.cpp)
endif()

find_package(ADTF COMPONENTS filtersdk)

# Adds the data_generator_filter project to the Visual Studio solution, which when build
# creates a shared object called data_generator_filter.adtfplugin
adtf_add_filter(${DATA_GENERATOR_FILTER} tutorial_filter_data_generator.h tutorial_filter_data_generator.cpp)

# Adds the INSTALL project to the Visual Studio solution, which when build
# copies our Filter to the subdirectory given as the second argument into ${CMAKE_INSTALL_PREFIX}
adtf_install_filter(${DATA_GENERATOR_FILTER} src/examples/bin)

# Generate a plugindescription for our Filter
adtf_create_plugindescription(TARGET ${DATA_GENERATOR_FILTER} PLUGIN_SUBDIR "src/examples/bin")

    

Now use the CMake-GUI to fill in all the information required by CMake to create the Visual Studio solution. If you need help have a look at the CMake-GUI. Then open thedata_generator_filterproject in the solution explorer.

Open the tutorial_filter_data_generator header and source files in Visual Studio.

Visual Studio - Solution Explorer

The header file of the Filter

Just like before we continue by creating our tutorial_filter_data_generator.h header file.

            
/**
 *
 * ADTF Tutorial filter for data processing
 *
 */
#pragma once

// Include all necessary headers from the ADTF SDK
#include <adtffiltersdk/adtf_filtersdk.h>

// For simplicity use the necessary namespaces
using namespace adtf::util;
using namespace adtf::ucom;
using namespace adtf::base;
using namespace adtf::streaming;
using namespace adtf::mediadescription;
using namespace adtf::filter;

// Now we declare a new class cTutorialFilterDataGenerator that
// inherits from cFilter. This will be our Tutorial Filter.
class cTutorialFilterDataGenerator: public cFilter
{
public:
    // Inside the class declaration we use an ADTF macro to enable correct treatment
    // of class identifier and class name by IClassInfo and the class factories.
    ADTF_CLASS_ID_NAME(cTutorialFilterDataGenerator,
                       "tutorial_data_generator.filter.adtf_guides.cid",
                       "Tutorial Data Generator");

public:
    // We implement the constructor where we create our Pins and Runners.
    cTutorialFilterDataGenerator();

    // We override the Process method in order to handle triggers from the
    // connected Active Runner.
    tResult Process(tNanoSeconds tmTrigger, IRunner* pRunner) override;

private:
    // Some helper methods.
    tFloat32 CalculateVelocityValue();
    tFloat32 CalculateYawRateValue();

    // Our writers for our output data.
    ISampleWriter* m_pVelocityWriter;
    ISampleWriter* m_pYawRateWriter;

    // Defines property variables, this properties will occur within your property set
    // You still need to register with name in the constructor.
    // Defines the change rates for the velocity/yaw rate values.
    property_variable<tFloat32> m_fVelocityChangeRate = 5.0;
    property_variable<tFloat32> m_fYawRateChangeRate = 1.0;
    // Defines the max values for velocity and yaw rate.
    property_variable<tFloat32> m_fVelocityMax = 100.0;
    property_variable<tFloat32> m_fYawRateMax = 10.0;

    // Store the current values.
    tFloat32 m_fCurrentVelocity = 50.0;
    tFloat32 m_fCurrentYawRate = 10.0;
};

            
          

The source file of the Filter

Now we need to write the tutorial_filter_data_generator.cpp source file.

            
/**
*
* ADTF Tutorial Filter for data processing
*
*/
#include "tutorial_filter_data_generator.h"

// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cTutorialFilterDataGenerator will be available through the plugins class factory.
ADTF_PLUGIN("ADTF Tutorial Filter Data Generator Plugin", cTutorialFilterDataGenerator);

cTutorialFilterDataGenerator::cTutorialFilterDataGenerator()
{
    // Create our output pins with a simple plain stream type.
    m_pVelocityWriter = CreateOutputPin("velocity", stream_type_plain<tFloat32>());
    SetDescription("velocity", "Provides the generated velocity data samples");

    m_pYawRateWriter = CreateOutputPin("yawrate", stream_type_plain<tFloat32>());
    SetDescription("yawrate", "Provides the generated yawrate data samples");

    // Now create our Runner and give the Configuration Editor a hint on which
    // Active Runner to connect to it. In this case a Timer Runner.
    CreateRunner("generate_data", cTimerTriggerHint(std::chrono::seconds(1)));
    SetDescription("generate_data", "Runner to periodically trigger the function which executes the calculation");

    // And register your Property Variables to make them accessible via the
    // configuration.
    RegisterPropertyVariable("velocity_change_rate", m_fVelocityChangeRate);
    RegisterPropertyVariable("yaw_rate_change_rate", m_fYawRateChangeRate);
    RegisterPropertyVariable("velocity_max_value", m_fVelocityMax);
    RegisterPropertyVariable("yaw_rate_max_value", m_fYawRateMax);
}

// This function will be executed each time a trigger for the "generate_data" Runner occurs
tResult cTutorialFilterDataGenerator::Process(tNanoSeconds tmTrigger, IRunner* /*pRunner*/)
{
    // To create output data use the output_sample_data template
    // This will handle sample allocation for you and you can use it just
    // like its template parameter type.
    output_sample_data<tFloat32> fVelocity(tmTrigger, CalculateVelocityValue());

    // Write it to the connected Sample Stream.
    // Do not call any methods of output_sample_data after you have called Release() which
    // hands over the sample instance.
    m_pVelocityWriter->Write(fVelocity.Release());

    // we do the same for the yaw rate
    output_sample_data<tFloat32> fYawRate(tmTrigger, CalculateYawRateValue());
    m_pYawRateWriter->Write(fYawRate.Release());

    RETURN_NOERROR;
}

tFloat32 cTutorialFilterDataGenerator::CalculateVelocityValue()
{
    // negate the velocity change rate if the max/min values are reached
    if ((m_fCurrentVelocity - std::abs(m_fVelocityChangeRate)) <= 0 ||
        m_fCurrentVelocity > m_fVelocityMax)
    {
        m_fVelocityChangeRate = -m_fVelocityChangeRate;
    }

    m_fCurrentVelocity += m_fVelocityChangeRate;

    LOG_INFO("Data Generator: Velocity: %f", m_fCurrentVelocity);

    return m_fCurrentVelocity;
}

tFloat32 cTutorialFilterDataGenerator::CalculateYawRateValue()
{
    // negate the yaw rate change rate if the max/min values are reached
    if ((m_fCurrentYawRate - std::abs(m_fYawRateChangeRate)) <= 0 ||
        m_fCurrentYawRate > m_fYawRateMax)
    {
        m_fYawRateChangeRate = -m_fYawRateChangeRate;
    }

    m_fCurrentYawRate += m_fYawRateChangeRate;

    LOG_INFO(cString::Format("Data Generator: Yaw Rate: %f", m_fCurrentYawRate).GetPtr());

    return m_fCurrentYawRate;
}

            
          

Finally we need to build the Project.

Now we want to integrate and test our Filters in an ADTF Project. We can accomplish this using the Configuration Editor.

Where to go next?

Have a look at the ADTF Project Tutorial.