1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-09-04 14:17:50 -04:00

SSB demod: updated AGC

This commit is contained in:
f4exb 2017-07-25 21:21:48 +02:00
parent d15b484a4f
commit 2597883015
9 changed files with 134 additions and 16 deletions

View File

@ -24,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "util/db.h"
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message)
@ -32,7 +33,10 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) :
m_audioFlipChannels(false), m_audioFlipChannels(false),
m_dsb(false), m_dsb(false),
m_audioMute(false), m_audioMute(false),
m_agc(12000, 40.0, 1e-2), m_agc(12000, agcTarget, 1e-2),
m_agcActive(false),
m_agcNbSamples(12000),
m_agcPowerThreshold(1e-2),
m_sampleSink(sampleSink), m_sampleSink(sampleSink),
m_audioFifo(4, 24000), m_audioFifo(4, 24000),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
@ -181,25 +185,25 @@ void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
} }
else else
{ {
double agcVal = m_agc.feedAndGetValue(sideband[i]); double agcVal = m_agcActive ? m_agc.feedAndGetValue(sideband[i]) : 1.0;
if (m_audioBinaual) if (m_audioBinaual)
{ {
if (m_audioFlipChannels) if (m_audioFlipChannels)
{ {
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * agcVal * 10); m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * agcVal);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * m_volume * agcVal * 10); m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * m_volume * agcVal);
} }
else else
{ {
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * agcVal * 10); m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * agcVal);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * m_volume * agcVal * 10); m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * m_volume * agcVal);
} }
} }
else else
{ {
Real demod = (sideband[i].real() + sideband[i].imag()) * 0.7; Real demod = (sideband[i].real() + sideband[i].imag()) * 0.7;
qint16 sample = (qint16)(demod * m_volume * agcVal * 10); qint16 sample = (qint16)(demod * m_volume * agcVal);
m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample; m_audioBuffer[m_audioBufferFill].r = sample;
} }
@ -305,6 +309,22 @@ bool SSBDemod::handleMessage(const Message& cmd)
m_audioFlipChannels = cfg.getAudioFlipChannels(); m_audioFlipChannels = cfg.getAudioFlipChannels();
m_dsb = cfg.getDSB(); m_dsb = cfg.getDSB();
m_audioMute = cfg.getAudioMute(); m_audioMute = cfg.getAudioMute();
m_agcActive = cfg.getAGC();
int agcNbSamples = 48 * (1<<cfg.getAGCTimeLog2());
double agcPowerThreshold = CalcDb::powerFromdB(cfg.getAGCPowerThershold()) * (1<<30);
if (m_agcNbSamples != agcNbSamples)
{
m_agc.resize(agcNbSamples, agcTarget);
m_agcNbSamples = agcNbSamples;
}
if (m_agcPowerThreshold != agcPowerThreshold)
{
m_agc.setThreshold(agcPowerThreshold);
m_agcPowerThreshold = agcPowerThreshold;
}
m_settingsMutex.unlock(); m_settingsMutex.unlock();
@ -315,7 +335,10 @@ bool SSBDemod::handleMessage(const Message& cmd)
<< " m_audioBinaual: " << m_audioBinaual << " m_audioBinaual: " << m_audioBinaual
<< " m_audioFlipChannels: " << m_audioFlipChannels << " m_audioFlipChannels: " << m_audioFlipChannels
<< " m_dsb: " << m_dsb << " m_dsb: " << m_dsb
<< "m_audioMute: " << m_audioMute; << " m_audioMute: " << m_audioMute
<< " m_agcActive: " << m_agcActive
<< " agcNbSamples: " << agcNbSamples
<< " agcPowerThreshold: " << agcPowerThreshold;
return true; return true;
} }

View File

