diff --git a/plugins/channelrx/demodssb/readme.md b/plugins/channelrx/demodssb/readme.md
index c7ffc2e02..e7ddc5b20 100644
--- a/plugins/channelrx/demodssb/readme.md
+++ b/plugins/channelrx/demodssb/readme.md
@@ -2,7 +2,7 @@
Introduction
-This plugin can be used to listen to a single sideband or double sidebands modulated signal.
+This plugin can be used to listen to a single sideband or double sidebands modulated signal.
Interface
@@ -24,7 +24,7 @@ Average total power in dB relative to a +/- 1.0 amplitude signal received in the
- Monaural: the scalar signal is routed to both left and right audio channels
- Binaural: the complex signal is fed with the real part on the left audio channel and the imaginary part to the right audio channel
-
+
4: Invert left and right channels
Inverts left and right audio channels. Useful in binaural mode only.
@@ -91,7 +91,7 @@ This is how the Span (8) and bandpass (9, 10) filter controls look like in the 3
Values are expressed in kHz and step is 100 Hz.
- In SSB mode this is the upper (USB: positive frequencies) or lower (LSB: negative frequencies) cutoff of the in channel single side band bandpass filter. The value triggers LSB mode when negative and USB when positive
- - In DSB mode this is half the bandwidth of the double side band in channel bandpass filter therefore the value is prefixed with the ± sign.
+ - In DSB mode this is half the bandwidth of the double side band in channel bandpass filter therefore the value is prefixed with the ± sign.
10: "Low cut": In channel bandpass filter cutoff frequency closest to zero
@@ -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.
diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp
index 2bd3532e4..58c02f76b 100644
--- a/plugins/channelrx/demodssb/ssbdemodgui.cpp
+++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp
@@ -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);
diff --git a/plugins/channelrx/demodssb/ssbdemodgui.h b/plugins/channelrx/demodssb/ssbdemodgui.h
index fceead47a..673e63dad 100644
--- a/plugins/channelrx/demodssb/ssbdemodgui.h
+++ b/plugins/channelrx/demodssb/ssbdemodgui.h
@@ -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*);
diff --git a/plugins/channelrx/demodssb/ssbdemodgui.ui b/plugins/channelrx/demodssb/ssbdemodgui.ui
index a481293b3..6b29df55c 100644
--- a/plugins/channelrx/demodssb/ssbdemodgui.ui
+++ b/plugins/channelrx/demodssb/ssbdemodgui.ui
@@ -6,7 +6,7 @@
0
0
- 412
+ 414
190
@@ -18,7 +18,7 @@
- 412
+ 414
0
@@ -36,13 +36,13 @@
0
0
- 410
+ 415
171
- 410
+ 415
0
@@ -836,7 +836,7 @@
Power threshold gate (ms)
- 20
+ 68
1
@@ -850,7 +850,7 @@
- 16
+ 22
0
@@ -858,7 +858,7 @@
Power threshold gate (ms)
- 00
+ 000
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
diff --git a/plugins/channelrx/demodssb/ssbplugin.cpp b/plugins/channelrx/demodssb/ssbplugin.cpp
index 932de22d7..b882a0253 100644
--- a/plugins/channelrx/demodssb/ssbplugin.cpp
+++ b/plugins/channelrx/demodssb/ssbplugin.cpp
@@ -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,
diff --git a/sdrbase/dsp/agc.cpp b/sdrbase/dsp/agc.cpp
index c105b3145..d899b111e 100644
--- a/sdrbase/dsp/agc.cpp
+++ b/sdrbase/dsp/agc.cpp
@@ -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
}
diff --git a/sdrbase/dsp/agc.h b/sdrbase/dsp/agc.h
index f1f1745b2..7b531a0ae 100644
--- a/sdrbase/dsp/agc.h
+++ b/sdrbase/dsp/agc.h
@@ -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; }