Added a noise blanker for SSB and DSB

pull/567/head
AlexandreRouma 2021-12-10 22:25:22 +01:00
rodzic 241632288e
commit 15010cff01
11 zmienionych plików z 84 dodań i 65 usunięć

Wyświetl plik

@ -267,7 +267,7 @@ namespace dsp {
public:
NoiseBlanker() {}
NoiseBlanker(stream<complex_t>* in, float attack, float decay, float threshold, float level, float sampleRate) { init(in, attack, decay, threshold, level, sampleRate); }
NoiseBlanker(stream<complex_t>* in, float level) { init(in, level); }
~NoiseBlanker() {
if (!generic_block<NoiseBlanker>::_block_init) { return; }
@ -275,16 +275,9 @@ namespace dsp {
volk_free(ampBuf);
}
void init(stream<complex_t>* in, float attack, float decay, float threshold, float level, float sampleRate) {
void init(stream<complex_t>* in, float level) {
_in = in;
_attack = attack;
_decay = decay;
_threshold = powf(10.0f, threshold / 10.0f);
_level = level;
_sampleRate = sampleRate;
_inv_attack = 1.0f - _attack;
_inv_decay = 1.0f - _decay;
_level = powf(10.0f, level / 10.0f);;
ampBuf = (float*)volk_malloc(STREAM_BUFFER_SIZE*sizeof(float), volk_get_alignment());
@ -293,28 +286,8 @@ namespace dsp {
generic_block<NoiseBlanker>::_block_init = true;
}
void setAttack(float attack) {
_attack = attack;
_inv_attack = 1.0f - _attack;
}
void setDecay(float decay) {
_decay = decay;
_inv_decay = 1.0f - _decay;
}
void setThreshold(float threshold) {
_threshold = powf(10.0f, threshold / 10.0f);
spdlog::warn("Threshold {0}", _threshold);
}
void setLevel(float level) {
_level = level;
}
void setSampleRate(float sampleRate) {
_sampleRate = sampleRate;
// TODO: Change parameters if the algo needs it
_level = powf(10.0f, level / 10.0f);
}
void setInput(stream<complex_t>* in) {
@ -334,33 +307,13 @@ namespace dsp {
// Get amplitudes
volk_32fc_magnitude_32f(ampBuf, (lv_32fc_t*)_in->readBuf, count);
// Apply filtering and threshold
float val;
// Hard limit the amplitude
complex_t inVal;
for (int i = 0; i < count; i++) {
// Filter using attack/threshold methode
val = ampBuf[i];
if (val > lastValue) {
lastValue = (_inv_attack*lastValue) + (_attack*val);
}
else {
lastValue = (_inv_decay*lastValue) + (_decay*val);
}
// Apply threshold and invert
if (lastValue > _threshold) {
ampBuf[i] = _threshold / (lastValue * _level);
if (ampBuf[i] == 0) {
spdlog::warn("WTF???");
}
}
else {
ampBuf[i] = 1.0f;
}
inVal = _in->readBuf[i];
out.writeBuf[i] = (ampBuf[i] > _level) ? inVal * (_level / inVal.amplitude()) : inVal;
}
// Multiply
volk_32fc_32f_multiply_32fc((lv_32fc_t*)out.writeBuf, (lv_32fc_t*)_in->readBuf, ampBuf, count);
_in->flush();
if (!out.swap(count)) { return -1; }
return count;
@ -371,15 +324,7 @@ namespace dsp {
private:
float* ampBuf;
float _attack;
float _decay;
float _inv_attack;
float _inv_decay;
float _threshold;
float _level;
float _sampleRate;
float lastValue = 0.0f;
stream<complex_t>* _in;

Wyświetl plik

@ -38,6 +38,7 @@ namespace demod {
virtual int getDefaultDeemphasisMode() = 0;
virtual double getAFBandwidth(double bandwidth) = 0;
virtual bool getFMIFNRAllowed() = 0;
virtual bool getNBAllowed() = 0;
virtual bool getDynamicAFBandwidth() = 0;
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;

Wyświetl plik

@ -68,6 +68,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; }
bool getDynamicAFBandwidth() { return true; }
bool getFMIFNRAllowed() { return false; }
bool getNBAllowed() { return false; }
dsp::stream<dsp::stereo_t>* getOutput() { return &m2s.out; }
private:

Wyświetl plik

@ -69,6 +69,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return (bandwidth / 2.0) + 1000.0; }
bool getDynamicAFBandwidth() { return true; }
bool getFMIFNRAllowed() { return false; }
bool getNBAllowed() { return false; }
dsp::stream<dsp::stereo_t>* getOutput() { return &m2s.out; }
private:

Wyświetl plik

@ -70,6 +70,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; }
bool getDynamicAFBandwidth() { return true; }
bool getFMIFNRAllowed() { return false; }
bool getNBAllowed() { return true; }
dsp::stream<dsp::stereo_t>* getOutput() { return &m2s.out; }
private:

Wyświetl plik

@ -70,6 +70,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return bandwidth; }
bool getDynamicAFBandwidth() { return true; }
bool getFMIFNRAllowed() { return false; }
bool getNBAllowed() { return true; }
dsp::stream<dsp::stereo_t>* getOutput() { return &m2s.out; }
private:

Wyświetl plik

@ -62,6 +62,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return bandwidth / 2.0; }
bool getDynamicAFBandwidth() { return true; }
bool getFMIFNRAllowed() { return true; }
bool getNBAllowed() { return false; }
dsp::stream<dsp::stereo_t>* getOutput() { return &demod.out; }
private:

Wyświetl plik

@ -63,6 +63,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return bandwidth; }
bool getDynamicAFBandwidth() { return false; }
bool getFMIFNRAllowed() { return false; }
bool getNBAllowed() { return true; }
dsp::stream<dsp::stereo_t>* getOutput() { return &c2s.out; }
private:

Wyświetl plik

@ -70,6 +70,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return bandwidth; }
bool getDynamicAFBandwidth() { return true; }
bool getFMIFNRAllowed() { return false; }
bool getNBAllowed() { return true; }
dsp::stream<dsp::stereo_t>* getOutput() { return &m2s.out; }
private:

Wyświetl plik

@ -86,6 +86,7 @@ namespace demod {
double getAFBandwidth(double bandwidth) { return 16000.0; }
bool getDynamicAFBandwidth() { return false; }
bool getFMIFNRAllowed() { return true; }
bool getNBAllowed() { return false; }
dsp::stream<dsp::stereo_t>* getOutput() { return stereo ? demodStereo.out : &demod.out; }
// ============= DEDICATED FUNCTIONS =============

Wyświetl plik

@ -62,10 +62,12 @@ public:
fmnr.block.init(NULL, 32);
notch.block.init(NULL, 0.5, 0, 250000); // TODO: The rate has to depend on IF sample rate so the width is always the same
squelch.block.init(NULL, MIN_SQUELCH);
nb.block.init(NULL, -100.0f);
ifChain.add(&notch);
ifChain.add(&squelch);
ifChain.add(&fmnr);
ifChain.add(&nb);
// Load configuration for and enabled all demodulators
EventHandler<dsp::stream<dsp::stereo_t>*> _demodOutputChangeHandler;
@ -258,6 +260,21 @@ private:
}
if (!_this->squelchEnabled && _this->enabled) { style::endDisabled(); }
// Noise blanker
if (_this->nbAllowed) {
if (ImGui::Checkbox(("Noise Blanker##_radio_nb_ena_" + _this->name).c_str(), &_this->nbEnabled)) {
_this->setNoiseBlankerEnabled(_this->nbEnabled);
}
if (!_this->nbEnabled && _this->enabled) { style::beginDisabled(); }
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::SliderFloat(("##_radio_nb_lvl_" + _this->name).c_str(), &_this->nbLevel, 0.0f, -100.0f, "%.3fdB")) {
_this->setNoiseBlankerLevel(_this->nbLevel);
}
if (!_this->nbEnabled && _this->enabled) { style::endDisabled(); }
}
// // Notch filter
// if (ImGui::Checkbox("Notch##_radio_notch_ena_", &_this->notchEnabled)) {
// _this->ifChain.setState(&_this->notch, _this->notchEnabled);
@ -324,6 +341,10 @@ private:
postProcEnabled = selectedDemod->getPostProcEnabled();
FMIFNRAllowed = selectedDemod->getFMIFNRAllowed();
FMIFNREnabled = false;
nbAllowed = selectedDemod->getNBAllowed();
nbEnabled = false;
nbLevel = 0.0f;
config.acquire();
if (config.conf[name][selectedDemod->getName()].contains("bandwidth")) {
bandwidth = config.conf[name][selectedDemod->getName()]["bandwidth"];
bandwidth = std::clamp<double>(bandwidth, minBandwidth, maxBandwidth);
@ -343,6 +364,16 @@ private:
if (config.conf[name][selectedDemod->getName()].contains("FMIFNREnabled")) {
FMIFNREnabled = config.conf[name][selectedDemod->getName()]["FMIFNREnabled"];
}
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) {
nbEnabled = config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"];
}
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) {
nbEnabled = config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"];
}
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerLevel")) {
nbLevel = config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"];
}
config.release();
deempMode = std::clamp<int>(deempMode, 0, _DEEMP_MODE_COUNT-1);
// Configure VFO
@ -363,6 +394,10 @@ private:
squelch.block.setLevel(squelchLevel);
setSquelchEnabled(squelchEnabled);
// Configure noise blanker
nb.block.setLevel(nbLevel);
setNoiseBlankerEnabled(nbEnabled);
// Configure AF chain
if (postProcEnabled) {
// Configure resampler
@ -483,6 +518,28 @@ private:
config.release(true);
}
void setNoiseBlankerEnabled(bool enabled) {
nbEnabled = enabled;
if (!selectedDemod) { return; }
ifChain.setState(&nb, nbEnabled);
// Save config
config.acquire();
config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"] = nbEnabled;
config.release(true);
}
void setNoiseBlankerLevel(float level) {
nbLevel = level;
if (!selectedDemod) { return; }
nb.block.setLevel(nbLevel);
// Save config
config.acquire();
config.conf[name][selectedDemod->getName()]["noiseBlankerLevel"] = nbLevel;
config.release(true);
}
static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) {
RadioModule* _this = (RadioModule*)ctx;
_this->setBandwidth(newBw);
@ -568,6 +625,7 @@ private:
dsp::ChainLink<dsp::FMIFNoiseReduction, dsp::complex_t> fmnr;
dsp::ChainLink<dsp::NotchFilter, dsp::complex_t> notch;
dsp::ChainLink<dsp::Squelch, dsp::complex_t> squelch;
dsp::ChainLink<dsp::NoiseBlanker, dsp::complex_t> nb;
// Audio chain
dsp::stream<dsp::stereo_t> dummyAudioStream;
@ -587,12 +645,15 @@ private:
float bandwidth;
bool bandwidthLocked;
int snapInterval;
int selectedDemodID = 1;
bool postProcEnabled;
bool squelchEnabled = false;
float squelchLevel;
int selectedDemodID = 1;
int deempMode = DEEMP_MODE_NONE;
bool deempAllowed;
bool postProcEnabled;
bool FMIFNRAllowed;
bool FMIFNREnabled = false;
@ -600,6 +661,10 @@ private:
float notchPos = 0;
float notchWidth = 500;
bool nbAllowed;
bool nbEnabled;
float nbLevel = -100.0f;
const double MIN_SQUELCH = -100.0;
const double MAX_SQUELCH = 0.0;