kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
489 wiersze
14 KiB
C++
489 wiersze
14 KiB
C++
#pragma once
|
|
#include <thread>
|
|
#include <dsp/stream.h>
|
|
#include <dsp/types.h>
|
|
#include <vector>
|
|
#include <dsp/math.h>
|
|
#include <spdlog/spdlog.h>
|
|
|
|
#define GET_FROM_RIGHT_BUF(buffer, delayLine, delayLineSz, n) (((n) < 0) ? delayLine[(delayLineSz) + (n)] : buffer[(n)])
|
|
|
|
namespace dsp {
|
|
inline void BlackmanWindow(std::vector<float>& taps, float sampleRate, float cutoff, float transWidth, int addedTaps = 0) {
|
|
taps.clear();
|
|
|
|
float fc = cutoff / sampleRate;
|
|
if (fc > 1.0f) {
|
|
fc = 1.0f;
|
|
}
|
|
|
|
int _M = (4.0f / (transWidth / sampleRate)) + (float)addedTaps;
|
|
if (_M < 4) {
|
|
_M = 4;
|
|
}
|
|
|
|
if (_M % 2 == 0) { _M++; }
|
|
float M = _M;
|
|
float sum = 0.0f;
|
|
float val;
|
|
for (int i = 0; i < _M; i++) {
|
|
val = (sin(2.0f * M_PI * fc * ((float)i - (M / 2))) / ((float)i - (M / 2))) * (0.42f - (0.5f * cos(2.0f * M_PI / M)) + (0.8f * cos(4.0f * M_PI / M)));
|
|
taps.push_back(val);
|
|
sum += val;
|
|
}
|
|
for (int i = 0; i < M; i++) {
|
|
taps[i] /= sum;
|
|
}
|
|
}
|
|
|
|
class DecimatingFIRFilter {
|
|
public:
|
|
DecimatingFIRFilter() {
|
|
|
|
}
|
|
|
|
DecimatingFIRFilter(stream<complex_t>* input, std::vector<float> taps, int blockSize, float decim) {
|
|
output.init((blockSize * 2) / decim);
|
|
_in = input;
|
|
_blockSize = blockSize;
|
|
_tapCount = taps.size();
|
|
delayBuf = new complex_t[_tapCount];
|
|
|
|
_taps = new float[_tapCount];
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
_taps[i] = taps[i];
|
|
}
|
|
|
|
_decim = decim;
|
|
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
delayBuf[i].i = 0.0f;
|
|
delayBuf[i].q = 0.0f;
|
|
}
|
|
|
|
running = false;
|
|
}
|
|
|
|
void init(stream<complex_t>* input, std::vector<float>& taps, int blockSize, float decim) {
|
|
output.init((blockSize * 2) / decim);
|
|
_in = input;
|
|
_blockSize = blockSize;
|
|
_tapCount = taps.size();
|
|
delayBuf = new complex_t[_tapCount];
|
|
|
|
_taps = new float[_tapCount];
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
_taps[i] = taps[i];
|
|
}
|
|
|
|
_decim = decim;
|
|
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
delayBuf[i].i = 0.0f;
|
|
delayBuf[i].q = 0.0f;
|
|
}
|
|
|
|
running = false;
|
|
}
|
|
|
|
void start() {
|
|
if (running) {
|
|
return;
|
|
}
|
|
running = true;
|
|
_workerThread = std::thread(_worker, this);
|
|
}
|
|
|
|
void stop() {
|
|
if (!running) {
|
|
return;
|
|
}
|
|
_in->stopReader();
|
|
output.stopWriter();
|
|
_workerThread.join();
|
|
_in->clearReadStop();
|
|
output.clearWriteStop();
|
|
running = false;
|
|
}
|
|
|
|
void setTaps(std::vector<float>& taps) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_tapCount = taps.size();
|
|
delete[] _taps;
|
|
delete[] delayBuf;
|
|
_taps = new float[_tapCount];
|
|
delayBuf = new complex_t[_tapCount];
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
_taps[i] = taps[i];
|
|
delayBuf[i].i = 0;
|
|
delayBuf[i].q = 0;
|
|
}
|
|
}
|
|
|
|
void setInput(stream<complex_t>* input) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_in = input;
|
|
}
|
|
|
|
void setDecimation(float decimation) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_decim = decimation;
|
|
output.setMaxLatency((_blockSize * 2) / _decim);
|
|
}
|
|
|
|
void setBlockSize(int blockSize) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_blockSize = blockSize;
|
|
output.setMaxLatency(getOutputBlockSize() * 2);
|
|
}
|
|
|
|
int getOutputBlockSize() {
|
|
return _blockSize / _decim;
|
|
}
|
|
|
|
stream<complex_t> output;
|
|
|
|
private:
|
|
static void _worker(DecimatingFIRFilter* _this) {
|
|
int outputSize = _this->_blockSize / _this->_decim;
|
|
complex_t* inBuf = new complex_t[_this->_blockSize];
|
|
complex_t* outBuf = new complex_t[outputSize];
|
|
float tap = 0.0f;
|
|
int delayOff;
|
|
void* delayStart = &inBuf[_this->_blockSize - (_this->_tapCount - 1)];
|
|
int delaySize = (_this->_tapCount - 1) * sizeof(complex_t);
|
|
|
|
int blockSize = _this->_blockSize;
|
|
int outBufferLength = outputSize * sizeof(complex_t);
|
|
int tapCount = _this->_tapCount;
|
|
int decim = _this->_decim;
|
|
complex_t* delayBuf = _this->delayBuf;
|
|
int id = 0;
|
|
|
|
while (true) {
|
|
if (_this->_in->read(inBuf, blockSize) < 0) { break; };
|
|
memset(outBuf, 0, outBufferLength);
|
|
|
|
for (int t = 0; t < tapCount; t++) {
|
|
tap = _this->_taps[t];
|
|
if (tap == 0.0f) {
|
|
continue;
|
|
}
|
|
|
|
delayOff = tapCount - t;
|
|
id = 0;
|
|
|
|
for (int i = 0; i < blockSize; i += decim) {
|
|
if (i < t) {
|
|
outBuf[id].i += tap * delayBuf[delayOff + i].i;
|
|
outBuf[id].q += tap * delayBuf[delayOff + i].q;
|
|
}
|
|
else {
|
|
outBuf[id].i += tap * inBuf[i - t].i;
|
|
outBuf[id].q += tap * inBuf[i - t].q;
|
|
}
|
|
id++;
|
|
}
|
|
}
|
|
memcpy(delayBuf, delayStart, delaySize);
|
|
if (_this->output.write(outBuf, outputSize) < 0) { break; };
|
|
}
|
|
delete[] inBuf;
|
|
delete[] outBuf;
|
|
}
|
|
|
|
stream<complex_t>* _in;
|
|
complex_t* delayBuf;
|
|
int _blockSize;
|
|
int _tapCount = 0;
|
|
float _decim;
|
|
std::thread _workerThread;
|
|
float* _taps;
|
|
bool running;
|
|
};
|
|
|
|
|
|
class FloatDecimatingFIRFilter {
|
|
public:
|
|
FloatDecimatingFIRFilter() {
|
|
|
|
}
|
|
|
|
FloatDecimatingFIRFilter(stream<float>* input, std::vector<float> taps, int blockSize, float decim) {
|
|
output.init((blockSize * 2) / decim);
|
|
_in = input;
|
|
_blockSize = blockSize;
|
|
_tapCount = taps.size();
|
|
delayBuf = new float[_tapCount];
|
|
|
|
_taps = new float[_tapCount];
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
_taps[i] = taps[i];
|
|
}
|
|
|
|
_decim = decim;
|
|
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
delayBuf[i] = 0.0f;
|
|
}
|
|
|
|
running = false;
|
|
}
|
|
|
|
void init(stream<float>* input, std::vector<float>& taps, int blockSize, float decim) {
|
|
output.init((blockSize * 2) / decim);
|
|
_in = input;
|
|
_blockSize = blockSize;
|
|
_tapCount = taps.size();
|
|
delayBuf = new float[_tapCount];
|
|
|
|
_taps = new float[_tapCount];
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
_taps[i] = taps[i];
|
|
}
|
|
|
|
_decim = decim;
|
|
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
delayBuf[i] = 0.0f;
|
|
}
|
|
|
|
running = false;
|
|
}
|
|
|
|
void start() {
|
|
if (running) {
|
|
return;
|
|
}
|
|
running = true;
|
|
_workerThread = std::thread(_worker, this);
|
|
}
|
|
|
|
void stop() {
|
|
if (!running) {
|
|
return;
|
|
}
|
|
_in->stopReader();
|
|
output.stopWriter();
|
|
_workerThread.join();
|
|
_in->clearReadStop();
|
|
output.clearWriteStop();
|
|
running = false;
|
|
}
|
|
|
|
void setTaps(std::vector<float>& taps) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_tapCount = taps.size();
|
|
delete[] _taps;
|
|
delete[] delayBuf;
|
|
_taps = new float[_tapCount];
|
|
delayBuf = new float[_tapCount];
|
|
for (int i = 0; i < _tapCount; i++) {
|
|
_taps[i] = taps[i];
|
|
delayBuf[i] = 0;
|
|
}
|
|
}
|
|
|
|
void setInput(stream<float>* input) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_in = input;
|
|
}
|
|
|
|
void setDecimation(float decimation) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_decim = decimation;
|
|
output.setMaxLatency((_blockSize * 2) / _decim);
|
|
}
|
|
|
|
void setBlockSize(int blockSize) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_blockSize = blockSize;
|
|
output.setMaxLatency((_blockSize * 2) / _decim);
|
|
}
|
|
|
|
int getOutputBlockSize() {
|
|
return _blockSize / _decim;
|
|
}
|
|
|
|
stream<float> output;
|
|
|
|
private:
|
|
static void _worker(FloatDecimatingFIRFilter* _this) {
|
|
int outputSize = _this->_blockSize / _this->_decim;
|
|
float* inBuf = new float[_this->_blockSize];
|
|
float* outBuf = new float[outputSize];
|
|
float tap = 0.0f;
|
|
int delayOff;
|
|
void* delayStart = &inBuf[_this->_blockSize - (_this->_tapCount - 1)];
|
|
int delaySize = (_this->_tapCount - 1) * sizeof(float);
|
|
|
|
int blockSize = _this->_blockSize;
|
|
int outBufferLength = outputSize * sizeof(float);
|
|
int tapCount = _this->_tapCount;
|
|
int decim = _this->_decim;
|
|
float* delayBuf = _this->delayBuf;
|
|
int id = 0;
|
|
|
|
while (true) {
|
|
if (_this->_in->read(inBuf, blockSize) < 0) { break; };
|
|
memset(outBuf, 0, outBufferLength);
|
|
|
|
for (int t = 0; t < tapCount; t++) {
|
|
tap = _this->_taps[t];
|
|
if (tap == 0.0f) {
|
|
continue;
|
|
}
|
|
|
|
delayOff = tapCount - t;
|
|
id = 0;
|
|
|
|
for (int i = 0; i < blockSize; i += decim) {
|
|
if (i < t) {
|
|
outBuf[id] += tap * delayBuf[delayOff + i];
|
|
id++;
|
|
continue;
|
|
}
|
|
outBuf[id] += tap * inBuf[i - t];
|
|
id++;
|
|
}
|
|
}
|
|
memcpy(delayBuf, delayStart, delaySize);
|
|
if (_this->output.write(outBuf, outputSize) < 0) { break; };
|
|
}
|
|
delete[] inBuf;
|
|
delete[] outBuf;
|
|
}
|
|
|
|
stream<float>* _in;
|
|
float* delayBuf;
|
|
int _blockSize;
|
|
int _tapCount = 0;
|
|
float _decim;
|
|
std::thread _workerThread;
|
|
float* _taps;
|
|
bool running;
|
|
};
|
|
|
|
class FMDeemphasis {
|
|
public:
|
|
FMDeemphasis() {
|
|
|
|
}
|
|
|
|
FMDeemphasis(stream<float>* input, int bufferSize, float tau, float sampleRate) : output(bufferSize * 2) {
|
|
_in = input;
|
|
_bufferSize = bufferSize;
|
|
bypass = false;
|
|
_tau = tau;
|
|
_sampleRate = sampleRate;
|
|
}
|
|
|
|
void init(stream<float>* input, int bufferSize, float tau, float sampleRate) {
|
|
output.init(bufferSize * 2);
|
|
_in = input;
|
|
_bufferSize = bufferSize;
|
|
bypass = false;
|
|
_tau = tau;
|
|
_sampleRate = sampleRate;
|
|
}
|
|
|
|
void start() {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_workerThread = std::thread(_worker, this);
|
|
running = true;
|
|
}
|
|
|
|
void stop() {
|
|
if (!running) {
|
|
return;
|
|
}
|
|
_in->stopReader();
|
|
output.stopWriter();
|
|
_workerThread.join();
|
|
_in->clearReadStop();
|
|
output.clearWriteStop();
|
|
running = false;
|
|
}
|
|
|
|
void setBlockSize(int blockSize) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_bufferSize = blockSize;
|
|
output.setMaxLatency(blockSize * 2);
|
|
}
|
|
|
|
void setSamplerate(float sampleRate) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_sampleRate = sampleRate;
|
|
}
|
|
|
|
void setTau(float tau) {
|
|
if (running) {
|
|
return;
|
|
}
|
|
_tau = tau;
|
|
}
|
|
|
|
stream<float> output;
|
|
bool bypass;
|
|
|
|
private:
|
|
static void _worker(FMDeemphasis* _this) {
|
|
float* inBuf = new float[_this->_bufferSize];
|
|
float* outBuf = new float[_this->_bufferSize];
|
|
int count = _this->_bufferSize;
|
|
float lastOut = 0.0f;
|
|
float dt = 1.0f / _this->_sampleRate;
|
|
float alpha = dt / (_this->_tau + dt);
|
|
|
|
while (true) {
|
|
if (_this->_in->read(inBuf, count) < 0) { break; };
|
|
if (_this->bypass) {
|
|
if (_this->output.write(inBuf, count) < 0) { break; };
|
|
continue;
|
|
}
|
|
|
|
if (isnan(lastOut)) {
|
|
lastOut = 0.0f;
|
|
}
|
|
outBuf[0] = (alpha * inBuf[0]) + ((1-alpha) * lastOut);
|
|
for (int i = 1; i < count; i++) {
|
|
outBuf[i] = (alpha * inBuf[i]) + ((1 - alpha) * outBuf[i - 1]);
|
|
}
|
|
lastOut = outBuf[count - 1];
|
|
|
|
if (_this->output.write(outBuf, count) < 0) { break; };
|
|
}
|
|
delete[] inBuf;
|
|
delete[] outBuf;
|
|
}
|
|
|
|
stream<float>* _in;
|
|
int _bufferSize;
|
|
std::thread _workerThread;
|
|
bool running = false;
|
|
float _sampleRate;
|
|
float _tau;
|
|
};
|
|
}; |