kopia lustrzana https://github.com/vsamy/DiFipp
rodzic
06c70f4ef0
commit
24df3ddedc
|
@ -44,6 +44,18 @@ set(CMAKE_CXX_STANDARD 14)
|
|||
setup_project()
|
||||
|
||||
option(DISABLE_TESTS "Disable unit tests." OFF)
|
||||
option(THROW_ON_CONTRACT_VIOLATION "Throw an error when program fails." ON)
|
||||
option(TERMINATE_ON_CONTRACT_VIOLATION "Terminate program when an error occurs. (Default)" OFF)
|
||||
option(UNENFORCED_ON_CONTRACT_VIOLATION "Do not perform any check." OFF)
|
||||
|
||||
# Handle contracts specifications
|
||||
if(${THROW_ON_CONTRACT_VIOLATION})
|
||||
add_compile_options(-DGSL_THROW_ON_CONTRACT_VIOLATION)
|
||||
elseif(${TERMINATE_ON_CONTRACT_VIOLATION})
|
||||
add_compile_options(-DGSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||
elseif()
|
||||
add_compile_options(-DGSL_UNENFORCED_ON_CONTRACT_VIOLATION)
|
||||
endif()
|
||||
|
||||
# for MSVC
|
||||
if(MSVC)
|
||||
|
|
4
LICENSE
4
LICENSE
|
@ -22,3 +22,7 @@ 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.
|
||||
|
||||
|
||||
|
||||
Note: GSL has a different license
|
|
@ -25,8 +25,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gsl/gsl_assert.h"
|
||||
#include "type_checks.h"
|
||||
#include "typedefs.h"
|
||||
#include <limits>
|
||||
|
||||
namespace difi {
|
||||
|
||||
|
@ -69,6 +71,7 @@ struct BilinearTransform {
|
|||
template <typename T>
|
||||
void BilinearTransform<T>::SToZ(SubType fs, const T& sPlanePole, T& zPlanePole)
|
||||
{
|
||||
Expects(std::abs(2 * fs - sPlanePole) > std::numeric_limits<SubType>::epsilon()); // Divide-by-zero otherwise
|
||||
T scalePole = sPlanePole / (2 * fs);
|
||||
zPlanePole = (T(1) + scalePole) / (T(1) - scalePole);
|
||||
}
|
||||
|
@ -76,7 +79,7 @@ void BilinearTransform<T>::SToZ(SubType fs, const T& sPlanePole, T& zPlanePole)
|
|||
template <typename T>
|
||||
void BilinearTransform<T>::SToZ(SubType fs, const vectX_t<T>& sPlanePoles, Eigen::Ref<vectX_t<T>>& zPlanePoles)
|
||||
{
|
||||
assert(sPlanePoles.size() == zPlanePoles.size());
|
||||
Expects(sPlanePoles.size() == zPlanePoles.size());
|
||||
for (Eigen::Index k = 0; k < sPlanePoles.size(); ++k)
|
||||
SToZ(fs, sPlanePoles(k), zPlanePoles(k));
|
||||
}
|
||||
|
@ -84,6 +87,7 @@ void BilinearTransform<T>::SToZ(SubType fs, const vectX_t<T>& sPlanePoles, Eigen
|
|||
template <typename T>
|
||||
void BilinearTransform<T>::ZToS(SubType fs, const T& zPlanePole, T& sPlanePole)
|
||||
{
|
||||
Expects(std::abs(T(1) + zPlanePole) > std::numeric_limits<SubType>::epsilon()); // Divide-by-zero otherwise
|
||||
T invPole = T(1) / zPlanePole;
|
||||
sPlanePole = 2 * fs * (T(1) - invPole) / (T(1) + invPole);
|
||||
}
|
||||
|
@ -91,7 +95,7 @@ void BilinearTransform<T>::ZToS(SubType fs, const T& zPlanePole, T& sPlanePole)
|
|||
template <typename T>
|
||||
void BilinearTransform<T>::ZToS(SubType fs, const vectX_t<T>& zPlanePoles, Eigen::Ref<vectX_t<T>>& sPlanePoles)
|
||||
{
|
||||
assert(zPlanePoles.size() == sPlanePoles.size());
|
||||
Expects(sPlanePoles.size() == zPlanePoles.size());
|
||||
for (Eigen::Index k = 0; k < sPlanePoles.size(); ++k)
|
||||
ZToS(fs, zPlanePoles(k), sPlanePoles(k));
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ T Butterworth<T>::PI = static_cast<T>(M_PI);
|
|||
template <typename T>
|
||||
std::pair<int, T> Butterworth<T>::findMinimumButter(T wPass, T wStop, T APass, T AStop)
|
||||
{
|
||||
Expects(wPass > T(0) && wPass < T(1));
|
||||
Expects(wStop > T(0) && wPass < T(1));
|
||||
T num = std::log10((std::pow(T(10), T(0.1) * std::abs(AStop)) - 1) / (std::pow(T(10), T(0.1) * std::abs(APass)) - 1));
|
||||
// pre-warp
|
||||
T fwPass = std::tan(T(0.5) * PI * wPass);
|
||||
|
@ -65,25 +67,27 @@ template <typename T>
|
|||
Butterworth<T>::Butterworth(int order, T fc, T fs, Type type)
|
||||
: m_type(type)
|
||||
{
|
||||
initialize(order, fc, 0, fs);
|
||||
setFilterParameters(order, fc, fs);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Butterworth<T>::Butterworth(int order, T fLower, T fUpper, T fs, Type type)
|
||||
: m_type(type)
|
||||
{
|
||||
initialize(order, fLower, fUpper, fs);
|
||||
setFilterParameters(order, fLower, fUpper, fs);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Butterworth<T>::setFilterParameters(int order, T fc, T fs)
|
||||
{
|
||||
Expects(fc < fs / T(2));
|
||||
initialize(order, fc, 0, fs);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Butterworth<T>::setFilterParameters(int order, T fLower, T fUpper, T fs)
|
||||
{
|
||||
Expects(fLower < fUpper);
|
||||
initialize(order, fLower, fUpper, fs);
|
||||
}
|
||||
|
||||
|
@ -92,25 +96,8 @@ void Butterworth<T>::initialize(int order, T f1, T f2, T fs)
|
|||
{
|
||||
// f1 = fc for LowPass/HighPass filter
|
||||
// f1 = fLower, f2 = fUpper for BandPass/BandReject filter
|
||||
if (order <= 0) {
|
||||
m_status = FilterStatus::BAD_ORDER_SIZE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (f1 <= 0 || fs <= 0) {
|
||||
m_status = FilterStatus::BAD_FREQUENCY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_type == Type::BandPass || m_type == Type::BandReject) && f1 >= f2) {
|
||||
m_status = FilterStatus::BAD_BAND_FREQUENCY;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_type == Type::LowPass || m_type == Type::HighPass) && f1 > fs / 2.) {
|
||||
m_status = FilterStatus::BAD_CUTOFF_FREQUENCY;
|
||||
return;
|
||||
}
|
||||
Expects(order > 0);
|
||||
Expects(f1 > 0 && fs > 0); // f2 must be > f1 check in setFilterParameters
|
||||
|
||||
m_order = order;
|
||||
m_fs = fs;
|
||||
|
@ -118,8 +105,6 @@ void Butterworth<T>::initialize(int order, T f1, T f2, T fs)
|
|||
computeDigitalRep(f1);
|
||||
else
|
||||
computeBandDigitalRep(f1, f2); // For band-like filters
|
||||
|
||||
resetFilter();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -195,8 +180,9 @@ std::complex<T> Butterworth<T>::generateAnalogPole(int k, T fpw1)
|
|||
case Type::HighPass:
|
||||
return T(2) * PI * fpw1 / analogPole;
|
||||
case Type::LowPass:
|
||||
default:
|
||||
return T(2) * PI * fpw1 * analogPole;
|
||||
default:
|
||||
GSL_ASSUME(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,11 +204,12 @@ std::pair<std::complex<T>, std::complex<T>> Butterworth<T>::generateBandAnalogPo
|
|||
poles.second = s0 * (s - std::complex<T>(T(0), T(1)) * std::sqrt(T(1) - s * s));
|
||||
return poles;
|
||||
case Type::BandPass:
|
||||
default:
|
||||
s *= analogPole;
|
||||
poles.first = s0 * (s + std::complex<T>(T(0), T(1)) * std::sqrt(T(1) - s * s));
|
||||
poles.second = s0 * (s - std::complex<T>(T(0), T(1)) * std::sqrt(T(1) - s * s));
|
||||
return poles;
|
||||
default:
|
||||
GSL_ASSUME(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
set(HEADERS
|
||||
gsl/gsl_assert.h
|
||||
BilinearTransform.h
|
||||
Butterworth.h
|
||||
Butterworth.tpp
|
||||
|
|
|
@ -46,13 +46,6 @@ 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:
|
||||
/*! \brief Get the meaning of the filter status.
|
||||
* \param status Filter status to get the meaning from.
|
||||
* \return The meaning.
|
||||
*/
|
||||
static std::string filterStatus(FilterStatus status);
|
||||
|
||||
public:
|
||||
/*! \brief Filter a new data.
|
||||
*
|
||||
|
@ -75,22 +68,22 @@ public:
|
|||
* \param data Signal.
|
||||
* \return False if vector's lengths do not match.
|
||||
*/
|
||||
bool getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data);
|
||||
void getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data);
|
||||
/*! \brief Reset the data and filtered data. */
|
||||
void resetFilter();
|
||||
void resetFilter() noexcept;
|
||||
/*! \brief Get digital filter coefficients.
|
||||
*
|
||||
* It will automatically resize the given vectors.
|
||||
* \param[out] aCoeff Denominator coefficients of the filter in decreasing order.
|
||||
* \param[out] bCoeff Numerator coefficients of the filter in decreasing order.
|
||||
*/
|
||||
void getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const;
|
||||
/*! \brief Return the current filter status. */
|
||||
FilterStatus status() const noexcept { return m_status; }
|
||||
void getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const noexcept;
|
||||
/*! \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. */
|
||||
Eigen::Index bOrder() const noexcept { return m_bCoeff.size(); }
|
||||
/*! \brief Return the initialization state of the filter0 */
|
||||
bool isInitialized() const noexcept { return m_isInitialized; }
|
||||
|
||||
protected:
|
||||
/*! \brief Default uninitialized constructor. */
|
||||
|
@ -120,12 +113,10 @@ protected:
|
|||
* \param bCoeff Numerator coefficients of the filter.
|
||||
* \return True if the filter status is set on READY.
|
||||
*/
|
||||
bool checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff);
|
||||
|
||||
protected:
|
||||
FilterStatus m_status; /*!< Filter status */
|
||||
void checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff);
|
||||
|
||||
private:
|
||||
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 */
|
||||
vectX_t<T> m_filteredData; /*!< Last set of filtered data */
|
||||
|
|
|
@ -27,40 +27,12 @@
|
|||
|
||||
namespace difi {
|
||||
|
||||
// Public static functions
|
||||
template <typename T>
|
||||
std::string GenericFilter<T>::filterStatus(FilterStatus status)
|
||||
{
|
||||
switch (status) {
|
||||
case FilterStatus::NONE:
|
||||
return "Filter is uninitialized";
|
||||
case FilterStatus::READY:
|
||||
return "Filter is ready to be used";
|
||||
case FilterStatus::BAD_ORDER_SIZE:
|
||||
return "You try to initialize the filter with an order inferior or equal to 0 (window size for the moving average)";
|
||||
case FilterStatus::ALL_COEFF_MISSING:
|
||||
return "Filter has none of its coefficient initialized";
|
||||
case FilterStatus::A_COEFF_MISSING:
|
||||
return "Filter has its 'a' coefficients uninitialized";
|
||||
case FilterStatus::B_COEFF_MISSING:
|
||||
return "Filter has its 'b' coefficients uninitialized";
|
||||
case FilterStatus::BAD_FREQUENCY_VALUE:
|
||||
return "Filter has a received a frequency that is negative or equal to zero";
|
||||
case FilterStatus::BAD_CUTOFF_FREQUENCY:
|
||||
return "Filter has a received a bad cut-off frequency. It must be inferior to the sampling frequency";
|
||||
case FilterStatus::BAD_BAND_FREQUENCY:
|
||||
return "You try to initialize the filter with a bad combination of the frequency and bandwith, you must have fCenter > bw/2";
|
||||
default:
|
||||
return "I forgot to implement this error documentation";
|
||||
}
|
||||
}
|
||||
|
||||
// Public functions
|
||||
|
||||
template <typename T>
|
||||
T GenericFilter<T>::stepFilter(const T& data)
|
||||
{
|
||||
assert(m_status == FilterStatus::READY);
|
||||
Expects(m_isInitialized);
|
||||
|
||||
// Slide data (can't use SIMD, but should be small)
|
||||
for (Eigen::Index i = m_rawData.size() - 1; i > 0; --i)
|
||||
|
@ -78,27 +50,21 @@ template <typename T>
|
|||
vectX_t<T> GenericFilter<T>::filter(const vectX_t<T>& data)
|
||||
{
|
||||
vectX_t<T> results(data.size());
|
||||
if (!getFilterResults(results, data))
|
||||
return vectX_t<T>();
|
||||
|
||||
getFilterResults(results, data);
|
||||
return results;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool GenericFilter<T>::getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data)
|
||||
void GenericFilter<T>::getFilterResults(Eigen::Ref<vectX_t<T>> results, const vectX_t<T>& data)
|
||||
{
|
||||
assert(m_status == FilterStatus::READY);
|
||||
if (results.size() != data.size())
|
||||
return false;
|
||||
|
||||
Expects(m_isInitialized);
|
||||
Expects(results.size() == data.size());
|
||||
for (Eigen::Index i = 0; i < data.size(); ++i)
|
||||
results(i) = stepFilter(data(i));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GenericFilter<T>::resetFilter()
|
||||
void GenericFilter<T>::resetFilter() noexcept
|
||||
{
|
||||
m_filteredData.setZero(m_aCoeff.size());
|
||||
m_rawData.setZero(m_bCoeff.size());
|
||||
|
@ -110,17 +76,16 @@ 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>");
|
||||
|
||||
if (!checkCoeffs(aCoeff, bCoeff))
|
||||
return;
|
||||
|
||||
checkCoeffs(aCoeff, bCoeff);
|
||||
m_aCoeff = aCoeff;
|
||||
m_bCoeff = bCoeff;
|
||||
resetFilter();
|
||||
normalizeCoeffs();
|
||||
resetFilter();
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GenericFilter<T>::getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const
|
||||
void GenericFilter<T>::getCoeffs(vectX_t<T>& aCoeff, vectX_t<T>& bCoeff) const noexcept
|
||||
{
|
||||
aCoeff = m_aCoeff;
|
||||
bCoeff = m_bCoeff;
|
||||
|
@ -135,18 +100,15 @@ GenericFilter<T>::GenericFilter(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoe
|
|||
, m_filteredData(aCoeff.size())
|
||||
, m_rawData(bCoeff.size())
|
||||
{
|
||||
if (!checkCoeffs(aCoeff, bCoeff))
|
||||
return;
|
||||
|
||||
resetFilter();
|
||||
checkCoeffs(aCoeff, bCoeff);
|
||||
normalizeCoeffs();
|
||||
resetFilter();
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GenericFilter<T>::normalizeCoeffs()
|
||||
{
|
||||
assert(m_status == FilterStatus::READY);
|
||||
|
||||
T a0 = m_aCoeff(0);
|
||||
if (std::abs(a0 - T(1)) < std::numeric_limits<T>::epsilon())
|
||||
return;
|
||||
|
@ -156,21 +118,11 @@ void GenericFilter<T>::normalizeCoeffs()
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
bool GenericFilter<T>::checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
|
||||
void GenericFilter<T>::checkCoeffs(const vectX_t<T>& aCoeff, const vectX_t<T>& bCoeff)
|
||||
{
|
||||
m_status = FilterStatus::NONE;
|
||||
if (aCoeff.size() == 0)
|
||||
m_status = FilterStatus::A_COEFF_MISSING;
|
||||
else if (std::abs(aCoeff[0]) < std::numeric_limits<T>::epsilon())
|
||||
m_status = FilterStatus::BAD_A_COEFF;
|
||||
|
||||
if (bCoeff.size() == 0)
|
||||
m_status = (m_status == FilterStatus::A_COEFF_MISSING ? FilterStatus::ALL_COEFF_MISSING : FilterStatus::B_COEFF_MISSING);
|
||||
|
||||
if (m_status == FilterStatus::NONE)
|
||||
m_status = FilterStatus::READY;
|
||||
|
||||
return m_status == FilterStatus::READY;
|
||||
Expects(aCoeff.size() > 0);
|
||||
Expects(std::abs(aCoeff[0]) > std::numeric_limits<T>::epsilon());
|
||||
Expects(bCoeff.size() > 0);
|
||||
}
|
||||
|
||||
} // namespace difi
|
|
@ -50,11 +50,7 @@ public:
|
|||
/*! \brief Set the size of the moving average window. */
|
||||
void setWindowSize(int windowSize)
|
||||
{
|
||||
if (windowSize <= 0) {
|
||||
m_status = FilterStatus::BAD_ORDER_SIZE;
|
||||
return;
|
||||
}
|
||||
|
||||
Expects(windowSize > 0);
|
||||
setCoeffs(vectX_t<T>::Constant(1, T(1)), vectX_t<T>::Constant(windowSize, T(1) / windowSize));
|
||||
}
|
||||
/*! \brief Get the size of the moving average window. */
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept> // for logic_error
|
||||
|
||||
//
|
||||
// make suppress attributes parse for some compilers
|
||||
// Hopefully temporary until suppresion standardization occurs
|
||||
//
|
||||
#if defined(_MSC_VER)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
|
||||
#else
|
||||
#if defined(__clang__)
|
||||
#define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
|
||||
#else
|
||||
#define GSL_SUPPRESS(x)
|
||||
#endif // __clang__
|
||||
#endif // _MSC_VER
|
||||
|
||||
//
|
||||
// Temporary until MSVC STL supports no-exceptions mode.
|
||||
// Currently terminate is a no-op in this mode, so we add termination behavior back
|
||||
//
|
||||
#if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
|
||||
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
|
||||
#include <intrin.h>
|
||||
#define RANGE_CHECKS_FAILURE 0
|
||||
#endif
|
||||
|
||||
//
|
||||
// There are three configuration options for this GSL implementation's behavior
|
||||
// when pre/post conditions on the GSL types are violated:
|
||||
//
|
||||
// 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
|
||||
// 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
|
||||
// 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens
|
||||
//
|
||||
#if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) || defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) || defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
|
||||
#define GSL_TERMINATE_ON_CONTRACT_VIOLATION
|
||||
#endif
|
||||
|
||||
#define GSL_STRINGIFY_DETAIL(x) #x
|
||||
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define GSL_LIKELY(x) (!!(x))
|
||||
#define GSL_UNLIKELY(x) (!!(x))
|
||||
#endif
|
||||
|
||||
//
|
||||
// GSL_ASSUME(cond)
|
||||
//
|
||||
// Tell the optimizer that the predicate cond must hold. It is unspecified
|
||||
// whether or not cond is actually evaluated.
|
||||
//
|
||||
#ifdef _MSC_VER
|
||||
#define GSL_ASSUME(cond) __assume(cond)
|
||||
#elif defined(__GNUC__)
|
||||
#define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable())
|
||||
#else
|
||||
#define GSL_ASSUME(cond) static_cast<void>((cond) ? 0 : 0)
|
||||
#endif
|
||||
|
||||
//
|
||||
// GSL.assert: assertions
|
||||
//
|
||||
|
||||
namespace gsl {
|
||||
struct fail_fast : public std::logic_error {
|
||||
explicit fail_fast(char const* const message)
|
||||
: std::logic_error(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace details {
|
||||
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
|
||||
typedef void(__cdecl* terminate_handler)();
|
||||
|
||||
GSL_SUPPRESS(f .6) // NO-FORMAT: attribute
|
||||
[[noreturn]] inline void __cdecl default_terminate_handler()
|
||||
{
|
||||
__fastfail(RANGE_CHECKS_FAILURE);
|
||||
}
|
||||
|
||||
inline gsl::details::terminate_handler& get_terminate_handler() noexcept
|
||||
{
|
||||
static terminate_handler handler = &default_terminate_handler;
|
||||
return handler;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[noreturn]] inline void terminate() noexcept
|
||||
{
|
||||
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||
(*gsl::details::get_terminate_handler())();
|
||||
#else
|
||||
std::terminate();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||
|
||||
template <typename Exception>
|
||||
[[noreturn]] void throw_exception(Exception&&) noexcept
|
||||
{
|
||||
gsl::details::terminate();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Exception>
|
||||
[[noreturn]] void throw_exception(Exception&& exception) {
|
||||
throw std::forward<Exception>(exception);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace details
|
||||
} // namespace gsl
|
||||
|
||||
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
|
||||
|
||||
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||
(GSL_LIKELY(cond) ? static_cast<void>(0) \
|
||||
: gsl::details::throw_exception(gsl::fail_fast( \
|
||||
"GSL: " type " failure in " __FILE__ " at line " GSL_STRINGIFY(__LINE__) ")")))
|
||||
|
||||
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||
|
||||
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
|
||||
|
||||
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
|
||||
|
||||
#define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond)
|
||||
|
||||
#endif
|
||||
|
||||
#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
|
||||
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
|
|
@ -35,21 +35,4 @@ using vectX_t = Eigen::Matrix<T, Eigen::Dynamic, 1>; /*!< Eigen column-vector */
|
|||
template <typename T>
|
||||
using vectXc_t = vectX_t<std::complex<T>>; /*!< Eigen complex column-vector */
|
||||
|
||||
/*! \brief Filter status */
|
||||
enum class FilterStatus {
|
||||
// Generic filter
|
||||
NONE, /*!< Filter has not yet been initialized */
|
||||
READY, /*!< Filter is ready to process data */
|
||||
BAD_ORDER_SIZE, /*!< Order of the filter is bad */
|
||||
BAD_A_COEFF, /*!< Denominator coefficients of the filter is bad */
|
||||
A_COEFF_MISSING, /*!< Denominator coefficients have not been set */
|
||||
B_COEFF_MISSING, /*!< Numerator coefficients have not been set */
|
||||
ALL_COEFF_MISSING = A_COEFF_MISSING | B_COEFF_MISSING, /*!< Coefficients have not been set */
|
||||
|
||||
// Butterworth filter
|
||||
BAD_FREQUENCY_VALUE, /*!< Given frequency is bad */
|
||||
BAD_CUTOFF_FREQUENCY, /*!< Given ctu-off frequency is bad */
|
||||
BAD_BAND_FREQUENCY /*!< Given band frequency is bad */
|
||||
};
|
||||
|
||||
} // namespace difi
|
|
@ -27,26 +27,31 @@
|
|||
|
||||
#include "difi"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(FILTER_FAILURES)
|
||||
{
|
||||
auto dfd = difi::DigitalFilterd(Eigen::VectorXd(), Eigen::VectorXd::Constant(2, 0));
|
||||
BOOST_REQUIRE(dfd.status() == difi::FilterStatus::A_COEFF_MISSING);
|
||||
dfd = difi::DigitalFilterd(Eigen::VectorXd::Constant(2, 1), Eigen::VectorXd());
|
||||
BOOST_REQUIRE(dfd.status() == difi::FilterStatus::B_COEFF_MISSING);
|
||||
dfd = difi::DigitalFilterd(Eigen::VectorXd(), Eigen::VectorXd());
|
||||
BOOST_REQUIRE(dfd.status() == difi::FilterStatus::ALL_COEFF_MISSING);
|
||||
dfd = difi::DigitalFilterd(Eigen::VectorXd::Constant(2, 0), Eigen::VectorXd::Constant(2, 0));
|
||||
BOOST_REQUIRE(dfd.status() == difi::FilterStatus::BAD_A_COEFF);
|
||||
dfd = difi::DigitalFilterd();
|
||||
BOOST_REQUIRE(dfd.status() == difi::FilterStatus::NONE);
|
||||
dfd = difi::DigitalFilterd(Eigen::VectorXd::Constant(2, 1), Eigen::VectorXd::Constant(2, 0));
|
||||
BOOST_REQUIRE(dfd.status() == difi::FilterStatus::READY);
|
||||
auto mad = difi::MovingAveraged(0);
|
||||
BOOST_REQUIRE(mad.status() == difi::FilterStatus::BAD_ORDER_SIZE);
|
||||
auto bfd = difi::Butterworthd(0, 10, 100);
|
||||
BOOST_REQUIRE(bfd.status() == difi::FilterStatus::BAD_ORDER_SIZE);
|
||||
bfd = difi::Butterworthd(5, 6, 5, 100);
|
||||
BOOST_REQUIRE(bfd.status() == difi::FilterStatus::BAD_BAND_FREQUENCY);
|
||||
// A coeff are missing
|
||||
BOOST_REQUIRE_THROW(difi::DigitalFilterd(Eigen::VectorXd(), Eigen::VectorXd::Constant(2, 0)), std::logic_error);
|
||||
// B coeff are missing
|
||||
BOOST_REQUIRE_THROW(difi::DigitalFilterd(Eigen::VectorXd::Constant(2, 1), Eigen::VectorXd()), std::logic_error);
|
||||
// aCoeff(0) = 0
|
||||
BOOST_REQUIRE_THROW(difi::DigitalFilterd(Eigen::VectorXd::Constant(2, 0), Eigen::VectorXd::Constant(2, 0)), std::logic_error);
|
||||
// Filter left uninitialized
|
||||
BOOST_REQUIRE_NO_THROW(difi::DigitalFilterd());
|
||||
auto df = difi::DigitalFilterd();
|
||||
// Filter data with uninitialized filter
|
||||
BOOST_REQUIRE_THROW(df.stepFilter(10.), std::logic_error);
|
||||
// window <= 0
|
||||
BOOST_REQUIRE_THROW(difi::MovingAveraged(0), std::logic_error);
|
||||
// order <= 0
|
||||
BOOST_REQUIRE_THROW(difi::Butterworthd(0, 10, 100), std::logic_error);
|
||||
// fc > 2*fs
|
||||
BOOST_REQUIRE_THROW(difi::Butterworthd(2, 60, 100), std::logic_error);
|
||||
// Upper frequency < lower frequency
|
||||
BOOST_REQUIRE_THROW(difi::Butterworthd(2, 6, 5, 100), std::logic_error);
|
||||
|
||||
// Ok
|
||||
BOOST_REQUIRE_NO_THROW(difi::DigitalFilterd(Eigen::VectorXd::Constant(2, 1), Eigen::VectorXd::Constant(2, 0)));
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue