Add Central filtrering.

topic/diffentiators v1.3.0
Vincent Samy 2019-10-28 17:23:25 +09:00
rodzic 75e8924949
commit 3320b425bd
4 zmienionych plików z 105 dodań i 32 usunięć

Wyświetl plik

@ -50,6 +50,35 @@ public:
: GenericFilter<T>(aCoeff, bCoeff)
{
}
void setCoefficients(vectX_t<T>&& aCoeff, vectX_t<T>&& bCoeff)
{
setCoeffs(std::forward(aCoeff), std::forward(bCoeff));
}
};
/*! \brief Basic centered digital filter.
*
* This filter allows you to set any centered digital filter based on its coefficients.
* \tparam T Floating type.
*/
template <typename T>
class CenteredDigitalFilter : public GenericFilter<T> {
public:
/*! \brief Default uninitialized constructor. */
CenteredDigitalFilter() = default;
/*! \brief Constructor.
* \param aCoeff Denominator coefficients of the filter in decreasing order.
* \param bCoeff Numerator coefficients of the filter in decreasing order.
*/
CenteredDigitalFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
: GenericFilter<T>(aCoeff, bCoeff, Type::Centered)
{
}
void setCoefficients(vectX_t<T>&& aCoeff, vectX_t<T>&& bCoeff)
{
setCoeffs(std::forward(aCoeff), std::forward(bCoeff));
setType(Type::Centered);
}
};
} // namespace difi

Wyświetl plik

@ -35,6 +35,9 @@
namespace difi {
// TODO: noexcept(Function of gsl variable)
// TODO: constructor with universal refs
/*! \brief Low-level filter.
*
* It creates the basic and common functions of all linear filter that can written as a digital filter.
@ -49,6 +52,12 @@ template <typename T>
class GenericFilter {
static_assert(std::is_floating_point<T>::value && !std::is_const<T>::value, "Only accept non-complex floating point types.");
public:
enum class Type {
OneSided,
Centered
};
public:
/*! \brief Filter a new data.
*
@ -64,16 +73,11 @@ public:
* \return Filtered signal.
*/
vectX_t<T> filter(const vectX_t<T>& data);
/*! \brief Filter a signal and store in a user-defined Eigen vector.
*
* Useful if the length of the signal is known in advance.
* \param[out] results Filtered signal.
* \param data Signal.
* \return False if vector's lengths do not match.
*/
void getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data);
/*! \brief Reset the data and filtered data. */
void resetFilter() noexcept;
/*!< \brief Return the filter type */
Type type() const noexcept { return (m_center == 0 ? Type::OneSided : Type::Centered); }
/*! \brief Get digital filter coefficients.
*
* It will automatically resize the given vectors.
@ -81,6 +85,10 @@ public:
* \param[out] bCoeff Numerator coefficients of the filter in decreasing order.
*/
void getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const noexcept;
/*! \brief Return coefficients of the denominator polynome. */
const vectX_t<T>& aCoeff() const noexcept { return m_aCoeff; }
/*! \brief Return coefficients of the numerator polynome. */
const vectX_t<T>& bCoeff() const noexcept { return m_bCoeff; }
/*! \brief Return the order the denominator polynome order of the filter. */
Eigen::Index aOrder() const noexcept { return m_aCoeff.size(); }
/*! \brief Return the order the numerator polynome order of the filter. */
@ -94,11 +102,18 @@ protected:
/*! \brief Constructor.
* \param aCoeff Denominator coefficients of the filter in decreasing order.
* \param bCoeff Numerator coefficients of the filter in decreasing order.
* \param center
*/
GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff);
GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff, Type type = Type::OneSided);
/*! \brief Default destructor. */
virtual ~GenericFilter() = default;
/*! \brief Set type of filter (one-sided or centered)
*
* \param type The filter type.
* \warning bCoeff must be set before.
*/
void setType(Type type);
/*! \brief Set the new coefficients of the filters.
*
* It awaits a universal reference.
@ -116,9 +131,10 @@ protected:
* \param bCoeff Numerator coefficients of the filter.
* \return True if the filter status is set on READY.
*/
void checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff);
bool checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff, Type type);
private:
Eigen::Index m_center = 0; /*!< Center of the filter. 0 is a one-sided filter. Default is 0. */
bool m_isInitialized = false; /*!< Initialization state of the filter. Default is false */
vectX_t<T> m_aCoeff; /*!< Denominator coefficients of the filter */
vectX_t<T> m_bCoeff; /*!< Numerator coefficients of the filter */

Wyświetl plik

@ -2,13 +2,13 @@
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// this list of conditions and the following disclaimer.
// 2. 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.
// and/or other materials provided with the distribution.
// 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
@ -22,7 +22,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The views and conclusions contained in the software and documentation are those
// of the authors and should not be interpreted as representing official policies,
// of the authors and should not be interpreted as representing official policies,
// either expressed or implied, of the FreeBSD Project.
#include <limits>
@ -44,25 +44,18 @@ T GenericFilter<T>::stepFilter(const T& data)
m_rawData[0] = data;
m_filteredData[0] = 0;
m_filteredData[0] = m_bCoeff.dot(m_rawData) - m_aCoeff.dot(m_filteredData);
return m_filteredData[0];
m_filteredData[m_center] = m_bCoeff.dot(m_rawData) - m_aCoeff.dot(m_filteredData);
return m_filteredData[m_center];
}
template <typename T>
vectX_t<T> GenericFilter<T>::filter(const vectX_t<T>& data)
{
vectX_t<T> results(data.size());
getFilterResults(results, data);
return results;
}
template <typename T>
void GenericFilter<T>::getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data)
{
Expects(m_isInitialized);
Expects(results.size() == data.size());
vectX_t<T> results(data.size());
for (Eigen::Index i = 0; i < data.size(); ++i)
results(i) = stepFilter(data(i));
return results;
}
template <typename T>
@ -72,13 +65,20 @@ void GenericFilter<T>::resetFilter() noexcept
m_rawData.setZero(m_bCoeff.size());
}
template <typename T>
void GenericFilter<T>::setType(Type type)
{
Expects(type == Type::Centered ? m_bCoeff.size() > 2 && m_bCoeff.size() % 2 == 1 : true);
m_center = (type == Type::OneSided ? 0 : (m_bCoeff.size() - 1) / 2);
}
template <typename T>
template <typename T2>
void GenericFilter<T>::setCoeffs(T2&& aCoeff, T2&& bCoeff)
{
static_assert(std::is_convertible_v<T2, vectX_t<T>>, "The coefficients types should be convertible to vectX_t<T>");
checkCoeffs(aCoeff, bCoeff);
Expects(checkCoeffs(aCoeff, bCoeff, (m_center == 0 ? Type::OneSided : Type::Centered)));
m_aCoeff = aCoeff;
m_bCoeff = bCoeff;
normalizeCoeffs();
@ -96,13 +96,14 @@ void GenericFilter<T>::getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const n
// Protected functions
template <typename T>
GenericFilter<T>::GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
GenericFilter<T>::GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff, Type type)
: m_aCoeff(aCoeff)
, m_bCoeff(bCoeff)
, m_filteredData(aCoeff.size())
, m_rawData(bCoeff.size())
{
checkCoeffs(aCoeff, bCoeff);
Expects(checkCoeffs(aCoeff, bCoeff, type));
m_center = (type == Type::OneSided ? 0 : (bCoeff.size() - 1) / 2);
normalizeCoeffs();
resetFilter();
m_isInitialized = true;
@ -120,11 +121,10 @@ void GenericFilter<T>::normalizeCoeffs()
}
template <typename T>
void GenericFilter<T>::checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
bool GenericFilter<T>::checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff, Type type)
{
Expects(aCoeff.size() > 0);
Expects(std::abs(aCoeff[0]) > std::numeric_limits<T>::epsilon());
Expects(bCoeff.size() > 0);
bool centering = (type == Type::Centered ? (bCoeff.size() % 2 == 1) : true);
return aCoeff.size() > 0 && std::abs(aCoeff[0]) > std::numeric_limits<T>::epsilon() && bCoeff.size() > 0 && centering;
}
} // namespace difi

Wyświetl plik

@ -60,4 +60,32 @@ public:
int windowSize() const noexcept { return bOrder(); }
};
/*! \brief Centered moving average digital filter.
*
* This is a specialization of a digital filter in order to use a centered moving average.
* \tparam T Floating type.
*/
template <typename T>
class CenteredMovingAverage : public DigitalFilter<T> {
public:
/*! \brief Default uninitialized constructor. */
CenteredMovingAverage() = default;
/*! \brief Constructor.
* \param windowSize Size of the moving average window.
*/
CenteredMovingAverage(int windowSize)
{
setWindowSize(windowSize);
}
/*! \brief Set the size of the moving average window. */
void setWindowSize(int windowSize)
{
Expects(windowSize > 2 && windowSize % 2 == 1);
setCoeffs(vectX_t<T>::Constant(1, T(1)), vectX_t<T>::Constant(windowSize, T(1) / windowSize));
setType(Type::Centered);
}
/*! \brief Get the size of the moving average window. */
int windowSize() const noexcept { return bOrder(); }
};
} // namespace difi