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:
parent
d15b484a4f
commit
2597883015
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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() :
|
||||
|
@ -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
|
||||
|
@ -50,6 +50,11 @@ public:
|
||||
return m_sum;
|
||||
}
|
||||
|
||||
int historySize() const
|
||||
{
|
||||
return m_history.size();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<Type> m_history;
|
||||
Type m_sum;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user