Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DiscreteFilter block #47

Closed
wants to merge 92 commits into from

Conversation

diegoferigo
Copy link
Member

@diegoferigo diegoferigo commented Aug 10, 2017

This block wraps all the filters included in the iCub::ctrl namespace (filters.h):

  • iCub::ctrl::Filter
  • iCub::ctrl::FirstOrderLowPassFilter
  • iCub::ctrl::MedianFilter

This class already supports multidimensional input signals.
This PR needs the interface that has been discussed in robotology/icub-main#463.

Future TODOs:

This is what is currently missing and it might be included in future PRs if required:

  • Passing filter coefficients during run time (through an additional port)
  • Passing initial state from a signal

@diegoferigo diegoferigo self-assigned this Aug 10, 2017
@francesco-romano francesco-romano mentioned this pull request Aug 10, 2017
5 tasks
@diegoferigo diegoferigo force-pushed the DiscreteFilterBlock branch 2 times, most recently from c27a8dd to 57a432d Compare August 10, 2017 09:58
@traversaro
Copy link
Member

If we are going to require the devel branch of icub-main in WB-Toolbox, I think it is convenient to create a devel branch also on icub-main.

@@ -125,7 +132,10 @@ bool DiscreteFilter::initialize(BlockInformation* blockInfo, wbt::Error* error)
}
return 1;
}
filter = new iCub::ctrl::Filter(*num, *den);
for (unsigned i = 0; i < inputSignalWidth; ++i) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filter class support vector input/output, why are are you using a different filter for each component of the vector?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new commit I forced pushed now the block works with vectors and reduces dynamic allocation

// Get the width of the signals
unsigned inputSignalWidth = blockInfo->getInputPortWidth(INPUT_IDX_SIGNAL);
unsigned outputSignalWidth = blockInfo->getOutputPortWidth(OUTPUT_IDX_SIGNAL);
assert(inputSignalWidth == outputSignalWidth);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not an expert of Simulink, but what happens with this assert if the user connect two signal of different size to the input and output of the block? Simulink crashes?

Copy link
Member Author

@diegoferigo diegoferigo Aug 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It crashes. In my opinion having asserts is good even in this case. When people work on controllers (downstream) the code should be always be set in release. Debug should be enabled only when developing the block themselves. @francesco-romano

@diegoferigo diegoferigo changed the base branch from master to devel August 11, 2017 07:11
@diegoferigo diegoferigo changed the title [WIP] DiscreteFilter block DiscreteFilter block Aug 11, 2017
s.erase(remove_if(s.begin(), s.end(), lambda_remove_chars), s.end());

// Convert the cleaned string to a yarp vector of floats
std::istringstream sstrm(s);
Copy link
Member

@traversaro traversaro Aug 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion part could be affected by locale-bugs such as robotology/idyntree#288 .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in aafaf38

@@ -36,7 +36,10 @@ wbt::Block* wbt::Block::instantiateBlockWithClassName(std::string blockClassName
#ifdef WBT_USES_ICUB
else if (blockClassName == wbt::MinimumJerkTrajectoryGenerator::ClassName) {
block = new wbt::MinimumJerkTrajectoryGenerator();
}
}
else if (blockClassName == wbt::DiscreteFilter::ClassName) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the indentation of the else coherent with the rest of the file

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? It looks already coherent but is morning for me as well :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry, now I see. Inside WBT_USES_ICUB is coherent, outside no. I fix both.

Copy link
Member Author

@diegoferigo diegoferigo Aug 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh consideing that the last part of the file is all with defines, and the indentation has to be changes, imo the current status looks better. Compare:

    ...
    } else if (blockClassName == wbt::GetLimits::ClassName) {
        block = new wbt::GetLimits();
    } else if (blockClassName == wbt::CentroidalMomentum::ClassName) {
        block = new wbt::CentroidalMomentum();
    }
#ifdef WBT_USES_ICUB
    else if (blockClassName == wbt::MinimumJerkTrajectoryGenerator::ClassName) {
        block = new wbt::MinimumJerkTrajectoryGenerator();
    }
    else if (blockClassName == wbt::DiscreteFilter::ClassName) {
        block = new wbt::DiscreteFilter();
    }
#endif
#ifdef WBT_USES_IPOPT
    else if (blockClassName == wbt::InverseKinematics::ClassName) {
        block = new wbt::InverseKinematics();
    }
#endif

with

    ...
    } else if (blockClassName == wbt::GetLimits::ClassName) {
        block = new wbt::GetLimits();
    } else if (blockClassName == wbt::CentroidalMomentum::ClassName) {
        block = new wbt::CentroidalMomentum();
    }
#ifdef WBT_USES_ICUB
    else if (blockClassName == wbt::MinimumJerkTrajectoryGenerator::ClassName) {
        block = new wbt::MinimumJerkTrajectoryGenerator();
    } else if (blockClassName == wbt::DiscreteFilter::ClassName) {
        block = new wbt::DiscreteFilter();
    }
#endif
#ifdef WBT_USES_IPOPT
    else if (blockClassName == wbt::InverseKinematics::ClassName) {
        block = new wbt::InverseKinematics();
    }
#endif

But as you prefer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the second one.

Copy link
Collaborator

@francesco-romano francesco-romano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments are related to the C++ only.
Before merging the matlab part should also be tested

private:
bool firstRun;
iCub::ctrl::IFilter* filter;
yarp::sig::Vector* num;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why putting num and den in the .h file? They are only needed in configuration and not in real time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


DiscreteFilter::DiscreteFilter() : firstRun(true), filter(nullptr), inputSignalVector(nullptr)
{
num = new Vector(0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment in the .h

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

unsigned inputSignalWidth = blockInfo->getInputPortWidth(INPUT_IDX_SIGNAL);

// Allocate the memory for the input data
if (firstRun) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also another callback (initializeInitialConditions) which is called before the first output.

Furthermore, have you tried to ask for the port width in the initialize method?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In initialize() it returns the correct width. I'll add a private member for that and move the initialization into the initializeInitialConditions callback that I didn't know existed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if initialize returns the correct width, I advise to use it instead of initializeInitialConditions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok thanks, should be ok now.


void DiscreteFilter::stringToYarpVector(const std::string str, Vector* v)
{
assert(v != nullptr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the pointer should always be != null, I would use a reference, not a pointer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the argument type to Vector&

@diegoferigo
Copy link
Member Author

@francesco-romano
Ready for the final review


// If the initial conditions for the output are not set, allocate a properly
// sized vector
if (*y0 == Vector(0)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not asking for the size of the vector and calling a resize on it, instead of allocated twice?


DiscreteFilter::DiscreteFilter() : filter(nullptr), inputSignalVector(nullptr)
{
y0 = new Vector(0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the delete are done in the terminate, move the allocation in the corresponding method, and not in the constructor.
Here simply initialise to nullptr the pointers

// zero-gain case
Filter* filter_c = dynamic_cast<Filter*>(filter);
if (filter_c != nullptr) {
filter_c->init(*y0, *u0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember what init does, but is it ok to call with an empty vector? (i.e. u0.size() == 0)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With 4a29231 the vectors that hold the optional initial values are null if the parameters are not specified, and allocated to the correct size only when needed. If instead they are specified, their size is checked in the initialize method.

y0 = new Vector(inputSignalWidth, 0.0);
if (y0 == nullptr) {
unsigned outputSignalWidth = blockInfo->getInputPortWidth(OUTPUT_IDX_SIGNAL);
y0 = new Vector(outputSignalWidth, 0.0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you avoid to align the =? I don't like this kind of indentation

@francesco-romano
Copy link
Collaborator

A part from the inline comment the .cpp is ok.
As soon as I have time I will test the .mdl

@francesco-romano
Copy link
Collaborator

@diegoferigo
To "rebase" on top of devel, rebase the C++ files.
Regarding the mdl, save the new block in a temporary model, get the devel version of the library and then re-add the block

francesco-romano and others added 7 commits September 25, 2017 12:10
SetReferences subList parameter was erroneously converted to a boolean, while it is actually the index of the selected item in the Simulink mask dropdown.
Being the index >=1 the boolean conversion resulted always in a true value.

Fix robotology#57
Note: actually the std::cerr are warnings for the user, this is why they are not returned as an error.
We have to find a smarter way to return the warning to the user.
This class contains and validates the configuration passed to every wbt::WBBlock object.

ValidConfiguration is a Dependent property and it is set to 1 only if the basic checks currently implemented in other properties don't fail. From this state, it is possible to call getSimulinkParameters() in order to obtain the struct which is passed to the S-Functions and then parsed in C++.

This class also contains utilities functions for obtainng a simple string representation of 1D vectors and 1D chars, required to serialize the data in the Config Block's mask. The deserialization is performed using eval().
Initial version of the library, which will become independent in the future.

MxAnyType handles the C / C++ mxArray pointer that represents any generic data type in Matlab. It wraps most of the C APIs, and it has optional support of strict type checking.
wbt::Log is the new class that provides log support to the WBToolbox.
It now supports both Errors and Warnings.

For being more flexible, wbt::Log is a singleton. This approach simplifies dramatically the handling of warnings, and can be called from every method without the need of passing it though arguments. Since singletons cannot be deleted, wbt::Log state is reset in the early stage of the processing.

[Squash] toolbox.cpp
Its functionality are implemented by the new generic WBBlock, which is a refactored version of WBIBlock that access robot resources
in a lazy way. This approach allows avoiding the previous separation between WBIBlock and WBIModelBlock.
@diegoferigo diegoferigo changed the base branch from devel to WB3.0 December 6, 2017 13:14
@diegoferigo
Copy link
Member Author

For simplifying the test of the WB-Toolbox 3.0, I cherry picked these commits to #56.

Closing this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants