1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-07-22 18:55:45 -04:00

UDPSrc plugin: full squelch implementation

This commit is contained in:
f4exb 2017-08-18 00:10:15 +02:00
parent c6b58431fe
commit 32510091df
3 changed files with 117 additions and 29 deletions

View File

@ -15,14 +15,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "udpsrc.h"
#include <dsp/downchannelizer.h>
#include <QUdpSocket> #include <QUdpSocket>
#include <QHostAddress> #include <QHostAddress>
#include "dsp/downchannelizer.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "util/db.h"
#include "udpsrcgui.h" #include "udpsrcgui.h"
#include "udpsrc.h"
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcConfigure, Message) MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcConfigure, Message)
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcConfigureImmediate, Message) MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcConfigureImmediate, Message)
@ -38,6 +39,12 @@ UDPSrc::UDPSrc(MessageQueue* uiMessageQueue, UDPSrcGUI* udpSrcGUI, BasebandSampl
m_outMovingAverage(480, 1e-10), m_outMovingAverage(480, 1e-10),
m_inMovingAverage(480, 1e-10), m_inMovingAverage(480, 1e-10),
m_audioFifo(4, 24000), m_audioFifo(4, 24000),
m_squelch(1e-6),
m_squelchEnabled(true),
m_squelchOpen(false),
m_squelchOpenCount(0),
m_squelchCloseCount(0),
m_squelchThreshold(4800),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
{ {
setObjectName("UDPSrc"); setObjectName("UDPSrc");
@ -144,7 +151,7 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
{ {
Complex ci; Complex ci;
fftfilt::cmplx* sideband; fftfilt::cmplx* sideband;
Real l, r; double l, r;
m_sampleBuffer.clear(); m_sampleBuffer.clear();
m_settingsMutex.lock(); m_settingsMutex.lock();
@ -157,17 +164,18 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
if(m_interpolator.decimate(&m_sampleDistanceRemain, c, &ci)) if(m_interpolator.decimate(&m_sampleDistanceRemain, c, &ci))
{ {
double inMagSq = ci.real()*ci.real() + ci.imag()*ci.imag(); double inMagSq = ci.real()*ci.real() + ci.imag()*ci.imag();
//m_magsq = (inMagSq*m_gain*m_gain) / (1<<30);
m_outMovingAverage.feed((inMagSq*m_gain*m_gain) / (1<<30));
m_inMovingAverage.feed(inMagSq / (1<<30)); m_inMovingAverage.feed(inMagSq / (1<<30));
m_magsq = m_outMovingAverage.average();
m_inMagsq = m_inMovingAverage.average(); m_inMagsq = m_inMovingAverage.average();
Sample s(ci.real() * m_gain, ci.imag() * m_gain); Sample ss(ci.real(), ci.imag());
m_sampleBuffer.push_back(s); m_sampleBuffer.push_back(ss);
m_sampleDistanceRemain += m_inputSampleRate / m_outputSampleRate; m_sampleDistanceRemain += m_inputSampleRate / m_outputSampleRate;
if (m_sampleFormat == FormatLSB) calculateSquelch(m_inMagsq);
if (m_sampleFormat == FormatLSB) // binaural LSB
{ {
int n_out = UDPFilter->runSSB(ci, &sideband, false); int n_out = UDPFilter->runSSB(ci, &sideband, false);
@ -175,13 +183,14 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
{ {
for (int i = 0; i < n_out; i++) for (int i = 0; i < n_out; i++)
{ {
l = sideband[i].real(); l = m_squelchOpen ? sideband[i].real() * m_gain : 0;
r = sideband[i].imag(); r = m_squelchOpen ? sideband[i].imag() * m_gain : 0;
m_udpBuffer->write(Sample(l, r)); m_udpBuffer->write(Sample(l, r));
m_outMovingAverage.feed((l*l + r*r) / (1<<30));
} }
} }
} }
if (m_sampleFormat == FormatUSB) if (m_sampleFormat == FormatUSB) // binaural USB
{ {
int n_out = UDPFilter->runSSB(ci, &sideband, true); int n_out = UDPFilter->runSSB(ci, &sideband, true);
@ -189,23 +198,26 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
{ {
for (int i = 0; i < n_out; i++) for (int i = 0; i < n_out; i++)
{ {
l = sideband[i].real(); l = m_squelchOpen ? sideband[i].real() * m_gain : 0;
r = sideband[i].imag(); r = m_squelchOpen ? sideband[i].imag() * m_gain : 0;
m_udpBuffer->write(Sample(l, r)); m_udpBuffer->write(Sample(l, r));
m_outMovingAverage.feed((l*l + r*r) / (1<<30));
} }
} }
} }
else if (m_sampleFormat == FormatNFM) else if (m_sampleFormat == FormatNFM)
{ {
Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci); double demod = m_squelchOpen ? 32768.0 * m_phaseDiscri.phaseDiscriminator(ci) * m_gain : 0;
m_udpBuffer->write(Sample(demod, demod)); m_udpBuffer->write(Sample(demod, demod));
m_outMovingAverage.feed((demod * demod) / (1<<30));
} }
else if (m_sampleFormat == FormatNFMMono) else if (m_sampleFormat == FormatNFMMono)
{ {
FixReal demod = (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci)); FixReal demod = m_squelchOpen ? (FixReal) (32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_gain) : 0;
m_udpBufferMono->write(demod); m_udpBufferMono->write(demod);
m_outMovingAverage.feed((demod * demod) / 1073741824.0);
} }
else if (m_sampleFormat == FormatLSBMono) else if (m_sampleFormat == FormatLSBMono) // Monaural LSB
{ {
int n_out = UDPFilter->runSSB(ci, &sideband, false); int n_out = UDPFilter->runSSB(ci, &sideband, false);
@ -213,12 +225,13 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
{ {
for (int i = 0; i < n_out; i++) for (int i = 0; i < n_out; i++)
{ {
l = (sideband[i].real() + sideband[i].imag()) * 0.7; l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_gain : 0;
m_udpBufferMono->write(l); m_udpBufferMono->write(l);
m_outMovingAverage.feed((l * l) / (1<<30));
} }
} }
} }
else if (m_sampleFormat == FormatUSBMono) else if (m_sampleFormat == FormatUSBMono) // Monaural USB
{ {
int n_out = UDPFilter->runSSB(ci, &sideband, true); int n_out = UDPFilter->runSSB(ci, &sideband, true);
@ -226,20 +239,35 @@ void UDPSrc::feed(const SampleVector::const_iterator& begin, const SampleVector:
{ {
for (int i = 0; i < n_out; i++) for (int i = 0; i < n_out; i++)
{ {
l = (sideband[i].real() + sideband[i].imag()) * 0.7; l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_gain : 0;
m_udpBufferMono->write(l); m_udpBufferMono->write(l);
m_outMovingAverage.feed((l * l) / (1<<30));
} }
} }
} }
else if (m_sampleFormat == FormatAMMono) else if (m_sampleFormat == FormatAMMono)
{ {
FixReal demod = (FixReal) (32768.0f * sqrt(inMagSq) * m_gain); FixReal demod = m_squelchOpen ? (FixReal) (32768.0f * sqrt(inMagSq) * m_gain) : 0;
m_udpBufferMono->write(demod); m_udpBufferMono->write(demod);
m_outMovingAverage.feed((demod * demod) / (1<<30));
} }
else // Raw I/Q samples else // Raw I/Q samples
{ {
if (m_squelchOpen)
{
Sample s(ci.real() * m_gain, ci.imag() * m_gain);
m_udpBuffer->write(s); m_udpBuffer->write(s);
m_outMovingAverage.feed((inMagSq*m_gain*m_gain) / (1<<30));
} }
else
{
Sample s(0, 0);
m_udpBuffer->write(s);
m_outMovingAverage.feed(0);
}
}
m_magsq = m_outMovingAverage.average();
} }
} }
@ -320,13 +348,18 @@ bool UDPSrc::handleMessage(const Message& cmd)
m_volume = cfg.getVolume(); m_volume = cfg.getVolume();
} }
m_squelch = CalcDb::powerFromdB(cfg.getSquelchDB());
m_squelchEnabled = cfg.getSquelchEnabled();
m_settingsMutex.unlock(); m_settingsMutex.unlock();
qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigureImmediate: " qDebug() << "UDPSrc::handleMessage: MsgUDPSrcConfigureImmediate: "
<< " m_audioActive: " << m_audioActive << " m_audioActive: " << m_audioActive
<< " m_audioStereo: " << m_audioStereo << " m_audioStereo: " << m_audioStereo
<< " m_gain: " << m_gain << " m_gain: " << m_gain
<< " m_volume: " << m_volume; << " m_squelchEnabled: " << m_squelchEnabled
<< " m_squelch: " << m_squelch
<< " getSquelchDB: " << cfg.getSquelchDB();
return true; return true;
@ -384,8 +417,9 @@ bool UDPSrc::handleMessage(const Message& cmd)
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate; m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
UDPFilter->create_filter(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate); UDPFilter->create_filter(0.0, (m_rfBandwidth / 2.0) / m_outputSampleRate);
m_inMovingAverage.resize(m_inputSampleRate * 0.01, 1e-10); // 10 ms m_inMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10); // 10 ms
m_outMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10); // 10 ms m_outMovingAverage.resize(m_outputSampleRate * 0.01, 1e-10); // 10 ms
m_squelchThreshold = m_outputSampleRate * 0.05; // 50 ms
m_settingsMutex.unlock(); m_settingsMutex.unlock();

