kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

commit bd01dfab4e1354ec6c6c5ed5a548b68fd7ccf8d2
parent 0902232812a92dcdcf78d2bbb05f9187cdde6270
Author: Stephen Larew <[email protected]>
Date:   Thu, 20 Feb 2020 12:30:38 -0800

add moving_sum expression

Diffstat:
Minclude/kfr/dsp/fir.hpp | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/dsp_test.cpp | 29+++++++++++++++++++++++++++--
2 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/include/kfr/dsp/fir.hpp b/include/kfr/dsp/fir.hpp @@ -71,6 +71,21 @@ struct fir_state mutable size_t delayline_cursor; }; +template <typename U, univector_tag Tag = tag_dynamic_vector> +struct moving_sum_state +{ + moving_sum_state() : delayline({ 0 }), head_cursor(0), tail_cursor(1) {} + mutable univector<U, Tag> delayline; + mutable size_t head_cursor, tail_cursor; +}; +template <typename U> +struct moving_sum_state<U, tag_dynamic_vector> +{ + moving_sum_state(size_t sum_length) : delayline(sum_length, U(0)), head_cursor(0), tail_cursor(1) {} + mutable univector<U> delayline; + mutable size_t head_cursor, tail_cursor; +}; + namespace internal { @@ -134,6 +149,51 @@ struct expression_fir : expression_with_arguments<E1> } state_holder<fir_state<T, U>, stateless> state; }; + +template <typename U, typename E1, univector_tag STag, bool stateless = false> +struct expression_moving_sum : expression_with_arguments<E1> +{ + using value_type = U; + + expression_moving_sum(E1&& e1, const moving_sum_state<U, STag>& state) + : expression_with_arguments<E1>(std::forward<E1>(e1)), state(state) + { + } + + template <size_t N> + KFR_INTRINSIC friend vec<U, N> get_elements(const expression_moving_sum& self, cinput_t cinput, + size_t index, vec_shape<U, N> x) + { + static_assert(N >= 1, ""); + + const vec<U, N> input = self.argument_first(cinput, index, x); + + vec<U, N> output; + size_t wcursor = self.state.s.head_cursor; + size_t rcursor = self.state.s.tail_cursor; + + // initial summation + self.state.s.delayline.ringbuf_write(wcursor, input[0]); + auto s = sum(self.state.s.delayline); + output[0] = s; + + CMT_LOOP_NOUNROLL + for (size_t i = 1; i < N; i++) + { + U nextout; + self.state.s.delayline.ringbuf_read(rcursor, nextout); + U const nextin = input[i]; + self.state.s.delayline.ringbuf_write(wcursor, nextin); + s += nextin - nextout; + output[i] = s; + } + self.state.s.delayline.ringbuf_step(rcursor, 1); + self.state.s.head_cursor = wcursor; + self.state.s.tail_cursor = rcursor; + return output; + } + state_holder<moving_sum_state<U, STag>, stateless> state; +}; } // namespace internal /** @@ -159,6 +219,30 @@ KFR_INTRINSIC internal::expression_fir<T, U, E1, true> fir(fir_state<T, U>& stat } /** + * @brief Returns template expression that performs moving sum on the input + * @param state moving sum state + * @param e1 an input expression + */ +template <size_t sum_length, typename E1> +KFR_INTRINSIC internal::expression_moving_sum<value_type_of<E1>, E1, tag_dynamic_vector> moving_sum(E1&& e1) +{ + return internal::expression_moving_sum<value_type_of<E1>, E1, tag_dynamic_vector>(std::forward<E1>(e1), + sum_length); +} + +/** + * @brief Returns template expression that performs moving sum on the input + * @param state moving sum state + * @param e1 an input expression + */ +template <typename U, typename E1, univector_tag STag> +KFR_INTRINSIC internal::expression_moving_sum<U, E1, STag, true> moving_sum(moving_sum_state<U, STag>& state, + E1&& e1) +{ + return internal::expression_moving_sum<U, E1, STag, true>(std::forward<E1>(e1), state); +} + +/** * @brief Returns template expression that applies FIR filter to the input (count of coefficients must be in * range 2..32) * @param e1 an input expression diff --git a/tests/dsp_test.cpp b/tests/dsp_test.cpp @@ -417,6 +417,31 @@ TEST(fir) result += data.get(index - i, 0) * taps[i]; return result; }); + + CHECK_EXPRESSION(moving_sum<taps.size()>(data), 100, [&](size_t index) -> T { + T result = 0; + for (size_t i = 0; i < taps.size(); i++) + result += data.get(index - i, 0); + return result; + }); + + moving_sum_state<T, 131> msstate1; + + CHECK_EXPRESSION(moving_sum(msstate1, data), 100, [&](size_t index) -> T { + T result = 0; + for (size_t i = 0; i < msstate1.delayline.size(); i++) + result += data.get(index - i, 0); + return result; + }); + + moving_sum_state<T> msstate2(133); + + CHECK_EXPRESSION(moving_sum(msstate2, data), 100, [&](size_t index) -> T { + T result = 0; + for (size_t i = 0; i < msstate2.delayline.size(); i++) + result += data.get(index - i, 0); + return result; + }); }); #endif } @@ -599,9 +624,9 @@ TEST(resampler_test) } // namespace CMT_ARCH_NAME #ifndef KFR_NO_MAIN -int main() +int main(int argc, char* argv[]) { println(library_version()); - return testo::run_all("", true); + return testo::run_all(argc > 1 ? argv[1] : "", true); } #endif