mirror of
https://github.com/AlexandreRouma/dsp2.git
synced 2026-04-20 07:22:44 +00:00
linux compile fix
This commit is contained in:
@@ -7,15 +7,15 @@ add_executable(${PROJECT_NAME} ${SRC})
|
|||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE "/")
|
target_include_directories(${PROJECT_NAME} PRIVATE "/")
|
||||||
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /std:c++20)
|
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||||
|
|
||||||
# Set compiler options
|
# Set compiler options
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /EHsc) # /O2 /Ob2
|
target_compile_options(${PROJECT_NAME} PRIVATE /EHsc) # /O2 /Ob2
|
||||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -O3)
|
target_compile_options(${PROJECT_NAME} PRIVATE -O3 -Wno-literal-suffix)
|
||||||
else ()
|
else ()
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -O3)
|
target_compile_options(${PROJECT_NAME} PRIVATE -O3 -Wno-literal-suffix)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
13
dsp/buffer.h
13
dsp/buffer.h
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// TODO: Force inline the data stuff for maximal performance in FIR
|
// TODO: Force inline the data stuff for maximal performance in FIR
|
||||||
|
|
||||||
@@ -103,6 +104,18 @@ namespace dsp {
|
|||||||
*/
|
*/
|
||||||
inline operator bool() const { return _capacity; }
|
inline operator bool() const { return _capacity; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast to sample pointer.
|
||||||
|
* @return Pointer to the samples
|
||||||
|
*/
|
||||||
|
inline operator T*() { return buffer; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast to const sample pointer.
|
||||||
|
* @return Const pointer to the samples
|
||||||
|
*/
|
||||||
|
inline operator const T*() const { return buffer; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access a sample by index.
|
* Access a sample by index.
|
||||||
* @param index Index of the sample.
|
* @param index Index of the sample.
|
||||||
|
|||||||
@@ -8,26 +8,26 @@ namespace dsp {
|
|||||||
*/
|
*/
|
||||||
struct Complex {
|
struct Complex {
|
||||||
// Default constructor
|
// Default constructor
|
||||||
constexpr inline Complex() {}
|
inline Complex() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a complex number from its real and imaginary components.
|
* Create a complex number from its real and imaginary components.
|
||||||
* @param re Real component.
|
* @param re Real component.
|
||||||
* @param im Imaginary component.
|
* @param im Imaginary component.
|
||||||
*/
|
*/
|
||||||
constexpr inline Complex(float re, float im) {
|
constexpr inline Complex(float re, float im) :
|
||||||
this->re = re;
|
re(re),
|
||||||
this->im = im;
|
im(im)
|
||||||
}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a complex number from a real value.
|
* Create a complex number from a real value.
|
||||||
* @param value Real component.
|
* @param value Real component.
|
||||||
*/
|
*/
|
||||||
constexpr inline Complex(float value) {
|
constexpr inline Complex(float value) :
|
||||||
re = value;
|
re(value),
|
||||||
im = 0.0f;
|
im(0.0f)
|
||||||
}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the conjugate of the Complex number.
|
* Compute the conjugate of the Complex number.
|
||||||
@@ -114,6 +114,18 @@ namespace dsp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline constexpr bool operator==(const dsp::Complex& a, const dsp::Complex& b) {
|
||||||
|
return a.re == b.re && a.im == b.im;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool operator==(const dsp::Complex& a, float b) {
|
||||||
|
return a.im == 0.0f && a.re == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr bool operator==(float a, const dsp::Complex& b) {
|
||||||
|
return b.im == 0.0f && b.re == a;
|
||||||
|
}
|
||||||
|
|
||||||
inline constexpr dsp::Complex operator+(const dsp::Complex& a, float b) {
|
inline constexpr dsp::Complex operator+(const dsp::Complex& a, float b) {
|
||||||
return dsp::Complex{ a.re + b, a.im };
|
return dsp::Complex{ a.re + b, a.im };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../processor.h"
|
#include <stddef.h>
|
||||||
#include "../worker.h"
|
|
||||||
#include "../complex.h"
|
#include "../complex.h"
|
||||||
|
|
||||||
namespace dsp::demod {
|
namespace dsp::demod {
|
||||||
class FM : SISOProcessor<Complex, float> {
|
class FM {
|
||||||
public:
|
public:
|
||||||
// Default constructor
|
// Default constructor
|
||||||
FM();
|
FM();
|
||||||
@@ -60,6 +59,4 @@ namespace dsp::demod {
|
|||||||
float gain = 0.0f;
|
float gain = 0.0f;
|
||||||
float lastPhase = 0.0f;
|
float lastPhase = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
using FMw = SISOWorker<FM, Complex, float>;
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "fir.h"
|
#include "fir.h"
|
||||||
#include "../complex.h"
|
#include "../complex.h"
|
||||||
|
#include <string.h>
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
|
|
||||||
namespace dsp::filter {
|
namespace dsp::filter {
|
||||||
@@ -83,6 +84,7 @@ namespace dsp::filter {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Instantiate the class
|
||||||
template class FIR<float, float>;
|
template class FIR<float, float>;
|
||||||
template class FIR<Complex, float>;
|
template class FIR<Complex, float>;
|
||||||
template class FIR<Complex, Complex>;
|
template class FIR<Complex, Complex>;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
namespace dsp::math {
|
namespace dsp::math {
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
#include "decimating_fir.h"
|
|
||||||
#include "../complex.h"
|
|
||||||
#include <volk/volk.h>
|
|
||||||
|
|
||||||
namespace dsp::multirate {
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
DecimatingFIR<SAMPLE, TAP>::DecimatingFIR() {}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
DecimatingFIR<SAMPLE, TAP>::DecimatingFIR(const Taps<TAP>& 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 <class SAMPLE, class TAP>
|
|
||||||
DecimatingFIR<SAMPLE, TAP>::DecimatingFIR(Taps<TAP>&& 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 <class SAMPLE, class TAP>
|
|
||||||
const Taps<TAP>& DecimatingFIR<SAMPLE, TAP>::getTaps() const {
|
|
||||||
// Return the taps
|
|
||||||
return taps;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
void DecimatingFIR<SAMPLE, TAP>::setTaps(const Taps<TAP>& taps, int decim) {
|
|
||||||
// Update the taps
|
|
||||||
this->taps = taps;
|
|
||||||
|
|
||||||
// Update the decimation factor if it was given
|
|
||||||
if (decim) { this->decim = decim; }
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
void DecimatingFIR<SAMPLE, TAP>::setTaps(Taps<TAP>&& taps, int decim) {
|
|
||||||
// Update the taps
|
|
||||||
this->taps = taps;
|
|
||||||
|
|
||||||
// Update the decimation factor if it was given
|
|
||||||
if (decim) { this->decim = decim; }
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
void DecimatingFIR<SAMPLE, TAP>::reset() {
|
|
||||||
// Zero out the history buffer
|
|
||||||
memset(hist.data(), 0, (taps.size() - 1) * sizeof(SAMPLE));
|
|
||||||
|
|
||||||
// Reset the offset
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
size_t DecimatingFIR<SAMPLE, TAP>::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<SAMPLE, float>) {
|
|
||||||
volk_32f_x2_dot_prod_32f(&out[io++], &hist[i], taps.data(), taps.size());
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_same_v<SAMPLE, Complex> && std::is_same_v<TAP, float>) {
|
|
||||||
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<SAMPLE, Complex> && std::is_same_v<TAP, Complex>) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../processor.h"
|
|
||||||
#include "../buffer.h"
|
|
||||||
#include "../taps.h"
|
|
||||||
|
|
||||||
namespace dsp::multirate {
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
class DecimatingFIR {
|
|
||||||
public:
|
|
||||||
// Default constructor
|
|
||||||
DecimatingFIR();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a decimating FIR filter.
|
|
||||||
* @param taps Taps to use for the filter.
|
|
||||||
* @param decim Decimation factor.
|
|
||||||
*/
|
|
||||||
DecimatingFIR(const Taps<TAP>& taps, int decim);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a decimating FIR filter.
|
|
||||||
* @param taps Taps to use for the filter.
|
|
||||||
* @param decim Decimation factor.
|
|
||||||
*/
|
|
||||||
DecimatingFIR(Taps<TAP>&& taps, int decim);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the filter taps.
|
|
||||||
* @return Filter taps.
|
|
||||||
*/
|
|
||||||
const Taps<TAP>& getTaps() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter taps.
|
|
||||||
* @param taps Filter taps.
|
|
||||||
* @param decim Decimation factor. Zero to keep unchanged.
|
|
||||||
*/
|
|
||||||
void setTaps(const Taps<TAP>& taps, int decim = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter taps.
|
|
||||||
* @param taps Filter taps.
|
|
||||||
* @param decim Decimation factor. Zero to keep unchanged.
|
|
||||||
*/
|
|
||||||
void setTaps(Taps<TAP>&& 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<SAMPLE> hist;
|
|
||||||
uintptr_t offset = 0;
|
|
||||||
Taps<TAP> taps;
|
|
||||||
int decim = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
#include "interpolating_fir.h"
|
|
||||||
#include "../complex.h"
|
|
||||||
#include <volk/volk.h>
|
|
||||||
|
|
||||||
namespace dsp::multirate {
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
InterpolatingFIR<SAMPLE, TAP>::InterpolatingFIR() {}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
InterpolatingFIR<SAMPLE, TAP>::InterpolatingFIR(const Taps<TAP>& 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 <class SAMPLE, class TAP>
|
|
||||||
InterpolatingFIR<SAMPLE, TAP>::InterpolatingFIR(Taps<TAP>&& 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 <class SAMPLE, class TAP>
|
|
||||||
const Taps<TAP>& InterpolatingFIR<SAMPLE, TAP>::getTaps() const {
|
|
||||||
// Return the taps
|
|
||||||
return taps;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
void InterpolatingFIR<SAMPLE, TAP>::setTaps(const Taps<TAP>& 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 <class SAMPLE, class TAP>
|
|
||||||
void InterpolatingFIR<SAMPLE, TAP>::setTaps(Taps<TAP>&& 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 <class SAMPLE, class TAP>
|
|
||||||
void InterpolatingFIR<SAMPLE, TAP>::reset() {
|
|
||||||
// Zero out the history buffer
|
|
||||||
memset(hist.data(), 0, (taps.size() - 1) * sizeof(SAMPLE));
|
|
||||||
|
|
||||||
// Reset the offset
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
size_t InterpolatingFIR<SAMPLE, TAP>::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<SAMPLE, float>) {
|
|
||||||
volk_32f_x2_dot_prod_32f(&out[io++], &hist[i], taps.data(), taps.size());
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_same_v<SAMPLE, Complex> && std::is_same_v<TAP, float>) {
|
|
||||||
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<SAMPLE, Complex> && std::is_same_v<TAP, Complex>) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../processor.h"
|
|
||||||
#include "../buffer.h"
|
|
||||||
#include "../taps.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace dsp::multirate {
|
|
||||||
template <class SAMPLE, class TAP>
|
|
||||||
class InterpolatingFIR {
|
|
||||||
public:
|
|
||||||
// Default constructor
|
|
||||||
InterpolatingFIR();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a decimating FIR filter.
|
|
||||||
* @param taps Taps to use for the filter.
|
|
||||||
* @param interp Interpolation factor.
|
|
||||||
*/
|
|
||||||
InterpolatingFIR(const Taps<TAP>& taps, int interp);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a decimating FIR filter.
|
|
||||||
* @param taps Taps to use for the filter.
|
|
||||||
* @param interp Interpolation factor.
|
|
||||||
*/
|
|
||||||
InterpolatingFIR(Taps<TAP>&& taps, int interp);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the filter taps.
|
|
||||||
* @return Filter taps.
|
|
||||||
*/
|
|
||||||
const Taps<TAP>& getTaps() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter taps.
|
|
||||||
* @param taps Filter taps.
|
|
||||||
* @param interp Interpolation factor. Zero to keep unchanged.
|
|
||||||
*/
|
|
||||||
void setTaps(const Taps<TAP>& taps, int interp = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filter taps.
|
|
||||||
* @param taps Filter taps.
|
|
||||||
* @param interp Interpolation factor. Zero to keep unchanged.
|
|
||||||
*/
|
|
||||||
void setTaps(Taps<TAP>&& 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<SAMPLE> hist;
|
|
||||||
uintptr_t offset = 0;
|
|
||||||
Taps<TAP> taps;
|
|
||||||
std::vector<Buffer<TAP>> phases;
|
|
||||||
int interp = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,10 @@ namespace dsp {
|
|||||||
template <class T_IN, class T_OUT>
|
template <class T_IN, class T_OUT>
|
||||||
class SISOProcessor {
|
class SISOProcessor {
|
||||||
public:
|
public:
|
||||||
|
inline SISOProcessor() {}
|
||||||
|
|
||||||
|
inline SISOProcessor(SISOProcessor&& b) {}
|
||||||
|
|
||||||
virtual size_t process(const T_IN* in, T_OUT* out, size_t count) = 0;
|
virtual size_t process(const T_IN* in, T_OUT* out, size_t count) = 0;
|
||||||
|
|
||||||
inline size_t processSafe(const T_IN* in, T_OUT* out, size_t count) {
|
inline size_t processSafe(const T_IN* in, T_OUT* out, size_t count) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "../complex.h"
|
#include "../complex.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// TODO: Thread safety
|
// TODO: Thread safety
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "../complex.h"
|
#include "../complex.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// TODO: Thread safety
|
// TODO: Thread safety
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
namespace dsp::source {
|
namespace dsp::source {
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "taps.h"
|
#include "taps.h"
|
||||||
#include "complex.h"
|
#include "complex.h"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp {
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace dsp {
|
|||||||
* Get the number of taps.
|
* Get the number of taps.
|
||||||
* @return Number of taps.
|
* @return Number of taps.
|
||||||
*/
|
*/
|
||||||
inline size_t size() { return _size; }
|
inline size_t size() const { return _size; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a pointer to the taps.
|
* Get a pointer to the taps.
|
||||||
|
|||||||
74
src/main.cpp
74
src/main.cpp
@@ -1,71 +1,31 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include "dsp/buffer.h"
|
#include <string.h>
|
||||||
#include "dsp/demod/fm.h"
|
|
||||||
#include "dsp/sink/file.h"
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include "../dsp/buffer.h"
|
||||||
#include "dsp/source/wgn.h"
|
#include "../dsp/source/wgn.h"
|
||||||
|
#include "../dsp/demod/fm.h"
|
||||||
|
#include "../dsp/taps/low_pass.h"
|
||||||
|
#include "../dsp/mrate/fir_decim.h"
|
||||||
|
#include "../dsp/sink/file.h"
|
||||||
|
|
||||||
#define BUFFER_SIZE 1250
|
#define BUFFER_SIZE 1250
|
||||||
|
|
||||||
void sendWorker(dsp::Stream<dsp::Complex>* input) {
|
|
||||||
// Generate a buffer of random data
|
|
||||||
dsp::source::WGN<dsp::Complex> wgn(1.0);
|
|
||||||
dsp::Buffer<dsp::Complex> randShit(BUFFER_SIZE);
|
|
||||||
wgn.source(randShit.data(), BUFFER_SIZE);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Get a buffer for sending
|
|
||||||
auto bset = input->reserve(BUFFER_SIZE);
|
|
||||||
|
|
||||||
// Copy over the samples
|
|
||||||
memcpy(bset.buffer[0], randShit.data(), BUFFER_SIZE * sizeof(dsp::Complex));
|
|
||||||
|
|
||||||
// Send the samples
|
|
||||||
if (!input->send(BUFFER_SIZE)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::atomic_uint64_t counter;
|
|
||||||
void receiveWorker(dsp::Stream<float>* output) {
|
|
||||||
while (true) {
|
|
||||||
// Receive a buffer
|
|
||||||
auto bset = output->recv();
|
|
||||||
if (!bset.samples) { break; }
|
|
||||||
|
|
||||||
// Add to the counter
|
|
||||||
counter += bset.samples;
|
|
||||||
|
|
||||||
// Flush the buffer
|
|
||||||
output->flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
try {
|
try {
|
||||||
// Define the DSP
|
dsp::source::WGN<dsp::Complex> wgn(1.0f);
|
||||||
dsp::demod::FMw fmw = dsp::demod::FM(6125, 50e3);
|
dsp::demod::FM fmd(6125, 240e3);
|
||||||
|
dsp::mrate::FIRDecim<float, float> decim(dsp::taps::LowPass(20e3, 4e3, 240e3), 5);
|
||||||
|
dsp::sink::File<float> file("output.f32");
|
||||||
|
|
||||||
// Start the send worker
|
dsp::Buffer<dsp::Complex> cbuf(BUFFER_SIZE);
|
||||||
std::thread sendThread(sendWorker, fmw.in());
|
dsp::Buffer<float> rbuf(BUFFER_SIZE);
|
||||||
std::thread receiveThread(receiveWorker, fmw.out());
|
|
||||||
|
|
||||||
// Start the FM demod
|
wgn.source(cbuf, BUFFER_SIZE);
|
||||||
fmw.start();
|
fmd.process(cbuf, rbuf, BUFFER_SIZE);
|
||||||
|
size_t ocount = decim.process(rbuf, rbuf, BUFFER_SIZE);
|
||||||
// Start receiving
|
file.sink(rbuf, ocount);
|
||||||
while (true) {
|
|
||||||
// Get the number of samples processed
|
|
||||||
size_t proc = counter.exchange(0);
|
|
||||||
|
|
||||||
// Print
|
|
||||||
printf("%lf MS/s\n", (double)proc / 1e6);
|
|
||||||
|
|
||||||
// Wait
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user