View File

@ -78,6 +78,7 @@ public:
void setSpectrum(MessageQueue* messageQueue, bool enabled); void setSpectrum(MessageQueue* messageQueue, bool enabled);
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
double getInMagSq() const { return m_inMagsq; } double getInMagSq() const { return m_inMagsq; }
bool getSquelchOpen() const { return m_squelchOpen; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
virtual void start(); virtual void start();
@ -161,7 +162,7 @@ protected:
static MsgUDPSrcConfigureImmediate* create( static MsgUDPSrcConfigureImmediate* create(
bool audioActive, bool audioActive,
bool audioStereo, bool audioStereo,
int boost, int gain,
int volume, int volume,
Real squelchDB, Real squelchDB,
bool squelchEnabled) bool squelchEnabled)
@ -169,7 +170,7 @@ protected:
return new MsgUDPSrcConfigureImmediate( return new MsgUDPSrcConfigureImmediate(
audioActive, audioActive,
audioStereo, audioStereo,
boost, gain,
volume, volume,
squelchDB, squelchDB,
squelchEnabled); squelchEnabled);
@ -269,7 +270,53 @@ protected:
PhaseDiscriminators m_phaseDiscri; PhaseDiscriminators m_phaseDiscri;
Real m_squelch; //!< squared magnitude
bool m_squelchEnabled;
bool m_squelchOpen;
int m_squelchOpenCount;
int m_squelchCloseCount;
int m_squelchThreshold;
QMutex m_settingsMutex; QMutex m_settingsMutex;
inline void calculateSquelch(double value)
{
if ((!m_squelchEnabled) || (value > m_squelch))
{
if (m_squelchOpenCount < m_squelchThreshold) {
m_squelchOpenCount++;
} else {
m_squelchCloseCount = m_squelchThreshold;
m_squelchOpen = true;
}
}
else
{
if (m_squelchCloseCount > 0) {
m_squelchCloseCount--;
} else {
m_squelchOpenCount = 0;
m_squelchOpen = false;
}
}
}
inline void initSquelch(bool open)
{
if (open)
{
m_squelchOpen = true;
m_squelchOpenCount = m_squelchThreshold;
m_squelchCloseCount = m_squelchThreshold;
}
else
{
m_squelchOpen = false;
m_squelchOpenCount = 0;
m_squelchCloseCount = 0;
}
}
}; };
#endif // INCLUDE_UDPSRC_H #endif // INCLUDE_UDPSRC_H

