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. 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. 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) 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); ui->agcThresholdGateText->setText(s);
m_settings.m_agcThresholdGate = value; m_settings.m_agcThresholdGate = agcThresholdGate;
applySettings(); applySettings();
} }
@ -565,10 +566,7 @@ void SSBDemodGUI::displaySettings()
ui->agcPowerThreshold->setValue(m_settings.m_agcPowerThreshold); ui->agcPowerThreshold->setValue(m_settings.m_agcPowerThreshold);
displayAGCPowerThreshold(ui->agcPowerThreshold->value()); displayAGCPowerThreshold(ui->agcPowerThreshold->value());
displayAGCThresholdGate(m_settings.m_agcThresholdGate);
ui->agcThresholdGate->setValue(m_settings.m_agcThresholdGate);
s = QString::number(ui->agcThresholdGate->value(), 'f', 0);
ui->agcThresholdGateText->setText(s);
blockApplySettings(false); 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*) void SSBDemodGUI::leaveEvent(QEvent*)
{ {
m_channelMarker.setHighlighted(false); m_channelMarker.setHighlighted(false);

View File

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

View File

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

View File

@ -9,7 +9,7 @@
const PluginDescriptor SSBPlugin::m_pluginDescriptor = { const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
QString("SSB Demodulator"), QString("SSB Demodulator"),
QString("4.8.2"), QString("4.10.0"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, 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_stepLength(std::min(2400, historySize/2)), // max 50 ms (at 48 kHz)
m_stepDelta(1.0/m_stepLength), m_stepDelta(1.0/m_stepLength),
m_stepUpCounter(0), m_stepUpCounter(0),
m_stepDownCounter(m_stepLength), m_stepDownCounter(0),
m_gateCounter(0), m_gateCounter(0),
m_stepDownDelay(historySize), m_stepDownDelay(historySize),
m_clamping(false), m_clamping(false),
@ -68,7 +68,7 @@ void MagAGC::resize(int historySize, int stepLength, Real R)
m_stepLength = stepLength; m_stepLength = stepLength;
m_stepDelta = 1.0 / m_stepLength; m_stepDelta = 1.0 / m_stepLength;
m_stepUpCounter = 0; m_stepUpCounter = 0;
m_stepDownCounter = m_stepLength; m_stepDownCounter = 0;
AGC::resize(historySize, R); AGC::resize(historySize, R);
m_moving_average.fill(0); m_moving_average.fill(0);
} }
@ -85,7 +85,7 @@ void MagAGC::setThresholdEnable(bool enable)
if (m_thresholdEnable != enable) if (m_thresholdEnable != enable)
{ {
m_stepUpCounter = 0; m_stepUpCounter = 0;
m_stepDownCounter = m_stepLength; m_stepDownCounter = 0;
} }
m_thresholdEnable = enable; m_thresholdEnable = enable;
@ -136,50 +136,55 @@ double MagAGC::feedAndGetValue(const Complex& ci)
if (m_thresholdEnable) if (m_thresholdEnable)
{ {
bool open = false;
if (m_magsq > m_threshold) if (m_magsq > m_threshold)
{ {
if (m_gateCounter < m_gate) if (m_gateCounter < m_gate) {
{
m_gateCounter++; m_gateCounter++;
} } else {
else open = true;
{
m_count = 0;
} }
} }
else else
{ {
if (m_count < m_stepDownDelay) {
m_count++;
}
m_gateCounter = 0; 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++; m_stepUpCounter++;
return hardLimiter(m_u0 * StepFunctions::smootherstep(m_stepUpCounter * m_stepDelta), m_magsq); return hardLimiter(m_u0 * StepFunctions::smootherstep(m_stepUpCounter * m_stepDelta), m_magsq);
} }
else else // steady open
{ {
return hardLimiter(m_u0, m_magsq); 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--; m_stepDownCounter--;
return hardLimiter(m_u0 * StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta), m_magsq); return hardLimiter(m_u0 * StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta), m_magsq);
} }
else else // steady closed
{ {
return 0.0; 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 float MagAGC::getStepValue() const
{ {
if (m_count < m_stepDownDelay) if (m_count > 0) // up phase
{ {
return StepFunctions::smootherstep(m_stepUpCounter * m_stepDelta); // step up return StepFunctions::smootherstep(m_stepUpCounter * m_stepDelta); // step up
} }
else else // down phase
{ {
return StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta); // step down return StepFunctions::smootherstep(m_stepDownCounter * m_stepDelta); // step down
} }

View File

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