Skip to content

Developing the Analyzer

James edited this page Sep 10, 2015 · 12 revisions

Previous

Developing a Controller

Introduction

This topic continues the tutorial on building a package for the simple pendulum by describing the requirements for building the pendulum analyzer. The previous topic described development of the Reveal scenario and Controller. The analyzer presented here is very simple and produces an analysis based on the difference in joint angle between the model solution and the client experimental solution.

Analyzer Directory

In the Analyzer Framework section of the Introduction, the general directory structure for the analyzer was described and in the Package File Structure section the prescribed structure for the pendulum package was introduced; however, details of the analyzer directory were omitted. The following skeleton shows the additional files that appear in the analyzers subdirectory which will be covered in this topic:

analyzers/
|-pivot_angle
|--CMakeLists.txt
|--analyzer.cpp

The name of this analyzer is 'pivot_angle' based on the file structure.

Analyzer Implementation

The following is the source code the analyzer.cpp. the analyze(...) function is the implementation of the reveal::analytics::plugin_c interface and able to be dynamically linked by Reveal at run time. The other functions, pendulum_model(...) and pivot_joint(...) are module level helper functions to make locating data in the Reveal data structures easier.

The full documentation of the analyzer is provided inline to make the operations as clear as possible.

#include <stdio.h>
#include <cmath>

#include <reveal/analytics/types.h>
#include <reveal/core/pointers.h>
#include <reveal/core/solution_set.h>
#include <reveal/core/solution.h>
#include <reveal/core/scenario.h>
#include <reveal/core/trial.h>
#include <reveal/core/analyzer.h>

//-----------------------------------------------------------------------------

using namespace Reveal::Analytics;

//-----------------------------------------------------------------------------
/// Locates the pendulum model in the solution
Reveal::Core::model_ptr pendulum_model( Reveal::Core::solution_ptr solution ) {
  Reveal::Core::model_ptr nothing;

  // iterate through the list and return the pendulum model if found
  for( unsigned i = 0; i < solution->models.size(); i++ )
    if( solution->models[i]->id == "pendulum" ) return solution->models[i];

  // otherwise the pendulum was not found, so return the uninitialized reference
  return nothing;
}

//-----------------------------------------------------------------------------
/// Locates the pivot joint in the pendulum model
Reveal::Core::joint_ptr pivot_joint( Reveal::Core::model_ptr model ) {
  Reveal::Core::joint_ptr nothing;

  // if the model is not the pendulum return the uninitialized reference
  if( model->id != "pendulum" ) return nothing;

  // iterate through the list and return the pivot joint if found
  for( unsigned i = 0; i < model->joints.size(); i++ )
    if( model->joints[i]->id == "pivot_joint" ) return model->joints[i];

  // otherwise the joint was not found, so return the uninitialized reference
  return nothing;
}

//-----------------------------------------------------------------------------
extern "C" {
//-----------------------------------------------------------------------------
/// Produces an analysis from a solution set
/// @param input[in] the solution set to analyze
/// @param output[out] the analysis generated
/// @return returns ERROR_NONE if the operation succeeded OR an error code 
///         indicating the type of failure
error_e analyze( Reveal::Core::solution_set_ptr input, Reveal::Core::analysis_ptr& output ) {

  // create a new analysis reference to contain output
  output = Reveal::Core::analysis_ptr( new Reveal::Core::analysis_c( input ) );

  // add the keys defined for this analysis to the output
  output->add_key( "t" );
  output->add_key( "delta" );

  // iterate over all solutions contained in the solution set and analyze each
  for( unsigned i = 0; i < input->solutions.size(); i++ ) {

    // get references to both the user and desired solutions
    Reveal::Core::solution_ptr user_solution = input->solutions[i];
    Reveal::Core::solution_ptr desired_solution = input->models[i];

    // extract the pendulum state from the user and desired solutions
    Reveal::Core::model_ptr user_state = pendulum_model( input->solutions[i] );
    Reveal::Core::model_ptr desired_state = pendulum_model( input->models[i] );

    // get the time of the solution
    double t = user_solution->t;

    // get the pivot joint state for the user and desired solutions
    Reveal::Core::joint_ptr user_pivot = pivot_joint( user_state );
    Reveal::Core::joint_ptr desired_pivot = pivot_joint( desired_state );

    // compute an analysis.  this case is a simple differential between desired 
    // and experimental values recorded in the pivot joint's joint angle
    double delta = fabs( desired_pivot->state.q( 0 ) - user_pivot->state.q( 0 ) );

    // build a list of the analytical values ordered by the keys definition 
    std::vector<double> values;
    values.push_back( t );
    values.push_back( delta );

    // add the list of analytical values to the output
    output->add_row( values );
  }  

  return ERROR_NONE;
}

//-----------------------------------------------------------------------------
} // extern "C"
//-----------------------------------------------------------------------------

Analyzer CMake

The analyzer is entirely independent from the scenario definition and so it must have its own build script. The following cmake script will build the above analyzer.cpp as a plugin compatible to Reveal.

cmake_minimum_required( VERSION 2.8.7 )
project( reveal-analyzer-pendulum-pivot_angle )

find_package( Reveal REQUIRED )
include_directories( ${REVEAL_INCLUDE_DIRS} )
link_directories( ${REVEAL_LIBRARY_DIRS} )

set( LIBS 
  ${REVEAL_LIBRARIES}
) 

add_library( analyzer "MODULE" analyzer.cpp )
target_link_libraries( analyzer ${LIBS} )

Building the Analyzer

Once all the above files are defined, create a build directory in the analyzer implementation directory then execute the following commands:

cd build
cmake ..
make

libanalyzer.so should be successfully built. Unfortunately, there is currently no easy way to directly test the analyzer without running Reveal which will require additional steps.

Next

Continue with Gathering Scenario Data for Import.