diff --git a/dsp/mrate/fir_decim.cpp b/dsp/mrate/fir_decim.cpp new file mode 100644 index 0000000..f1f354e --- /dev/null +++ b/dsp/mrate/fir_decim.cpp @@ -0,0 +1,107 @@ +#include "fir_decim.h" +#include "../complex.h" +#include +#include + +namespace dsp::mrate { + template + FIRDecim::FIRDecim() {} + + template + FIRDecim::FIRDecim(const Taps& taps, int decim) { + // Save the parameters + this->taps = taps; + this->decim = decim; + + // Pre-allocate the history buffer + hist.reserve(taps.size()); + + // Initialize the state + reset(); + } + + template + FIRDecim::FIRDecim(Taps&& taps, int decim) { + // Save the parameters + this->taps = taps; + this->decim = decim; + + // Pre-allocate the history buffer + hist.reserve(taps.size()); + + // Initialize the state + reset(); + } + + template + const Taps& FIRDecim::getTaps() const { + // Return the taps + return taps; + } + + template + void FIRDecim::setTaps(const Taps& taps, int decim) { + // Update the taps + this->taps = taps; + + // Update the decimation factor if it was given + if (decim) { this->decim = decim; } + } + + template + void FIRDecim::setTaps(Taps&& taps, int decim) { + // Update the taps + this->taps = taps; + + // Update the decimation factor if it was given + if (decim) { this->decim = decim; } + } + + template + void FIRDecim::reset() { + // Zero out the history buffer + memset(hist.data(), 0, (taps.size() - 1) * sizeof(SAMPLE)); + + // Reset the offset + offset = 0; + } + + template + size_t FIRDecim::process(const SAMPLE* in, SAMPLE* out, size_t count) { + // Reserve enough space in the history buffer + hist.reserve(taps.size() + count - 1, REALLOC_KEEP); + + // Copy over the new input samples + memcpy(&hist[taps.size() - 1], in, count * sizeof(SAMPLE)); + + // Filter the samples + uintptr_t i; + uintptr_t io = 0; + for (i = offset; i < count; i += decim) { + // Compute the dot product depending on type + if constexpr (std::is_same_v) { + volk_32f_x2_dot_prod_32f(&out[io++], &hist[i], taps.data(), taps.size()); + } + else if constexpr (std::is_same_v && std::is_same_v) { + volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&out[io++], (const lv_32fc_t*)&hist[i], taps.data(), taps.size()); + } + else if constexpr (std::is_same_v && std::is_same_v) { + volk_32fc_x2_dot_prod_32fc((lv_32fc_t*)&out[io++], (const lv_32fc_t*)&hist[i], (const lv_32fc_t*)taps.data(), taps.size()); + } + } + + // Update the offset + offset = i - count; + + // Move over the unused sample to the history buffer + memmove(hist.data(), &hist[count], (taps.size() - 1) * sizeof(SAMPLE)); + + // Return the number of samples generated + return io; + } + + // Instantiate the class + template class FIRDecim; + template class FIRDecim; + template class FIRDecim; +} \ No newline at end of file diff --git a/dsp/mrate/fir_decim.h b/dsp/mrate/fir_decim.h new file mode 100644 index 0000000..f554321 --- /dev/null +++ b/dsp/mrate/fir_decim.h @@ -0,0 +1,79 @@ +#pragma once +#include "../processor.h" +#include "../buffer.h" +#include "../taps.h" + +namespace dsp::mrate { + template + class FIRDecim { + public: + // Default constructor + FIRDecim(); + + /** + * Create a decimating FIR filter. + * @param taps Taps to use for the filter. + * @param decim Decimation factor. + */ + FIRDecim(const Taps& taps, int decim); + + /** + * Create a decimating FIR filter. + * @param taps Taps to use for the filter. + * @param decim Decimation factor. + */ + FIRDecim(Taps&& taps, int decim); + + /** + * Get the filter taps. + * @return Filter taps. + */ + const Taps& getTaps() const; + + /** + * Set the filter taps. + * @param taps Filter taps. + * @param decim Decimation factor. Zero to keep unchanged. + */ + void setTaps(const Taps& taps, int decim = 0); + + /** + * Set the filter taps. + * @param taps Filter taps. + * @param decim Decimation factor. Zero to keep unchanged. + */ + void setTaps(Taps&& taps, int decim = 0); + + /** + * Get the decimation factor. + * @return Decimation factor. + */ + int getDecimation(); + + /** + * Set the decimation factor. + * @param decim Decimation factor. + */ + void setDecimation(int decim); + + /** + * Reset the state of the filter. + */ + void reset(); + + /** + * Filter and decimate samples. + * @param in Input samples. + * @param out Output samples. + * @param count Number of samples to filter. + * @return Number of samples generates. + */ + size_t process(const SAMPLE* in, SAMPLE* out, size_t count); + + private: + Buffer hist; + uintptr_t offset = 0; + Taps taps; + int decim = 0; + }; +} \ No newline at end of file diff --git a/dsp/mrate/fir_interp.cpp b/dsp/mrate/fir_interp.cpp new file mode 100644 index 0000000..d65e6ce --- /dev/null +++ b/dsp/mrate/fir_interp.cpp @@ -0,0 +1,98 @@ +#include "fir_interp.h" +#include "../complex.h" +#include +#include + +namespace dsp::mrate { + template + FIRInterp::FIRInterp() {} + + template + FIRInterp::FIRInterp(const Taps& taps, int interp) { + // Save the parameters + this->taps = taps; + this->interp = interp; + + // Pre-allocate the history buffer + hist.reserve(taps.size()); + + // Initialize the state + reset(); + + // Generate the tap phases + generatePhases(); + } + + template + FIRInterp::FIRInterp(Taps&& taps, int interp) { + // Save the parameters + this->taps = taps; + this->interp = interp; + + // Pre-allocate the history buffer + hist.reserve(taps.size()); + + // Initialize the state + reset(); + + // Generate the tap phases + generatePhases(); + } + + template + const Taps& FIRInterp::getTaps() const { + // Return the taps + return taps; + } + + template + void FIRInterp::setTaps(const Taps& taps, int interp) { + // Update the taps + this->taps = taps; + + // Update the interpolation factor if it was given + if (interp) { this->interp = interp; } + + // Regenerate the tap phases + generatePhases(); + } + + template + void FIRInterp::setTaps(Taps&& taps, int interp) { + // Update the taps + this->taps = taps; + + // Update the interpolation factor if it was given + if (interp) { this->interp = interp; } + + // Regenerate the tap phases + generatePhases(); + } + + template + void FIRInterp::reset() { + // Zero out the history buffer + memset(hist.data(), 0, (taps.size() - 1) * sizeof(SAMPLE)); + + // Reset the offset + offset = 0; + } + + template + size_t FIRInterp::process(const SAMPLE* in, SAMPLE* out, size_t count) { + // TODO + + // Return the number of samples generated + return 0; + } + + template + void FIRInterp::generatePhases() { + // TODO + } + + // Instantiate the class + template class FIRInterp; + template class FIRInterp; + template class FIRInterp; +} \ No newline at end of file diff --git a/dsp/mrate/fir_interp.h b/dsp/mrate/fir_interp.h new file mode 100644 index 0000000..4dff76c --- /dev/null +++ b/dsp/mrate/fir_interp.h @@ -0,0 +1,83 @@ +#pragma once +#include "../processor.h" +#include "../buffer.h" +#include "../taps.h" +#include + +namespace dsp::mrate { + template + class FIRInterp { + public: + // Default constructor + FIRInterp(); + + /** + * Create a decimating FIR filter. + * @param taps Taps to use for the filter. + * @param interp Interpolation factor. + */ + FIRInterp(const Taps& taps, int interp); + + /** + * Create a decimating FIR filter. + * @param taps Taps to use for the filter. + * @param interp Interpolation factor. + */ + FIRInterp(Taps&& taps, int interp); + + /** + * Get the filter taps. + * @return Filter taps. + */ + const Taps& getTaps() const; + + /** + * Set the filter taps. + * @param taps Filter taps. + * @param interp Interpolation factor. Zero to keep unchanged. + */ + void setTaps(const Taps& taps, int interp = 0); + + /** + * Set the filter taps. + * @param taps Filter taps. + * @param interp Interpolation factor. Zero to keep unchanged. + */ + void setTaps(Taps&& taps, int interp = 0); + + /** + * Get the interpolation factor. + * @return Interpolation factor. + */ + int getInterpolation(); + + /** + * Set the interpolation factor. + * @param interp Interpolation factor. + */ + void setInterpolation(int interp); + + /** + * Reset the state of the filter. + */ + void reset(); + + /** + * Filter and decimate samples. + * @param in Input samples. + * @param out Output samples. + * @param count Number of samples to filter. + * @return Number of samples generates. + */ + size_t process(const SAMPLE* in, SAMPLE* out, size_t count); + + private: + void generatePhases(); + + Buffer hist; + uintptr_t offset = 0; + Taps taps; + std::vector> phases; + int interp = 0; + }; +} \ No newline at end of file