1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 09:48:45 -05: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 "audio/audiooutput.h"
#include "dsp/dspengine.h"
#include "util/db.h"
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message)
@ -32,7 +33,10 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) :
m_audioFlipChannels(false),
m_dsb(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_audioFifo(4, 24000),
m_settingsMutex(QMutex::Recursive)
@ -181,25 +185,25 @@ void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
}
else
{
double agcVal = m_agc.feedAndGetValue(sideband[i]);
double agcVal = m_agcActive ? m_agc.feedAndGetValue(sideband[i]) : 1.0;
if (m_audioBinaual)
{
if (m_audioFlipChannels)
{
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * agcVal * 10);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * 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);
}
else
{
m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * agcVal * 10);
m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * 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);
}
}
else
{
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].r = sample;
}
@ -305,6 +309,22 @@ bool SSBDemod::handleMessage(const Message& cmd)
m_audioFlipChannels = cfg.getAudioFlipChannels();
m_dsb = cfg.getDSB();
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();
@ -315,7 +335,10 @@ bool SSBDemod::handleMessage(const Message& cmd)
<< " m_audioBinaual: " << m_audioBinaual
<< " m_audioFlipChannels: " << m_audioFlipChannels
<< " m_dsb: " << m_dsb
<< "m_audioMute: " << m_audioMute;
<< " m_audioMute: " << m_audioMute
<< " m_agcActive: " << m_agcActive
<< " agcNbSamples: " << agcNbSamples
<< " agcPowerThreshold: " << agcPowerThreshold;
return true;
}

View File

@ -29,6 +29,7 @@
#include "util/message.h"
#define ssbFftLen 1024
#define agcTarget 327.68 // -20 dB amplitude => -40 dB power: center of normal signal
class SSBDemod : public BasebandSampleSink {
public:
@ -173,6 +174,9 @@ private:
double m_magsqPeak;
int m_magsqCount;
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;
Interpolator m_interpolator;

View File

@ -79,6 +79,9 @@ QByteArray SSBDemodGUI::serialize() const
s.writeBool(8, m_audioBinaural);
s.writeBool(9, m_audioFlipChannels);
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();
}
@ -97,6 +100,7 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
QByteArray bytetmp;
quint32 u32tmp;
qint32 tmp;
bool booltmp;
blockApplySettings(true);
m_channelMarker.blockSignals(true);
@ -122,6 +126,12 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
ui->audioFlipChannels->setChecked(m_audioFlipChannels);
d.readBool(10, &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);
m_channelMarker.blockSignals(false);
@ -265,6 +275,23 @@ void SSBDemodGUI::on_volume_valueChanged(int value)
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)
{
m_audioMute = checked;

View File

@ -433,6 +433,9 @@
<height>24</height>
</size>
</property>
<property name="pageStep">
<number>1</number>
</property>
</widget>
</item>
<item>
@ -489,6 +492,12 @@
</item>
<item>
<widget class="QLabel" name="agcTimeText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>AGC time constant (ms)</string>
</property>
@ -521,12 +530,18 @@
<number>1</number>
</property>
<property name="value">
<number>-40</number>
<number>-50</number>
</property>
</widget>
</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">
<string>AGC power threshold (dB)</string>
</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"/>
</resources>
<connections/>
</ui>

View File

@ -45,7 +45,8 @@ Real AGC::getAverage()
MagSquaredAGC::MagSquaredAGC(int historySize, double R, double threshold) :
AGC(historySize, R),
m_magsq(0.0),
m_threshold(threshold)
m_threshold(threshold),
m_thresholdCount(0)
{}
MagSquaredAGC::~MagSquaredAGC()
@ -64,7 +65,19 @@ double MagSquaredAGC::feedAndGetValue(const Complex& ci)
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_moving_average.feed(m_magsq);
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() :
@ -75,7 +88,8 @@ double MagSquaredAGC::feedAndGetValue(const Complex& ci)
MagAGC::MagAGC(int historySize, double R, double threshold) :
AGC(historySize, R),
m_magsq(0.0),
m_threshold(threshold)
m_threshold(threshold),
m_thresholdCount(0)
{}
MagAGC::~MagAGC()
@ -94,7 +108,19 @@ double MagAGC::feedAndGetValue(const Complex& ci)
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_moving_average.feed(m_magsq);
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() :

View File

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

View File

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

View File

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

View File

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