Change error code to throws.

topic/diffentiators v1.1
Vincent Samy 2019-01-11 19:07:11 +09:00
rodzic 06c70f4ef0
commit 24df3ddedc
11 zmienionych plików z 245 dodań i 148 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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));
}

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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

Wyświetl plik

@ -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. */

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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)));
}