From b9280ddae1a925f7ffe639044a71e3cb215e42fe Mon Sep 17 00:00:00 2001 From: AlexandreRouma Date: Fri, 5 Sep 2025 23:12:07 -0400 Subject: [PATCH] implement the buffer class and derive the taps class from it --- dsp/buffer.cpp | 100 +++++++++++++++++++++++++++++--- dsp/buffer.h | 54 ++++++++++++++--- dsp/complex.h | 22 ++++++- dsp/taps.cpp | 95 ++---------------------------- dsp/taps.h | 58 +++--------------- dsp/taps/band_pass.cpp | 0 dsp/taps/band_pass.h | 0 dsp/taps/high_pass.cpp | 0 dsp/taps/high_pass.h | 0 dsp/taps/low_pass.cpp | 2 +- dsp/taps/root_raised_cosine.cpp | 7 +++ dsp/taps/root_raised_cosine.h | 8 ++- src/main.cpp | 12 ++++ 13 files changed, 198 insertions(+), 160 deletions(-) create mode 100644 dsp/taps/band_pass.cpp create mode 100644 dsp/taps/band_pass.h create mode 100644 dsp/taps/high_pass.cpp create mode 100644 dsp/taps/high_pass.h create mode 100644 dsp/taps/root_raised_cosine.cpp diff --git a/dsp/buffer.cpp b/dsp/buffer.cpp index fe8b6f7..3b846c0 100644 --- a/dsp/buffer.cpp +++ b/dsp/buffer.cpp @@ -1,53 +1,135 @@ #include "buffer.h" +#include "complex.h" +#include +#include namespace dsp { template - Buffer::Buffer() { + Buffer::Buffer() {} + template + Buffer::Buffer(size_t size, bool zero) { + // Allocate buffer + realloc(size, zero ? REALLOC_ZERO : REALLOC_DISCARD); } template - Buffer::Buffer(size_t size, bool zero = false) { - - } - - template - Buffer::Buffer(T* taps, int count) { + Buffer::Buffer(const T* samples, size_t size) { + // Allocate buffer + realloc(size); + // Copy data over + memcpy(buffer, samples, size * sizeof(T)); } template Buffer::Buffer(const Buffer& b) { + // Allocate buffer + realloc(b.count); + // Copy data over + memcpy(buffer, b.buffer, b.count * sizeof(T)); } template Buffer::Buffer(Buffer&& b) { + // Copy members + buffer = b.buffer; + capacity = b.capacity; + // Neutralize old instance + b.buffer = NULL; + b.capacity = 0; } template Buffer::~Buffer() { - + // Free the buffer + free(); } template Buffer& Buffer::operator=(const Buffer& b) { + // Reallocate the buffer + realloc(b.capacity); + // Copy over the data + memcpy(buffer, b.buffer, capacity * sizeof(T)); } template Buffer& Buffer::operator=(Buffer&& b) { + // Free the current buffer + free(); + // Copy the state of the original + buffer = b.buffer; + capacity = b.capacity; + + // Neutralize the original + b.buffer = NULL; + b.capacity = 0; } template - void Buffer::realloc(size_t size, bool zero = false) { + void Buffer::realloc(size_t size, ReallocBehavior behavior) { + // Select the desired behavior + switch (behavior) { + case REALLOC_DISCARD: + // Free the current buffer + volk_free(buffer); + // Allocate a new buffer + buffer = volk_malloc(size * sizeof(T)); + break; + case REALLOC_KEEP: + // Allocate a new buffer + T* newbuf = volk_malloc(size * sizeof(T)); + + // Copy the existing data + memcpy(newbuf, buffer, std::min(capacity, size)); + + // Replace buffer + buffer = newbuf; + break; + case REALLOC_ZERO: + // Free the current buffer + volk_free(buffer); + + // Allocate a new buffer + buffer = volk_malloc(size * sizeof(T)); + + // Zero-out the new buffer + memset(buffer, 0, size); + break; + case REALLOC_KEEP_AND_ZERO: + + } + + // Update the current capacity + capacity = size; } template void Buffer::free() { + // Free the buffer + volk_free(buffer); + // Mark the buffer as freed + buffer = NULL; + capacity = 0; } + + // Instantiate the class + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; + template class Buffer; } \ No newline at end of file diff --git a/dsp/buffer.h b/dsp/buffer.h index 708626b..e113bc9 100644 --- a/dsp/buffer.h +++ b/dsp/buffer.h @@ -2,6 +2,23 @@ #include namespace dsp { + /** + * Re-allocation behavior of buffers. + */ + enum ReallocBehavior { + // Discard the exiting content of the buffer. + REALLOC_DISCARD = 0, + + // Keep the existing content of the buffer. + REALLOC_KEEP = (1 << 0), + + // Zero out the buffer after reallocation. + REALLOC_ZERO = (1 << 1), + + // Keep the existing content and zero out the excess new samples. + REALLOC_KEEP_AND_ZERO = (REALLOC_KEEP | REALLOC_ZERO) + }; + /** * Sample buffer aligned for efficient DSP use. * This class is NOT thread-safe. @@ -20,11 +37,11 @@ namespace dsp { Buffer(size_t size, bool zero = false); /** - * Create a buffer from an array. - * @param taps Array containing the samples. - * @param count Number of samples to load. + * Create a buffer from an array of samples. + * @param samples Array containing the samples. + * @param size Number of samples to load. */ - Buffer(T* taps, int count); + Buffer(const T* samples, size_t size); // Copy constructor Buffer(const Buffer& b); @@ -44,23 +61,37 @@ namespace dsp { /** * Re-allocate the buffer conserving the existing data. * @param size Number of samples. - * @param zero Zero out additional samples. + * @param behavior Specify the reallocaition behavior to either discard exiting samples, keep existing samples or zero out the buffer. */ - void realloc(size_t size, bool zero = false); + void realloc(size_t size, ReallocBehavior behavior = REALLOC_DISCARD); /** - * Free the buffer. + * Ensure the buffer is big enough to contain a certain number of samples without being too big. Only reallocates when necessary. + * @param size Number of samples that the buffer must be able to hold. + * @param behavior Specify the reallocaition behavior to either discard exiting samples, keep existing samples or zero out the buffer. + */ + inline void reserve(size_t size, ReallocBehavior behavior = REALLOC_DISCARD) { + if (size > capacity || size < (capacity >> 1)) { realloc(size, behavior); } + } + + /** + * Free the buffer. The buffer can still be reallocated afterwards if desired. */ void free(); /** * Get the number of samples in the buffer. */ - inline int size() const { return capacity; } + inline size_t size() const { return capacity; } /** * Get a pointer to the samples. */ + inline T* data() { return buffer; } + + /** + * Get a const pointer to the samples. + */ inline const T* data() const { return buffer; } /** @@ -69,6 +100,13 @@ namespace dsp { */ inline operator bool() const { return capacity; } + /** + * Access a sample by index. + * @param index Index of the tap + * @return Tap at index. + */ + inline T& operator[](int index) { return buffer[index]; } + /** * Get a sample by index. * @param index Index of the tap diff --git a/dsp/complex.h b/dsp/complex.h index fc92d85..f78c9b3 100644 --- a/dsp/complex.h +++ b/dsp/complex.h @@ -7,7 +7,27 @@ namespace dsp { * This struct is NOT thread-safe. */ struct Complex { - // TODO: Allow construction from a float + // Default constructor + constexpr inline Complex() {} + + /** + * Create a complex number from its real and imaginary components. + * @param re Real component. + * @param im Imaginary component. + */ + constexpr inline Complex(float re, float im) { + this->re = re; + this->im = im; + } + + /** + * Create a complex number from a real value. + * @param value Real component. + */ + constexpr inline Complex(float value) { + re = value; + im = 0.0f; + } /** * Compute the conjugate of the Complex number. diff --git a/dsp/taps.cpp b/dsp/taps.cpp index 82bfdfb..c2c7c46 100644 --- a/dsp/taps.cpp +++ b/dsp/taps.cpp @@ -1,101 +1,14 @@ #include "taps.h" #include "complex.h" -#include namespace dsp { template Taps::Taps() {} template - Taps::Taps(int count, bool zero) { - // Allocate buffer - reallocate(count); + Taps::Taps(const T* taps, size_t count) : Buffer(taps, count) {} - // Null out if requested - if (zero) { memset(buffer, 0, count*sizeof(T)); } - } - - template - Taps::Taps(T* taps, int count) { - // Allocate buffer - reallocate(count); - - // Copy data over - memcpy(buffer, taps, count*sizeof(T)); - } - - template - Taps::Taps(const Taps& b) { - // Allocate buffer - reallocate(b.count); - - // Copy data over - memcpy(buffer, b.buffer, b.count*sizeof(T)); - } - - template - Taps::Taps(Taps&& b) { - // Copy members - buffer = b.buffer; - count = b.count; - - // Neutralize old instance - b.buffer = NULL; - b.count = 0; - } - - template - Taps::~Taps() { - // Free the buffer if it is allocated - if (buffer) { delete[] buffer; } - } - - template - Taps& Taps::operator=(const Taps& b) { - // Reallocate buffer - reallocate(b.count); - - // Copy data over - memcpy(buffer, b.buffer, b.count*sizeof(T)); - - // Return self - return *this; - } - - template - Taps& Taps::operator=(Taps&& b) { - // Destroy current instance - if (buffer) { delete[] buffer; } - - // Copy members - buffer = b.buffer; - count = b.count; - - // Neutralize old instance - b.buffer = NULL; - b.count = 0; - - // Return self - return *this; - } - - template - void Taps::reallocate(int count) { - // If the new count is no different and the buffer is allocated, no need to realloc - if (buffer && this->count == count) { return; } - - // Free buffer - if (buffer) { delete[] buffer; } - - // Allocate buffer - // TODO: Use volk instead - buffer = new T[count, sizeof(T)]; - - // Update tap count - this->count = count; - } - - // Instantiate the class - template class Taps; - template class Taps; + template class Buffer; + template class Buffer; + template class Buffer; } \ No newline at end of file diff --git a/dsp/taps.h b/dsp/taps.h index 736ca5d..3908791 100644 --- a/dsp/taps.h +++ b/dsp/taps.h @@ -1,5 +1,5 @@ #pragma once -#include +#include "buffer.h" namespace dsp { /** @@ -7,64 +7,24 @@ namespace dsp { * This class is NOT thread-safe. */ template - class Taps { + class Taps : public Buffer { public: // Default constructor Taps(); - - /** - * Create a tap bank holding count taps. - * @param count Number of taps. - * @param zero Zero out the taps. - */ - Taps(int count, bool zero = false); /** - * Create a tap bank from an array. - * @param taps Array contianing taps. + * Create a taps object from an array of taps. + * @param taps Array containing the taps. * @param count Number of taps to load. */ - Taps(T* taps, int count); + Taps(const T* taps, size_t count); - // Copy constructor - Taps(const Taps& b); - - // Move constructor - Taps(Taps&& b); - - // Destructor - virtual ~Taps(); - - // Copy assignment operator - Taps& operator=(const Taps& b); - - // Move assignment operator - Taps& operator=(Taps&& b); - - /** - * Get the number of taps in the filter. - */ - inline int size() const { return count; } - - /** - * Get a pointer to the tap buffer. - */ - inline const T* data() const { return buffer; } - - // Cast to bool operator - inline operator bool() const { return count; } - - /** - * Get a tap by index. - * @param index Index of the tap - * @return Tap at index. - */ - inline const T& operator[](int index) const { return buffer[index]; } + // TODO: Operations to combine, window, etc taps efficiently protected: - void reallocate(int count); + using Buffer::realloc; - int count = 0; - T* buffer = NULL; + private: + using Buffer::reserve; }; } \ No newline at end of file diff --git a/dsp/taps/band_pass.cpp b/dsp/taps/band_pass.cpp new file mode 100644 index 0000000..e69de29 diff --git a/dsp/taps/band_pass.h b/dsp/taps/band_pass.h new file mode 100644 index 0000000..e69de29 diff --git a/dsp/taps/high_pass.cpp b/dsp/taps/high_pass.cpp new file mode 100644 index 0000000..e69de29 diff --git a/dsp/taps/high_pass.h b/dsp/taps/high_pass.h new file mode 100644 index 0000000..e69de29 diff --git a/dsp/taps/low_pass.cpp b/dsp/taps/low_pass.cpp index 60bb311..be6cb8c 100644 --- a/dsp/taps/low_pass.cpp +++ b/dsp/taps/low_pass.cpp @@ -54,7 +54,7 @@ namespace dsp::taps { void LowPass::generate() { // Reallocate the buffer - reallocate(0 /*TODO: Tap count estimation*/); + realloc(0 /*TODO: Tap count estimation*/); // Generate taps // TODO diff --git a/dsp/taps/root_raised_cosine.cpp b/dsp/taps/root_raised_cosine.cpp new file mode 100644 index 0000000..e402d7c --- /dev/null +++ b/dsp/taps/root_raised_cosine.cpp @@ -0,0 +1,7 @@ +#include "root_raised_cosine.h" + +namespace dsp::taps { + void RootRaisedCosine::generate() { + + } +} \ No newline at end of file diff --git a/dsp/taps/root_raised_cosine.h b/dsp/taps/root_raised_cosine.h index 018fe1a..5279636 100644 --- a/dsp/taps/root_raised_cosine.h +++ b/dsp/taps/root_raised_cosine.h @@ -1,9 +1,15 @@ #pragma once #include "../taps.h" -namespace dsp { +namespace dsp::taps { class RootRaisedCosine : public Taps { public: + private: + void generate(); + + float beta; + float symbolrate; + float samplerate; }; } diff --git a/src/main.cpp b/src/main.cpp index 734dde6..9a63aba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,18 @@ #include +#include "dsp/buffer.h" +#include "dsp/taps.h" +#include "dsp/complex.h" +#include + +void testFunc(const float* buf, size_t len) { + +}; int main() { + float* test; + dsp::Taps taps; + + testFunc(((const dsp::Taps&)taps).data(), taps.size()); return 0; } \ No newline at end of file