From 21415d9a7b6b73dd2c9e1727f2b63a9c52d68a3a Mon Sep 17 00:00:00 2001 From: camilo Date: Sat, 30 Dec 2023 11:26:41 -0500 Subject: [PATCH] fixes and bump to 1.0.6 --- check/qlibs_cpp_test.cpp | 1 + doc/qfp16.dox | 58 +++++++++++++++++++++++----------------- doc/qtdl.dox | 15 ++++++++++- library.json | 2 +- library.properties | 2 +- src/bitfield.cpp | 32 +++++++++++----------- src/ffmath.cpp | 18 ++++++++----- src/include/bitfield.hpp | 26 +++++++++--------- src/include/ltisys.hpp | 38 ++++++-------------------- src/ltisys.cpp | 45 +++++++++++-------------------- src/qlibs.h | 5 ++-- 11 files changed, 117 insertions(+), 125 deletions(-) diff --git a/check/qlibs_cpp_test.cpp b/check/qlibs_cpp_test.cpp index 489ef17..faa4863 100644 --- a/check/qlibs_cpp_test.cpp +++ b/check/qlibs_cpp_test.cpp @@ -9,6 +9,7 @@ void test_tdl( void ); void test_fp16( void ); void test_crc( void ); void test_ltisys( void ); +void test_ffmath( void ); void test_tdl( void ) { diff --git a/doc/qfp16.dox b/doc/qfp16.dox index 6478c9b..56a3f70 100644 --- a/doc/qfp16.dox +++ b/doc/qfp16.dox @@ -26,11 +26,11 @@ * Conversion from integers and floating-point values. These conversions retain * the numeric value and perform rounding where necessary. * -* - \ref qlibs::fp16::from() Convert int/float or double to the qlibs::fp16 type -* - \ref qlibs::fp16::toInt() Convert qlibs::fp16 to integer. -* - \ref qlibs::fp16::toFloat() Convert qlibs::fp16 to float. -* - \ref qlibs::fp16::toDouble() Convert qlibs::fp16 to double. -* - \ref fp16::toASCII() Convert from qlibs::fp16 to raw c-string. +* - \ref qlibs::fp16 "from()" Convert @c int , @c float or @c double to the qlibs::fp16 type. For constants use the fixed-point literal +* - \ref qlibs::fp16 "toInt()" Convert qlibs::fp16 to integer. +* - \ref qlibs::fp16 "toFloat()" Convert qlibs::fp16 to float. +* - \ref qlibs::fp16 "toDouble()" Convert qlibs::fp16 to double. +* - \ref qlibs::fp16 "toASCII()" Convert from qlibs::fp16 to raw c-string. * * @subsection qfp16_basic_arithmetic Basic arithmetic * @@ -46,33 +46,41 @@ * * Roots, exponents & similar. * -* - \ref qlibs::fp16::sqrt() Square root. Performs rounding and is accurate to fp16 limits. -* - \ref qlibs::fp16::exp() Exponential function using power series approximation. +* - \ref qlibs::fp16 "sqrt()" Square root. Performs rounding and is accurate to fp16 limits. +* - \ref qlibs::fp16 "exp()" Exponential function using power series approximation. * Accuracy depends on range, worst case \c +-40 absolute for negative inputs and * @c +-0.003% for positive inputs. Average error is @c +-1 for neg and @c +-0.0003% for pos. -* - \ref qlibs::fp16::log() Natural logarithm using Newton approximation and qlibs::fp16::exp(). +* - \ref qlibs::fp16 "log()" Natural logarithm using Newton approximation and \ref qlibs::fp16 "exp()". * Worst case error \c +-3 absolute, average error less than 1 unit. -* - \ref qlibs::fp16::log2() Logarithm base 2. -* - \ref qlibs::fp16::pow() Computes the power of a qlibs::fp16 number +* - \ref qlibs::fp16 "log2()" Logarithm base 2. +* - \ref qlibs::fp16 "pow()" Computes the power of a qlibs::fp16 number * * * @subsection qfp16_trig_functions Trigonometric functions and helpers * -* - sin() Sine for angle in radians -* - \ref qlibs::fp16::cos() Cosine for angle in radians -* - \ref qlibs::fp16::tan() Tangent for angle in radians -* - \ref qlibs::fp16::asin() Inverse of sine, output in radians -* - \ref qlibs::fp16::acos() Inverse of cosine, output in radians -* - \ref qlibs::fp16::atan() Inverse of tangent, output in radians -* - \ref qlibs::fp16::atan2() Arc tangent in radians x,y -* - \ref qlibs::fp16::sinh() Hyperbolic sine -* - \ref qlibs::fp16::cosh() Hyperbolic cosine -* - \ref qlibs::fp16::tanh() Hyperbolic tangent -* - \ref qlibs::fp16::radToDeg() Converts angle units from radians to degrees. -* - \ref qlibs::fp16::degToRad() Converts angle units from degrees to radians -* - \ref qlibs::fp16::wrapToPi() Wrap the fixed-point angle in radians to [−pi pi] -* - \ref qlibs::fp16::wrapTo180() Wrap the fixed-point angle in degrees to [−180 180] -* +* - \ref qlibs::fp16 "sin()" Sine for angle in radians +* - \ref qlibs::fp16 "cos()" Cosine for angle in radians +* - \ref qlibs::fp16 "tan()" Tangent for angle in radians +* - \ref qlibs::fp16 "asin()" Inverse of sine, output in radians +* - \ref qlibs::fp16 "acos()" Inverse of cosine, output in radians +* - \ref qlibs::fp16 "atan()" Inverse of tangent, output in radians +* - \ref qlibs::fp16 "atan2()" Arc tangent in radians x,y +* - \ref qlibs::fp16 "sinh()" Hyperbolic sine +* - \ref qlibs::fp16 "cosh()" Hyperbolic cosine +* - \ref qlibs::fp16 "tanh()" Hyperbolic tangent +* - \ref qlibs::fp16 "radToDeg()" Converts angle units from radians to degrees. +* - \ref qlibs::fp16 "degToRad()" Converts angle units from degrees to radians +* - \ref qlibs::fp16 "wrapToPi()" Wrap the fixed-point angle in radians to [−pi pi] +* - \ref qlibs::fp16 "wrapTo180()" Wrap the fixed-point angle in degrees to [−180 180] +* +* @subsection qfp16_literal Fixed-Point literals +* +* Fixed-point literal defines a compile-time constant whose value is specified +* in the source file. +* The suffix @c _fp indicates a type of \ref qlibs::fp16. +* +* A plus (+) or minus (-) symbol can precede a fixed-point literal. However, +* it is not part of the literal; it is interpreted as a unary operator. * * @section qfp16_example Example: Solution of the quadratic equation * diff --git a/doc/qtdl.dox b/doc/qtdl.dox index fbaf4ff..323cb50 100644 --- a/doc/qtdl.dox +++ b/doc/qtdl.dox @@ -18,7 +18,9 @@ * You can also get any specific delay from it by using: * * - \ref qlibs::tdl::getOldest(), to get the oldest delay at tap \f$z^{-N}\f$ -* - \ref qlibs::tdl::getAtIndex(), to get the delay at tap \f$z^{-i}\f$ +* You can also use the index at @c -1 as follows: @c "delay[ -1 ]" +* - \ref qlibs::tdl::getAtIndex(), to get the delay at tap \f$z^{-i}\f$. +* You can also use the index using an unsigned value as follows: @c "delay[ i ]" * - Index operator * * Given the applications of this structure, the \ref qlibs::tdl class is used as the @@ -30,4 +32,15 @@ * real_t storage[ 256 ] = { 0.0f }; * tdl delay( storage ); * @endcode +* +* @code{.c} +* delay.insertSample( 2.5 ); +* delay.insertSample( -2.3 ); +* delay( 4.8 ); // same as delay.insertSample( 4.8 ) +* @endcode +* +* @code{.c} +* auto d3 = delay[ 3 ]; // get delay at t-3, same as delay.getAtIndex( 3 ) +* auto dOldest = delay[ -1 ]; // get delay at t-255 , same as delay.getOldest() +* @endcode */ \ No newline at end of file diff --git a/library.json b/library.json index 60fe4ac..bb0d275 100644 --- a/library.json +++ b/library.json @@ -16,7 +16,7 @@ "maintainer": true } ], - "version": "1.0.5", + "version": "1.0.6", "license": "MIT", "frameworks": "arduino", "platforms": "*" diff --git a/library.properties b/library.properties index eaa1ae0..a0543a9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=qlibs -version=1.0.5 +version=1.0.6 license=MIT author=J. Camilo Gomez C. maintainer=J. Camilo Gomez C. diff --git a/src/bitfield.cpp b/src/bitfield.cpp index 6ccc21c..fa6b70d 100644 --- a/src/bitfield.cpp +++ b/src/bitfield.cpp @@ -50,7 +50,7 @@ bool bitfield::setBit( const size_t index ) noexcept bool retValue = false; if ( nullptr != field ) { - bitSet( index ); + set( index ); retValue = true; } @@ -62,7 +62,7 @@ bool bitfield::clearBit( const size_t index ) noexcept bool retValue = false; if ( nullptr != field ) { - bitClear( index ); + clear( index ); retValue = true; } @@ -74,7 +74,7 @@ bool bitfield::toggleBit( const size_t index ) noexcept bool retValue = false; if ( nullptr != field ) { - bitToggle( index ); + toggle( index ); retValue = true; } @@ -86,7 +86,7 @@ bool bitfield::readBit( const size_t index ) const noexcept bool retValue = false; if ( nullptr != field ) { - retValue = 0U != bitGet( index ); + retValue = 0U != get( index ); } return retValue; @@ -99,10 +99,10 @@ bool bitfield::writeBit( const size_t index, if ( nullptr != field ) { if ( value ) { - bitSet( index ); + set( index ); } else { - bitClear( index ); + clear( index ); } retValue = true; } @@ -206,18 +206,18 @@ void* bitfield::dump( void * const dst, /*============================================================================*/ uint32_t bitfield::read_uint32( const size_t index ) const noexcept { - size_t slot, of, bits_taken; + size_t s, of, bits_taken; uint32_t result; - slot = bitSlot( index ); + s = slot( index ); of = offset( index ); /*cstat -CERT-INT34-C_a*/ - result = field[ slot ] >> of; + result = field[ s ] >> of; /*cstat +CERT-INT34-C_a*/ bits_taken = 32U - of; if ( ( 0U != of ) && ( ( index + bits_taken ) < size ) ) { /*cstat -ATH-shift-bounds -MISRAC++2008-5-8-1 -CERT-INT34-C_b*/ - result |= field[ slot + 1U ] << static_cast( bits_taken ); + result |= field[ s + 1U ] << static_cast( bits_taken ); /*cstat +ATH-shift-bounds +MISRAC++2008-5-8-1 +CERT-INT34-C_b*/ } @@ -228,20 +228,20 @@ void bitfield::write_uint32( const size_t index, const uint32_t value ) noexcept { uint32_t wMask; - size_t slot, of; + size_t s, of; - slot = bitSlot( index ); + s = slot( index ); of = offset( index ); if ( 0U == of ) { - field[ slot ] = value; + field[ s ] = value; } else { wMask = safeMask( 0xFFFFFFFFU, LBit, of ); /*cstat -CERT-INT34-C_a*/ - field[ slot ] = ( value << of ) | ( field[ slot ] & wMask ); + field[ s ] = ( value << of ) | ( field[ s ] & wMask ); /*cstat +CERT-INT34-C_a*/ - if ( ++slot < nSlots ) { - field[ slot ] = safeMask( value, 32U, of ) | ( field[ slot ] & ( ~wMask ) ); + if ( ++s < nSlots ) { + field[ s ] = safeMask( value, 32U, of ) | ( field[ s ] & ( ~wMask ) ); } } } diff --git a/src/ffmath.cpp b/src/ffmath.cpp index 5117417..01d66b6 100644 --- a/src/ffmath.cpp +++ b/src/ffmath.cpp @@ -5,6 +5,7 @@ using namespace qlibs; template static inline void cast_reinterpret( T1 &f, const T2 &u ) { + static_assert( sizeof(T1)==sizeof(T2), "Types must match sizes" ); (void)memcpy( &f, &u, sizeof(T2) ); } @@ -204,13 +205,18 @@ float ffmath::mod( float x, float y ) float ffmath::sin( float x ) { float y; + if ( ffmath::absf( x ) <= 0.0066F ) { + y = x; + } + else { + x *= -ffmath::FFP_1_PI; + y = x + 25165824.0F; + x -= y - 25165824.0F; + x *= ffmath::absf( x ) - 1.0F; + y = x*( ( 3.5841304553896F*ffmath::absf( x ) ) + 3.1039673861526F ); + } - x *= -ffmath::FFP_1_PI; - y = x + 25165824.0F; - x -= y - 25165824.0F; - x *= ffmath::absf( x ) - 1.0F; - - return x*( ( 3.5841304553896F*ffmath::absf( x ) ) + 3.1039673861526F ); + return y; } /*============================================================================*/ float ffmath::cos( float x ) diff --git a/src/include/bitfield.hpp b/src/include/bitfield.hpp index bbfd9d9..9548bd3 100644 --- a/src/include/bitfield.hpp +++ b/src/include/bitfield.hpp @@ -46,31 +46,31 @@ namespace qlibs { { return static_cast( 1U ) << ( index % LBit ); } - inline size_t bitSlot( const size_t index ) const noexcept + inline size_t slot( const size_t index ) const noexcept { return index/LBit; } - inline uint32_t bitGet( const size_t index ) const noexcept + inline uint32_t get( const size_t index ) const noexcept { - const size_t slot = bitSlot( index ); - return ( field[ slot ] >> ( index % LBit ) ) & 1U; + const size_t s = slot( index ); + return ( field[ s ] >> ( index % LBit ) ) & 1U; } - inline void bitSet( const size_t index ) noexcept + inline void set( const size_t index ) noexcept { - const size_t slot = bitSlot( index ); - field[ slot ] |= mask( index ); + const size_t s = slot( index ); + field[ s ] |= mask( index ); } - inline void bitClear( const size_t index ) noexcept + inline void clear( const size_t index ) noexcept { - const size_t slot = bitSlot( index ); + const size_t s = slot( index ); - field[ slot ] &= ~mask( index ); + field[ s ] &= ~mask( index ); } - inline void bitToggle( const size_t index ) noexcept + inline void toggle( const size_t index ) noexcept { - const size_t slot = bitSlot( index ); + const size_t s = slot( index ); - field[ slot ] ^= mask( index ); + field[ s ] ^= mask( index ); } inline uint32_t safeMask( const uint32_t val, const size_t x, diff --git a/src/include/ltisys.hpp b/src/include/ltisys.hpp index e71aed4..bbd049b 100644 --- a/src/include/ltisys.hpp +++ b/src/include/ltisys.hpp @@ -98,6 +98,8 @@ namespace qlibs { size_t n_den ); real_t saturate( real_t y ); ltisysType type{ LTISYS_TYPE_UNKNOWN }; + virtual real_t update( const real_t u ) = 0; + public: virtual ~ltisys() {} ltisys() = default; @@ -105,10 +107,13 @@ namespace qlibs { /** * @brief Drives the LTI system recursively using the input signal provided * @pre Instance must be previously initialized. + * @note The user must ensure that this function is executed in the + * required sample time @a T or time step @a dt either by using a + * HW or SW timer, a real time task or a timing service. * @param[in] u A sample of the input signal that excites the system * @return The system response. */ - virtual real_t excite( real_t u ) = 0; + real_t excite( real_t u ); /** * @brief Check if the LTI system is initialized. @@ -167,7 +172,7 @@ namespace qlibs { class discreteSystem : public ltisys { private: real_t *xd{ nullptr }; - real_t update( const real_t u ); + real_t update( const real_t u ) override; public: virtual ~discreteSystem() {} @@ -352,20 +357,6 @@ namespace qlibs { const size_t wsize, const real_t x, const real_t * const c = nullptr ); - - /** - * @brief Drives the discrete LTI system recursively using the input - * signal provided - * @pre Instance must be previously initialized using the - * discreteSystem::setup() method - * @note The user must ensure that this function is executed in the - * required sample time @a T either by using a HW or SW timer, a - * real time task or a timing service. - * @param[in] u A sample of the input signal that excites the system - * @return The system response. - */ - real_t excite( real_t u ) override; - }; /** @@ -377,7 +368,7 @@ namespace qlibs { private: real_t dt{ 1.0_re }; state *xc{ nullptr }; - real_t update( const real_t u ); + real_t update( const real_t u ) override; public: virtual ~continuousSystem() {} @@ -560,19 +551,6 @@ namespace qlibs { * @return @c true on success, otherwise return @c false. */ bool setIntegrationMethod( integrationMethod m ); - - /** - * @brief Drives the continuous LTI system recursively using the input - * signal provided - * @pre Instance must be previously initialized using the - * continuousSystem::setup() method - * @note The user must ensure that this function is executed in the time - * specified in @a dt either by using a HW or SW timer, a real time task, - * or a timing service. - * @param[in] u A sample of the input signal that excites the system - * @return The system response. - */ - real_t excite( real_t u ) override; }; /** @}*/ diff --git a/src/ltisys.cpp b/src/ltisys.cpp index 40b590c..a71799d 100644 --- a/src/ltisys.cpp +++ b/src/ltisys.cpp @@ -62,6 +62,21 @@ bool ltisys::setSaturation( const real_t minV, return retValue; } /*============================================================================*/ +real_t ltisys::excite( real_t u ) +{ + real_t y = 0.0_re; + + if ( isInitialized() ) { + if ( tdl::isInitialized() ) { + insertSample( u ); + u = getOldest(); + } + y = saturate( update( u ) ); + } + + return y; +} +/*============================================================================*/ real_t discreteSystem::updateFIR( real_t *w, const size_t wsize, const real_t x, @@ -145,21 +160,6 @@ real_t discreteSystem::update( const real_t u ) return updateFIR( xd, n, v, b ); } /*============================================================================*/ -real_t discreteSystem::excite( real_t u ) -{ - real_t y = 0.0_re; - - if ( isInitialized() ) { - if ( tdl::isInitialized() ) { - insertSample( u ); - u = getOldest(); - } - y = saturate( update( u ) ); - } - - return y; -} -/*============================================================================*/ bool continuousSystem::setup( real_t *num, real_t *den, state *x, @@ -235,21 +235,6 @@ real_t continuousSystem::update( const real_t u ) return y; } /*============================================================================*/ -real_t continuousSystem::excite( real_t u ) -{ - real_t y = 0.0_re; - - if ( isInitialized() ) { - if ( tdl::isInitialized() ) { - insertSample( u ); - u = getOldest(); - } - y = saturate( update( u ) ); - } - - return y; -} -/*============================================================================*/ bool continuousSystem::setIntegrationMethod( integrationMethod m ) { bool retValue = false; diff --git a/src/qlibs.h b/src/qlibs.h index 3d08286..603d800 100644 --- a/src/qlibs.h +++ b/src/qlibs.h @@ -41,8 +41,8 @@ This file is part of the QuarkTS++ OS distribution. #ifndef QLIBS_CPP_H #define QLIBS_CPP_H -#define QLIBS_CPP_VERSION "1.0.5" -#define QLIBS_CPP_VERNUM ( 105u ) +#define QLIBS_CPP_VERSION "1.0.6" +#define QLIBS_CPP_VERNUM ( 106U ) #define QLIBS_CPP_CAPTION "qLibs++" QLIBS_CPP_VERSION #include @@ -58,6 +58,7 @@ This file is part of the QuarkTS++ OS distribution. #include #include #include +#include using namespace qlibs;