kopia lustrzana https://github.com/f4exb/sdrangel
SSB demod: reworked AGC to handle the threshold gate properly
rodzic
2cefa0ed69
commit
fb0ec4a680
|
@ -2,7 +2,7 @@
|
|||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
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.
|
||||
|
||||
<h2>Interface</h2>
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
<h3>4: Invert left and right channels</h3>
|
||||
|
||||
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.
|
||||
|
||||
<h3>10: "Low cut": In channel bandpass filter cutoff frequency closest to zero</h3>
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue