Program Listing for File transfer_function.hpp
↰ Return to documentation for file (/tmp/ws/src/filters/include/filters/transfer_function.hpp
)
/*
* Copyright (c) 2008, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// Original version: Melonee Wise <mwise@willowgarage.com>
#ifndef FILTERS__TRANSFER_FUNCTION_HPP_
#define FILTERS__TRANSFER_FUNCTION_HPP_
#include <stdint.h>
#include <math.h>
#include <memory>
#include <vector>
#include <string>
#include "filters/filter_base.hpp"
#include "filters/realtime_circular_buffer.hpp"
namespace filters
{
template<typename T>
class SingleChannelTransferFunctionFilter : public filters::FilterBase<T>
{
public:
SingleChannelTransferFunctionFilter();
~SingleChannelTransferFunctionFilter() override;
bool configure() override;
bool update(const T & data_in, T & data_out) override;
protected:
std::unique_ptr<RealtimeCircularBuffer<T>> input_buffer_;
std::unique_ptr<RealtimeCircularBuffer<T>> output_buffer_;
T temp_; // used for storage and preallocation
std::vector<double> a_;
std::vector<double> b_;
};
template<typename T>
SingleChannelTransferFunctionFilter<T>::SingleChannelTransferFunctionFilter()
{
}
template<typename T>
SingleChannelTransferFunctionFilter<T>::~SingleChannelTransferFunctionFilter()
{
}
template<typename T>
bool SingleChannelTransferFunctionFilter<T>::configure()
{
// Parse a and b into a std::vector<double>.
if (!FilterBase<T>::getParam("a", a_)) {
RCLCPP_ERROR(
this->logging_interface_->get_logger(),
"TransferFunctionFilter, \"%s\", params has no attribute a.",
FilterBase<T>::getName().c_str());
return false;
}
if (!FilterBase<T>::getParam("b", b_)) {
RCLCPP_ERROR(
this->logging_interface_->get_logger(),
"TransferFunctionFilter, \"%s\", params has no attribute b.",
FilterBase<T>::getName().c_str());
return false;
}
// Create the input and output buffers of the correct size.
input_buffer_.reset(new RealtimeCircularBuffer<T>(b_.size() - 1, temp_));
output_buffer_.reset(new RealtimeCircularBuffer<T>(a_.size() - 1, temp_));
// Prevent divide by zero while normalizing coeffs.
if (a_[0] == 0.) {
RCLCPP_ERROR(this->logging_interface_->get_logger(), "a[0] can not equal 0.");
return false;
}
// Normalize the coeffs by a[0].
if (a_[0] != 1.) {
for (size_t i = 0; i < b_.size(); i++) {
b_[i] = (b_[i] / a_[0]);
}
for (size_t i = 1; i < a_.size(); i++) {
a_[i] = (a_[i] / a_[0]);
}
a_[0] = 1.;
}
return true;
}
template<typename T>
bool SingleChannelTransferFunctionFilter<T>::update(const T & data_in, T & data_out)
{
if (!FilterBase<T>::configured_) {
return false;
}
// Copy data to prevent mutation if in and out are the same ptr
temp_ = data_in;
data_out = b_[0] * temp_;
for (size_t row = 1; row <= input_buffer_->size(); ++row) {
data_out += b_[row] * (*input_buffer_)[row - 1];
}
for (size_t row = 1; row <= output_buffer_->size(); ++row) {
data_out -= a_[row] * (*output_buffer_)[row - 1];
}
input_buffer_->push_front(temp_);
output_buffer_->push_front(data_out);
return true;
}
template<typename T>
class MultiChannelTransferFunctionFilter : public filters::MultiChannelFilterBase<T>
{
public:
MultiChannelTransferFunctionFilter();
~MultiChannelTransferFunctionFilter() override;
bool configure() override;
bool update(const std::vector<T> & data_in, std::vector<T> & data_out) override;
protected:
std::unique_ptr<RealtimeCircularBuffer<std::vector<T>>> input_buffer_;
std::unique_ptr<RealtimeCircularBuffer<std::vector<T>>> output_buffer_;
std::vector<T> temp_; // used for storage and preallocation
std::vector<double> a_;
std::vector<double> b_;
};
template<typename T>
MultiChannelTransferFunctionFilter<T>::MultiChannelTransferFunctionFilter()
{
}
template<typename T>
MultiChannelTransferFunctionFilter<T>::~MultiChannelTransferFunctionFilter()
{
}
template<typename T>
bool MultiChannelTransferFunctionFilter<T>::configure()
{
// Parse a and b into a std::vector<double>.
if (!FilterBase<T>::getParam("a", a_)) {
RCLCPP_ERROR(
this->logging_interface_->get_logger(),
"TransferFunctionFilter, \"%s\", params has no attribute a.",
FilterBase<T>::getName().c_str());
return false;
}
if (!FilterBase<T>::getParam("b", b_)) {
RCLCPP_ERROR(
this->logging_interface_->get_logger(),
"TransferFunctionFilter, \"%s\", params has no attribute b.",
FilterBase<T>::getName().c_str());
return false;
}
// Create the input and output buffers of the correct size.
temp_.resize(this->number_of_channels_);
input_buffer_.reset(new RealtimeCircularBuffer<std::vector<T>>(b_.size() - 1, temp_));
output_buffer_.reset(new RealtimeCircularBuffer<std::vector<T>>(a_.size() - 1, temp_));
// Prevent divide by zero while normalizing coeffs.
if (a_[0] == 0.) {
RCLCPP_ERROR(this->logging_interface_->get_logger(), "a[0] can not equal 0.");
return false;
}
// Normalize the coeffs by a[0].
if (a_[0] != 1.) {
for (size_t i = 0; i < b_.size(); ++i) {
b_[i] = (b_[i] / a_[0]);
}
for (size_t i = 1; i < a_.size(); ++i) {
a_[i] = (a_[i] / a_[0]);
}
a_[0] = 1.;
}
return true;
}
template<typename T>
bool MultiChannelTransferFunctionFilter<T>::update(
const std::vector<T> & data_in,
std::vector<T> & data_out)
{
// Ensure the correct number of inputs
if (data_in.size() != this->number_of_channels_ || data_out.size() != this->number_of_channels_) {
RCLCPP_ERROR(
this->logging_interface_->get_logger(),
"Number of channels is %zu, but data_in.size() = %zu and data_out.size() = %zu. "
"They must match", this->number_of_channels_, data_in.size(), data_out.size());
return false;
}
// Copy data to prevent mutation if in and out are the same ptr
temp_ = data_in;
for (size_t i = 0; i < temp_.size(); ++i) {
data_out[i] = b_[0] * temp_[i];
for (size_t row = 1; row <= input_buffer_->size(); ++row) {
data_out[i] += b_[row] * (*input_buffer_)[row - 1][i];
}
for (size_t row = 1; row <= output_buffer_->size(); ++row) {
data_out[i] -= a_[row] * (*output_buffer_)[row - 1][i];
}
}
input_buffer_->push_front(temp_);
output_buffer_->push_front(data_out);
return true;
}
} // namespace filters
#endif // FILTERS__TRANSFER_FUNCTION_HPP_