mirror of
https://github.com/AlexandreRouma/dsp2.git
synced 2026-04-20 07:22:44 +00:00
implement the buffer class and derive the taps class from it
This commit is contained in:
100
dsp/buffer.cpp
100
dsp/buffer.cpp
@@ -1,53 +1,135 @@
|
|||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#include "complex.h"
|
||||||
|
#include <volk/volk.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp {
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>::Buffer() {
|
Buffer<T>::Buffer() {}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Buffer<T>::Buffer(size_t size, bool zero) {
|
||||||
|
// Allocate buffer
|
||||||
|
realloc(size, zero ? REALLOC_ZERO : REALLOC_DISCARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>::Buffer(size_t size, bool zero = false) {
|
Buffer<T>::Buffer(const T* samples, size_t size) {
|
||||||
|
// Allocate buffer
|
||||||
}
|
realloc(size);
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Buffer<T>::Buffer(T* taps, int count) {
|
|
||||||
|
|
||||||
|
// Copy data over
|
||||||
|
memcpy(buffer, samples, size * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>::Buffer(const Buffer<T>& b) {
|
Buffer<T>::Buffer(const Buffer<T>& b) {
|
||||||
|
// Allocate buffer
|
||||||
|
realloc(b.count);
|
||||||
|
|
||||||
|
// Copy data over
|
||||||
|
memcpy(buffer, b.buffer, b.count * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>::Buffer(Buffer<T>&& b) {
|
Buffer<T>::Buffer(Buffer<T>&& b) {
|
||||||
|
// Copy members
|
||||||
|
buffer = b.buffer;
|
||||||
|
capacity = b.capacity;
|
||||||
|
|
||||||
|
// Neutralize old instance
|
||||||
|
b.buffer = NULL;
|
||||||
|
b.capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>::~Buffer() {
|
Buffer<T>::~Buffer() {
|
||||||
|
// Free the buffer
|
||||||
|
free();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>& Buffer<T>::operator=(const Buffer<T>& b) {
|
Buffer<T>& Buffer<T>::operator=(const Buffer<T>& b) {
|
||||||
|
// Reallocate the buffer
|
||||||
|
realloc(b.capacity);
|
||||||
|
|
||||||
|
// Copy over the data
|
||||||
|
memcpy(buffer, b.buffer, capacity * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Buffer<T>& Buffer<T>::operator=(Buffer<T>&& b) {
|
Buffer<T>& Buffer<T>::operator=(Buffer<T>&& 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 <class T>
|
template <class T>
|
||||||
void Buffer<T>::realloc(size_t size, bool zero = false) {
|
void Buffer<T>::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<size_t>(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 <class T>
|
template <class T>
|
||||||
void Buffer<T>::free() {
|
void Buffer<T>::free() {
|
||||||
|
// Free the buffer
|
||||||
|
volk_free(buffer);
|
||||||
|
|
||||||
|
// Mark the buffer as freed
|
||||||
|
buffer = NULL;
|
||||||
|
capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Instantiate the class
|
||||||
|
template class Buffer<uint8_t>;
|
||||||
|
template class Buffer<uint16_t>;
|
||||||
|
template class Buffer<uint32_t>;
|
||||||
|
template class Buffer<uint64_t>;
|
||||||
|
template class Buffer<int8_t>;
|
||||||
|
template class Buffer<int16_t>;
|
||||||
|
template class Buffer<int32_t>;
|
||||||
|
template class Buffer<int64_t>;
|
||||||
|
template class Buffer<float>;
|
||||||
|
template class Buffer<double>;
|
||||||
|
template class Buffer<Complex>;
|
||||||
}
|
}
|
||||||
54
dsp/buffer.h
54
dsp/buffer.h
@@ -2,6 +2,23 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
namespace dsp {
|
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.
|
* Sample buffer aligned for efficient DSP use.
|
||||||
* This class is NOT thread-safe.
|
* This class is NOT thread-safe.
|
||||||
@@ -20,11 +37,11 @@ namespace dsp {
|
|||||||
Buffer(size_t size, bool zero = false);
|
Buffer(size_t size, bool zero = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a buffer from an array.
|
* Create a buffer from an array of samples.
|
||||||
* @param taps Array containing the samples.
|
* @param samples Array containing the samples.
|
||||||
* @param count Number of samples to load.
|
* @param size Number of samples to load.
|
||||||
*/
|
*/
|
||||||
Buffer(T* taps, int count);
|
Buffer(const T* samples, size_t size);
|
||||||
|
|
||||||
// Copy constructor
|
// Copy constructor
|
||||||
Buffer(const Buffer<T>& b);
|
Buffer(const Buffer<T>& b);
|
||||||
@@ -44,23 +61,37 @@ namespace dsp {
|
|||||||
/**
|
/**
|
||||||
* Re-allocate the buffer conserving the existing data.
|
* Re-allocate the buffer conserving the existing data.
|
||||||
* @param size Number of samples.
|
* @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();
|
void free();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of samples in the buffer.
|
* 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.
|
* 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; }
|
inline const T* data() const { return buffer; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +100,13 @@ namespace dsp {
|
|||||||
*/
|
*/
|
||||||
inline operator bool() const { return capacity; }
|
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.
|
* Get a sample by index.
|
||||||
* @param index Index of the tap
|
* @param index Index of the tap
|
||||||
|
|||||||
@@ -7,7 +7,27 @@ namespace dsp {
|
|||||||
* This struct is NOT thread-safe.
|
* This struct is NOT thread-safe.
|
||||||
*/
|
*/
|
||||||
struct Complex {
|
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.
|
* Compute the conjugate of the Complex number.
|
||||||
|
|||||||
95
dsp/taps.cpp
95
dsp/taps.cpp
@@ -1,101 +1,14 @@
|
|||||||
#include "taps.h"
|
#include "taps.h"
|
||||||
#include "complex.h"
|
#include "complex.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp {
|
||||||
template <class T>
|
template <class T>
|
||||||
Taps<T>::Taps() {}
|
Taps<T>::Taps() {}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Taps<T>::Taps(int count, bool zero) {
|
Taps<T>::Taps(const T* taps, size_t count) : Buffer<T>(taps, count) {}
|
||||||
// Allocate buffer
|
|
||||||
reallocate(count);
|
|
||||||
|
|
||||||
// Null out if requested
|
template class Buffer<float>;
|
||||||
if (zero) { memset(buffer, 0, count*sizeof(T)); }
|
template class Buffer<double>;
|
||||||
}
|
template class Buffer<Complex>;
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Taps<T>::Taps(T* taps, int count) {
|
|
||||||
// Allocate buffer
|
|
||||||
reallocate(count);
|
|
||||||
|
|
||||||
// Copy data over
|
|
||||||
memcpy(buffer, taps, count*sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Taps<T>::Taps(const Taps<T>& b) {
|
|
||||||
// Allocate buffer
|
|
||||||
reallocate(b.count);
|
|
||||||
|
|
||||||
// Copy data over
|
|
||||||
memcpy(buffer, b.buffer, b.count*sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Taps<T>::Taps(Taps<T>&& b) {
|
|
||||||
// Copy members
|
|
||||||
buffer = b.buffer;
|
|
||||||
count = b.count;
|
|
||||||
|
|
||||||
// Neutralize old instance
|
|
||||||
b.buffer = NULL;
|
|
||||||
b.count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Taps<T>::~Taps() {
|
|
||||||
// Free the buffer if it is allocated
|
|
||||||
if (buffer) { delete[] buffer; }
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Taps<T>& Taps<T>::operator=(const Taps<T>& b) {
|
|
||||||
// Reallocate buffer
|
|
||||||
reallocate(b.count);
|
|
||||||
|
|
||||||
// Copy data over
|
|
||||||
memcpy(buffer, b.buffer, b.count*sizeof(T));
|
|
||||||
|
|
||||||
// Return self
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
Taps<T>& Taps<T>::operator=(Taps<T>&& 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 <class T>
|
|
||||||
void Taps<T>::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<float>;
|
|
||||||
template class Taps<Complex>;
|
|
||||||
}
|
}
|
||||||
58
dsp/taps.h
58
dsp/taps.h
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stddef.h>
|
#include "buffer.h"
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp {
|
||||||
/**
|
/**
|
||||||
@@ -7,64 +7,24 @@ namespace dsp {
|
|||||||
* This class is NOT thread-safe.
|
* This class is NOT thread-safe.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
class Taps {
|
class Taps : public Buffer<T> {
|
||||||
public:
|
public:
|
||||||
// Default constructor
|
// Default constructor
|
||||||
Taps();
|
Taps();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a tap bank holding count taps.
|
* Create a taps object from an array of taps.
|
||||||
* @param count Number of taps.
|
* @param taps Array containing the 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.
|
|
||||||
* @param count Number of taps to load.
|
* @param count Number of taps to load.
|
||||||
*/
|
*/
|
||||||
Taps(T* taps, int count);
|
Taps(const T* taps, size_t count);
|
||||||
|
|
||||||
// Copy constructor
|
// TODO: Operations to combine, window, etc taps efficiently
|
||||||
Taps(const Taps<T>& b);
|
|
||||||
|
|
||||||
// Move constructor
|
|
||||||
Taps(Taps<T>&& b);
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
virtual ~Taps();
|
|
||||||
|
|
||||||
// Copy assignment operator
|
|
||||||
Taps<T>& operator=(const Taps<T>& b);
|
|
||||||
|
|
||||||
// Move assignment operator
|
|
||||||
Taps<T>& operator=(Taps<T>&& 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]; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void reallocate(int count);
|
using Buffer<T>::realloc;
|
||||||
|
|
||||||
int count = 0;
|
private:
|
||||||
T* buffer = NULL;
|
using Buffer<T>::reserve;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
0
dsp/taps/band_pass.cpp
Normal file
0
dsp/taps/band_pass.cpp
Normal file
0
dsp/taps/band_pass.h
Normal file
0
dsp/taps/band_pass.h
Normal file
0
dsp/taps/high_pass.cpp
Normal file
0
dsp/taps/high_pass.cpp
Normal file
0
dsp/taps/high_pass.h
Normal file
0
dsp/taps/high_pass.h
Normal file
@@ -54,7 +54,7 @@ namespace dsp::taps {
|
|||||||
|
|
||||||
void LowPass::generate() {
|
void LowPass::generate() {
|
||||||
// Reallocate the buffer
|
// Reallocate the buffer
|
||||||
reallocate(0 /*TODO: Tap count estimation*/);
|
realloc(0 /*TODO: Tap count estimation*/);
|
||||||
|
|
||||||
// Generate taps
|
// Generate taps
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
7
dsp/taps/root_raised_cosine.cpp
Normal file
7
dsp/taps/root_raised_cosine.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "root_raised_cosine.h"
|
||||||
|
|
||||||
|
namespace dsp::taps {
|
||||||
|
void RootRaisedCosine::generate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../taps.h"
|
#include "../taps.h"
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp::taps {
|
||||||
class RootRaisedCosine : public Taps<float> {
|
class RootRaisedCosine : public Taps<float> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
private:
|
||||||
|
void generate();
|
||||||
|
|
||||||
|
float beta;
|
||||||
|
float symbolrate;
|
||||||
|
float samplerate;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/main.cpp
12
src/main.cpp
@@ -1,6 +1,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "dsp/buffer.h"
|
||||||
|
#include "dsp/taps.h"
|
||||||
|
#include "dsp/complex.h"
|
||||||
|
#include <volk/volk.h>
|
||||||
|
|
||||||
|
void testFunc(const float* buf, size_t len) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
float* test;
|
||||||
|
dsp::Taps<float> taps;
|
||||||
|
|
||||||
|
testFunc(((const dsp::Taps<float>&)taps).data(), taps.size());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user