@ -29,6 +29,7 @@
#include "util/message.h" #include "util/message.h"
#define ssbFftLen 1024 #define ssbFftLen 1024
#define agcTarget 327.68 // -20 dB amplitude => -40 dB power: center of normal signal
class SSBDemod : public BasebandSampleSink { class SSBDemod : public BasebandSampleSink {
public: public:
@ -173,6 +174,9 @@ private:
double m_magsqPeak; double m_magsqPeak;
int m_magsqCount; int m_magsqCount;
MagAGC m_agc; MagAGC m_agc;
bool m_agcActive;
int m_agcNbSamples; //!< number of audio (48 kHz) samples for AGC averaging
double m_agcPowerThreshold; //!< AGC power threshold (linear)
NCOF m_nco; NCOF m_nco;
Interpolator m_interpolator; Interpolator m_interpolator;

View File

@ -79,6 +79,9 @@ QByteArray SSBDemodGUI::serialize() const
s.writeBool(8, m_audioBinaural); s.writeBool(8, m_audioBinaural);
s.writeBool(9, m_audioFlipChannels); s.writeBool(9, m_audioFlipChannels);
s.writeBool(10, m_dsb); s.writeBool(10, m_dsb);
s.writeBool(11, ui->agc->isChecked());
s.writeS32(12, ui->agcTimeLog2->value());
s.writeS32(13, ui->agcPowerThreshold->value());
return s.final(); return s.final();
} }
@ -97,6 +100,7 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
QByteArray bytetmp; QByteArray bytetmp;
quint32 u32tmp; quint32 u32tmp;
qint32 tmp; qint32 tmp;
bool booltmp;
blockApplySettings(true); blockApplySettings(true);
m_channelMarker.blockSignals(true); m_channelMarker.blockSignals(true);
@ -122,6 +126,12 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
ui->audioFlipChannels->setChecked(m_audioFlipChannels); ui->audioFlipChannels->setChecked(m_audioFlipChannels);
d.readBool(10, &m_dsb); d.readBool(10, &m_dsb);
ui->dsb->setChecked(m_dsb); ui->dsb->setChecked(m_dsb);
d.readBool(11, &booltmp, false);
ui->agc->setChecked(booltmp);
d.readS32(12, &tmp, 7);
ui->agcTimeText->setText(QString("%1").arg((1<<tmp), 0, 'f', 0));
d.readS32(13, &tmp, -20);
ui->agcPowerThresholdText->setText(QString("%1").arg(tmp, 0, 'f', 0));
blockApplySettings(false); blockApplySettings(false);
m_channelMarker.blockSignals(false); m_channelMarker.blockSignals(false);
@ -265,6 +275,23 @@ void SSBDemodGUI::on_volume_valueChanged(int value)
applySettings(); applySettings();
} }
void SSBDemodGUI::on_agc_stateChanged(int state)
{
applySettings();
}
void SSBDemodGUI::on_agcTimeLog2_valueChanged(int value)
{
ui->agcTimeText->setText(QString("%1").arg((1<<value), 0, 'f', 0));
applySettings();
}
void SSBDemodGUI::on_agcPowerThreshold_valueChanged(int value)
{
ui->agcPowerThresholdText->setText(QString("%1").arg(value, 0, 'f', 0));
applySettings();
}
void SSBDemodGUI::on_audioMute_toggled(bool checked) void SSBDemodGUI::on_audioMute_toggled(bool checked)
{ {
m_audioMute = checked; m_audioMute = checked;

View File

@ -433,6 +433,9 @@
<height>24</height> <height>24</height>
</size> </size>
</property> </property>
<property name="pageStep">
<number>1</number>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -489,6 +492,12 @@
</item> </item>
<item> <item>
<widget class="QLabel" name="agcTimeText"> <widget class="QLabel" name="agcTimeText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="toolTip"> <property name="toolTip">
<string>AGC time constant (ms)</string> <string>AGC time constant (ms)</string>
</property> </property>
@ -521,12 +530,18 @@
<number>1</number> <number>1</number>
</property> </property>
<property name="value"> <property name="value">
<number>-40</number> <number>-50</number>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="agcPowerThersholdText"> <widget class="QLabel" name="agcPowerThresholdText">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="toolTip"> <property name="toolTip">
<string>AGC power threshold (dB)</string> <string>AGC power threshold (dB)</string>
</property> </property>
@ -677,6 +692,14 @@
<include location="../../../sdrbase/resources/res.qrc"/> <include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/> <include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/> <include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -45,7 +45,8 @@ Real AGC::getAverage()
MagSquaredAGC::MagSquaredAGC(int historySize, double R, double threshold) : MagSquaredAGC::MagSquaredAGC(int historySize, double R, double threshold) :
AGC(historySize, R), AGC(historySize, R),
m_magsq(0.0), m_magsq(0.0),
m_threshold(threshold) m_threshold(threshold),
m_thresholdCount(0)
{} {}
MagSquaredAGC::~MagSquaredAGC() MagSquaredAGC::~MagSquaredAGC()
@ -64,7 +65,19 @@ double MagSquaredAGC::feedAndGetValue(const Complex& ci)
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_moving_average.feed(m_magsq); m_moving_average.feed(m_magsq);
m_u0 = m_R / m_moving_average.average(); m_u0 = m_R / m_moving_average.average();
return m_magsq > m_threshold ? m_u0 : 1.0;
if (m_magsq > m_threshold)
{
m_thresholdCount = 0;
}
else
{
if (m_thresholdCount < m_moving_average.historySize()) {
m_thresholdCount++;
}
}
return (m_thresholdCount < m_moving_average.historySize()) ? m_u0 : 0.0;
} }
//MagAGC::MagAGC() : //MagAGC::MagAGC() :
@ -75,7 +88,8 @@ double MagSquaredAGC::feedAndGetValue(const Complex& ci)
MagAGC::MagAGC(int historySize, double R, double threshold) : MagAGC::MagAGC(int historySize, double R, double threshold) :
AGC(historySize, R), AGC(historySize, R),
m_magsq(0.0), m_magsq(0.0),
m_threshold(threshold) m_threshold(threshold),
m_thresholdCount(0)
{} {}
MagAGC::~MagAGC() MagAGC::~MagAGC()
@ -94,7 +108,19 @@ double MagAGC::feedAndGetValue(const Complex& ci)
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_moving_average.feed(m_magsq); m_moving_average.feed(m_magsq);
m_u0 = m_R / sqrt(m_moving_average.average()); m_u0 = m_R / sqrt(m_moving_average.average());
return m_magsq > m_threshold ? m_u0 : 1.0;
if (m_magsq > m_threshold)
{
m_thresholdCount = 0;
}
else
{
if (m_thresholdCount < m_moving_average.historySize()) {
m_thresholdCount++;
}
}
return (m_thresholdCount < m_moving_average.historySize()) ? m_u0 : 0.0;
} }
//AlphaAGC::AlphaAGC() : //AlphaAGC::AlphaAGC() :

View File

@ -37,9 +37,11 @@ public:
virtual void feed(Complex& ci); virtual void feed(Complex& ci);
double feedAndGetValue(const Complex& ci); double feedAndGetValue(const Complex& ci);
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
void setThreshold(double threshold) { m_threshold = threshold; }
private: private:
double m_magsq; double m_magsq;
double m_threshold; double m_threshold; //!< squelch on magsq average with transition from +3dB
int m_thresholdCount;
}; };
class MagAGC : public AGC class MagAGC : public AGC
@ -50,9 +52,11 @@ public:
virtual void feed(Complex& ci); virtual void feed(Complex& ci);
double feedAndGetValue(const Complex& ci); double feedAndGetValue(const Complex& ci);
Real getMagSq() const { return m_magsq; } Real getMagSq() const { return m_magsq; }
void setThreshold(double threshold) { m_threshold = threshold; }
private: private:
double m_magsq; double m_magsq;
double m_threshold; double m_threshold; //!< squelch on magsq average
int m_thresholdCount;
}; };
class AlphaAGC : public AGC class AlphaAGC : public AGC

View File

@ -50,6 +50,11 @@ public:
return m_sum; return m_sum;
} }
int historySize() const
{
return m_history.size();
}
protected: protected:
std::vector<Type> m_history; std::vector<Type> m_history;
Type m_sum; Type m_sum;

View File

@ -28,3 +28,8 @@ double CalcDb::dbPower(double magsq, double floordB)
return floordB; return floordB;
} }
} }
double CalcDb::powerFromdB(double powerdB)
{
return pow(10.0, powerdB / 10.0);
}

View File

@ -23,6 +23,7 @@ class CalcDb
{ {
public: public:
static double dbPower(double magsq, double floordB = -100.0); static double dbPower(double magsq, double floordB = -100.0);
static double powerFromdB(double powerdB);
}; };
#endif /* INCLUDE_UTIL_DB_H_ */ #endif /* INCLUDE_UTIL_DB_H_ */