SSB demod: reworked AGC to handle the threshold gate properly

This commit is contained in:
f4exb 2019-06-09 09:25:18 +02:00
parent 2cefa0ed69
commit fb0ec4a680
7 changed files with 60 additions and 57 deletions

View File

@ -140,7 +140,7 @@ The signal power is calculated as the moving average over the AGC time constant
Active only in AGC mode with squelch enabled.
To avoid unwanted squelch opening on short transient bursts only signals with power above threshold during this period in milliseconds will open the squelch.It can be varied from 0 to 20 ms in 1 ms steps.
To avoid unwanted squelch opening on short transient bursts only signals with power above threshold during this period in milliseconds will open the squelch.It can be varied from 0 to 20 ms in 1 ms steps then from 30 to 500 ms in 10 ms steps.
When the power threshold is close to the noise floor a few milliseconds help in preventing noise power wiggle to open the squelch.

View File

@ -202,9 +202,10 @@ void SSBDemodGUI::on_agcPowerThreshold_valueChanged(int value)
void SSBDemodGUI::on_agcThresholdGate_valueChanged(int value)
{
QString s = QString::number(value, 'f', 0);
int agcThresholdGate = value < 20 ? value : ((value - 20) * 10) + 20;
QString s = QString::number(agcThresholdGate, 'f', 0);
ui->agcThresholdGateText->setText(s);
m_settings.m_agcThresholdGate = value;
m_settings.m_agcThresholdGate = agcThresholdGate;
applySettings();
}
@ -565,10 +566,7 @@ void SSBDemodGUI::displaySettings()
ui->agcPowerThreshold->setValue(m_settings.m_agcPowerThreshold);
displayAGCPowerThreshold(ui->agcPowerThreshold->value());
ui->agcThresholdGate->setValue(m_settings.m_agcThresholdGate);
s = QString::number(ui->agcThresholdGate->value(), 'f', 0);
ui->agcThresholdGateText->setText(s);
displayAGCThresholdGate(m_settings.m_agcThresholdGate);
blockApplySettings(false);
}
@ -586,6 +584,19 @@ void SSBDemodGUI::displayAGCPowerThreshold(int value)
}
}
void SSBDemodGUI::displayAGCThresholdGate(int value)
{
QString s = QString::number(value, 'f', 0);
ui->agcThresholdGateText->setText(s);
int dialValue = value;
if (value > 20) {
dialValue = ((value - 20) / 10) + 20;
}
ui->agcThresholdGate->setValue(dialValue);
}
void SSBDemodGUI::leaveEvent(QEvent*)
{
m_channelMarker.setHighlighted(false);

View File

@ -73,8 +73,8 @@ private:
void applyBandwidths(int spanLog2, bool force = false);
int spanLog2Limit(int spanLog2);
void displaySettings();
void displayAGCPowerThreshold(int value);
void displayAGCThresholdGate(int value);
void leaveEvent(QEvent*);
void enterEvent(QEvent*);

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<width>414</width>
<height>190</height>
</rect>
</property>
@ -18,7 +18,7 @@
</property>
<property name="minimumSize">
<size>
<width>412</width>
<width>414</width>
<height>0</height>
</size>
</property>
@ -36,13 +36,13 @@
<rect>
<x>0</x>
<y>0</y>
<width>410</width>
<width>415</width>
<height>171</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>410</width>
<width>415</width>
<height>0</height>
</size>
</property>
@ -836,7 +836,7 @@
<string>Power threshold gate (ms)</string>
</property>
<property name="maximum">
<number>20</number>
<number>68</number>
</property>
<property name="pageStep">
<number>1</number>
@ -850,7 +850,7 @@
<widget class="QLabel" name="agcThresholdGateText">
<property name="minimumSize">
<size>
<width>16</width>
<width>22</width>
<height>0</height>
</size>
</property>
@ -858,7 +858,7 @@
<string>Power threshold gate (ms)</string>
</property>
<property name="text">
<string>00</string>
<string>000</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>

View File

@ -9,7 +9,7 @@
const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
QString("SSB Demodulator"),
QString("4.8.2"),
QString("4.10.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,

View File

@ -50,7 +50,7 @@ MagAGC::MagAGC(int historySize, double R, double threshold) :
m_stepLength(std::min(2400, historySize/2)), // max 50 ms (at 48 kHz)
m_stepDelta(1.0/m_stepLength),
m_stepUpCounter(0),
m_stepDownCounter(m_stepLength),
m_stepDownCounter(0),
m_gateCounter(0),
m_stepDownDelay(historySize),
m_clamping(false),
@ -68,7 +68,7 @@ void MagAGC::resize(int historySize, int stepLength, Real R)
m_stepLength = stepLength;
m_stepDelta = 1.0 / m_stepLength;
m_stepUpCounter = 0;
m_stepDownCounter = m_stepLength;
m_stepDownCounter = 0;
AGC::resize(historySize, R);
m_moving_average.fill(0);
}
@ -85,7 +85,7 @@ void MagAGC::setThresholdEnable(bool enable)
if (m_thresholdEnable != enable)
{
m_stepUpCounter = 0;
m_stepDownCounter = m_stepLength;
m_stepDownCounter = 0;
}
m_thresholdEnable = enable;
@ -136,50 +136,55 @@ double MagAGC::feedAndGetValue(const Complex& ci)
if (m_thresholdEnable)
{
bool open = false;
if (m_magsq > m_threshold)
{
if (m_gateCounter < m_gate)
{
if (m_gateCounter < m_gate) {
m_gateCounter++;
}
else
{
m_count = 0;
} else {
open = true;
}
}
else
{
if (m_count < m_stepDownDelay) {
m_count++;
}
m_gateCounter = 0;
}
if (m_count < m_stepDownDelay)
if (open)
{
m_stepDownCounter = m_stepUpCounter;
m_count = m_stepDownDelay; // delay before step down (grace delay)
}
else
{
m_count--;
m_gateCounter = m_gate; // keep gate open during grace
}
if (m_stepUpCounter < m_stepLength)
if (m_count > 0) // up phase
{
m_stepDownCounter = m_stepUpCounter; // prepare for step down
if (m_stepUpCounter < m_stepLength) // step up
{
m_stepUpCounter++;
return hardLimiter(m_u0 * StepFunctions::smootherstep(m_stepUpCounter * m_stepDelta), m_magsq);
}
else
else // steady open
{
return hardLimiter(m_u0, m_magsq);
}
}
else
else // down phase
{
m_stepUpCounter = m_stepDownCounter;
m_stepUpCounter = m_stepDownCounter; // prepare for step up
if (m_stepDownCounter > 0)
if (m_stepDownCounter > 0) // step down
{
m_stepDownCounter--;
return hardLimiter(m_u0 * StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta), m_magsq);
}
else
else // steady closed
{
return 0.0;
}
@ -191,25 +196,13 @@ double MagAGC::feedAndGetValue(const Complex& ci)
}
}
float MagAGC::getStepDownValue() const
{
if (m_count < m_stepDownDelay)
{
return 1.0f;
}
else
{
return StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta);
}
}
float MagAGC::getStepValue() const
{
if (m_count < m_stepDownDelay)
if (m_count > 0) // up phase
{
return StepFunctions::smootherstep(m_stepUpCounter * m_stepDelta); // step up
}
else
else // down phase
{
return StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta); // step down
}

View File

@ -46,12 +46,11 @@ public:
double getMagSq() const { return m_magsq; }
void setThreshold(double threshold) { m_threshold = threshold; }
void setThresholdEnable(bool enable);
void setGate(int gate) { m_gate = gate; }
void setStepDownDelay(int stepDownDelay) { m_stepDownDelay = stepDownDelay; }
void setGate(int gate) { m_gate = gate; m_gateCounter = 0; m_count = 0; }
void setStepDownDelay(int stepDownDelay) { m_stepDownDelay = stepDownDelay; m_gateCounter = 0; m_count = 0; }
void setClamping(bool clamping) { m_clamping = clamping; }
void setClampMax(double clampMax) { m_clampMax = clampMax; }
int getStepDownDelay() const { return m_stepDownDelay; }
float getStepDownValue() const;
float getStepValue() const;
void setHardLimiting(bool hardLimiting) { m_hardLimiting = hardLimiting; }