View File

@ -172,7 +172,7 @@ bool UDPSrcGUI::deserialize(const QByteArray& data)
ui->udpPort->setText(QString("%1").arg(s32tmp)); ui->udpPort->setText(QString("%1").arg(s32tmp));
d.readBlob(7, &bytetmp); d.readBlob(7, &bytetmp);
ui->spectrumGUI->deserialize(bytetmp); ui->spectrumGUI->deserialize(bytetmp);
d.readS32(16, &s32tmp, 10); d.readS32(8, &s32tmp, 10);
ui->gain->setValue(s32tmp); ui->gain->setValue(s32tmp);
ui->gainText->setText(tr("%1").arg(s32tmp/10.0, 0, 'f', 1)); ui->gainText->setText(tr("%1").arg(s32tmp/10.0, 0, 'f', 1));
d.readS32(9, &s32tmp, 0); d.readS32(9, &s32tmp, 0);
@ -231,6 +231,12 @@ void UDPSrcGUI::tick()
ui->inputPower->setText(QString::number(inPowDb, 'f', 1)); ui->inputPower->setText(QString::number(inPowDb, 'f', 1));
} }
if (m_udpSrc->getSquelchOpen()) {
ui->squelchLabel->setStyleSheet("QLabel { background-color : green; }");
} else {
ui->squelchLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
}
m_tickCount++; m_tickCount++;
} }
@ -265,6 +271,7 @@ UDPSrcGUI::UDPSrcGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget*
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
ui->squelchLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
ui->glSpectrum->setCenterFrequency(0); ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(ui->sampleRate->text().toInt()); ui->glSpectrum->setSampleRate(ui->sampleRate->text().toInt());