Frequency tracker: added squelch gate control

This commit is contained in:
f4exb 2019-05-05 13:19:00 +02:00
parent f63b0fe96c
commit cdf8a63294
13 changed files with 152 additions and 22 deletions

View File

@ -59,6 +59,7 @@ FreqTracker::FreqTracker(DeviceSourceAPI *deviceAPI) :
m_channelSampleRate(48000), m_channelSampleRate(48000),
m_running(false), m_running(false),
m_squelchOpen(false), m_squelchOpen(false),
m_squelchGate(0),
m_magsqSum(0.0f), m_magsqSum(0.0f),
m_magsqPeak(0.0f), m_magsqPeak(0.0f),
m_magsqCount(0), m_magsqCount(0),
@ -182,19 +183,35 @@ void FreqTracker::processOneSample(Complex &ci)
if (m_magsq < m_squelchLevel) if (m_magsq < m_squelchLevel)
{ {
if (m_squelchCount > 0) { if (m_squelchGate > 0)
m_squelchCount--; {
if (m_squelchCount > 0) {
m_squelchCount--;
}
m_squelchOpen = m_squelchCount >= m_squelchGate;
}
else
{
m_squelchOpen = false;
} }
} }
else else
{ {
if (m_squelchCount < m_channelSampleRate / 10) { if (m_squelchGate > 0)
m_squelchCount++; {
if (m_squelchCount < 2*m_squelchGate) {
m_squelchCount++;
}
m_squelchOpen = m_squelchCount >= m_squelchGate;
}
else
{
m_squelchOpen = true;
} }
} }
m_squelchOpen = (m_squelchCount >= m_channelSampleRate / 20);
if (m_squelchOpen) if (m_squelchOpen)
{ {
if (m_settings.m_trackerType == FreqTrackerSettings::TrackerFLL) if (m_settings.m_trackerType == FreqTrackerSettings::TrackerFLL)
@ -412,6 +429,11 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force)
reverseAPIKeys.append("rrcRolloff"); reverseAPIKeys.append("rrcRolloff");
updateInterpolator = true; updateInterpolator = true;
} }
if ((m_settings.m_squelchGate != settings.m_squelchGate) || force)
{
reverseAPIKeys.append("squelchGate");
updateInterpolator = true;
}
if (settings.m_useReverseAPI) if (settings.m_useReverseAPI)
{ {
@ -439,6 +461,7 @@ void FreqTracker::setInterpolator()
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) m_channelSampleRate; m_interpolatorDistance = (Real) m_inputSampleRate / (Real) m_channelSampleRate;
m_rrcFilter->create_rrc_filter(m_settings.m_rfBandwidth / m_channelSampleRate, m_settings.m_rrcRolloff / 100.0); m_rrcFilter->create_rrc_filter(m_settings.m_rfBandwidth / m_channelSampleRate, m_settings.m_rrcRolloff / 100.0);
m_squelchGate = (m_channelSampleRate / 100) * m_settings.m_squelchGate; // gate is given in 10s of ms at channel sample rate
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }

View File

@ -214,6 +214,7 @@ private:
Real m_squelchLevel; Real m_squelchLevel;
uint32_t m_squelchCount; uint32_t m_squelchCount;
bool m_squelchOpen; bool m_squelchOpen;
uint32_t m_squelchGate; //!< Squelch gate in samples
double m_magsq; double m_magsq;
double m_magsqSum; double m_magsqSum;
double m_magsqPeak; double m_magsqPeak;

View File

@ -232,6 +232,13 @@ void FreqTrackerGUI::on_squelch_valueChanged(int value)
applySettings(); applySettings();
} }
void FreqTrackerGUI::on_squelchGate_valueChanged(int value)
{
ui->squelchGateText->setText(QString("%1").arg(value * 10.0f, 0, 'f', 0));
m_settings.m_squelchGate = value;
applySettings();
}
void FreqTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown) void FreqTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{ {
(void) widget; (void) widget;
@ -369,6 +376,8 @@ void FreqTrackerGUI::displaySettings()
ui->rrcRolloff->setValue(m_settings.m_rrcRolloff); ui->rrcRolloff->setValue(m_settings.m_rrcRolloff);
QString rolloffStr = QString::number(m_settings.m_rrcRolloff/100.0, 'f', 2); QString rolloffStr = QString::number(m_settings.m_rrcRolloff/100.0, 'f', 2);
ui->rrcRolloffText->setText(rolloffStr); ui->rrcRolloffText->setText(rolloffStr);
ui->squelchGateText->setText(QString("%1").arg(m_settings.m_squelchGate * 10.0f, 0, 'f', 0));
ui->squelchGate->setValue(m_settings.m_squelchGate);
blockApplySettings(false); blockApplySettings(false);
} }

View File

@ -94,6 +94,7 @@ private slots:
void on_rrc_toggled(bool checked); void on_rrc_toggled(bool checked);
void on_rrcRolloff_valueChanged(int value); void on_rrcRolloff_valueChanged(int value);
void on_squelch_valueChanged(int value); void on_squelch_valueChanged(int value);
void on_squelchGate_valueChanged(int value);
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p); void onMenuDialogCalled(const QPoint& p);
void handleInputMessages(); void handleInputMessages();

View File

@ -624,6 +624,53 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QDial" name="squelchGate">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Squelch gate (ms)</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="squelchGateText">
<property name="minimumSize">
<size>
<width>25</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Squelch gate (ms)</string>
</property>
<property name="text">
<string>000</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View File

@ -42,6 +42,7 @@ void FreqTrackerSettings::resetToDefaults()
m_pllPskOrder = 2; // BPSK m_pllPskOrder = 2; // BPSK
m_rrc = false; m_rrc = false;
m_rrcRolloff = 35; m_rrcRolloff = 35;
m_squelchGate = 5; // 50 ms
m_useReverseAPI = false; m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888; m_reverseAPIPort = 8888;
@ -74,6 +75,7 @@ QByteArray FreqTrackerSettings::serialize() const
s.writeU32(18, m_reverseAPIPort); s.writeU32(18, m_reverseAPIPort);
s.writeU32(19, m_reverseAPIDeviceIndex); s.writeU32(19, m_reverseAPIDeviceIndex);
s.writeU32(20, m_reverseAPIChannelIndex); s.writeU32(20, m_reverseAPIChannelIndex);
s.writeS32(21, m_squelchGate);
return s.final(); return s.final();
} }
@ -136,6 +138,8 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data)
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
d.readU32(20, &utmp, 0); d.readU32(20, &utmp, 0);
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
d.readS32(21, &tmp, 5);
m_squelchGate = tmp < 0 ? 0 : tmp > 99 ? 99 : tmp;
return true; return true;
} }

View File

@ -47,6 +47,7 @@ struct FreqTrackerSettings
uint32_t m_pllPskOrder; uint32_t m_pllPskOrder;
bool m_rrc; bool m_rrc;
uint32_t m_rrcRolloff; //!< in 100ths uint32_t m_rrcRolloff; //!< in 100ths
int m_squelchGate; //!< in 10s of ms
bool m_useReverseAPI; bool m_useReverseAPI;
QString m_reverseAPIAddress; QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort; uint16_t m_reverseAPIPort;

View File

@ -2783,8 +2783,9 @@ margin-bottom: 20px;
"type" : "string" "type" : "string"
}, },
"alphaEMA" : { "alphaEMA" : {
"type" : "integer", "type" : "number",
"description" : "Alpha factor for delta frequency EMA in %" "format" : "float",
"description" : "Alpha factor for delta frequency EMA"
}, },
"tracking" : { "tracking" : {
"type" : "integer", "type" : "integer",
@ -2806,6 +2807,10 @@ margin-bottom: 20px;
"type" : "integer", "type" : "integer",
"description" : "RRC filter rolloff factor in %" "description" : "RRC filter rolloff factor in %"
}, },
"squelchGate" : {
"type" : "integer",
"description" : "Squelch trigger gate in 10s of ms"
},
"useReverseAPI" : { "useReverseAPI" : {
"type" : "integer", "type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)" "description" : "Synchronize with reverse API (1 for yes, 0 for no)"
@ -24919,7 +24924,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2019-05-05T01:27:03.875+02:00 Generated 2019-05-05T11:13:49.637+02:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -20,8 +20,9 @@ FreqTrackerSettings:
title: title:
type: string type: string
alphaEMA: alphaEMA:
description: Alpha factor for delta frequency EMA in % description: Alpha factor for delta frequency EMA
type: integer type: number
format: float
tracking: tracking:
description: Tracking 1 for enabled 0 for disabled description: Tracking 1 for enabled 0 for disabled
type: integer type: integer
@ -37,6 +38,9 @@ FreqTrackerSettings:
rrcRolloff: rrcRolloff:
description: RRC filter rolloff factor in % description: RRC filter rolloff factor in %
type: integer type: integer
squelchGate:
description: Squelch trigger gate in 10s of ms
type: integer
useReverseAPI: useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no) description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer type: integer

View File

@ -38,6 +38,9 @@ FreqTrackerSettings:
rrcRolloff: rrcRolloff:
description: RRC filter rolloff factor in % description: RRC filter rolloff factor in %
type: integer type: integer
squelchGate:
description: Squelch trigger gate in 10s of ms
type: integer
useReverseAPI: useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no) description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer type: integer

View File

@ -2783,8 +2783,9 @@ margin-bottom: 20px;
"type" : "string" "type" : "string"
}, },
"alphaEMA" : { "alphaEMA" : {
"type" : "integer", "type" : "number",
"description" : "Alpha factor for delta frequency EMA in %" "format" : "float",
"description" : "Alpha factor for delta frequency EMA"
}, },
"tracking" : { "tracking" : {
"type" : "integer", "type" : "integer",
@ -2806,6 +2807,10 @@ margin-bottom: 20px;
"type" : "integer", "type" : "integer",
"description" : "RRC filter rolloff factor in %" "description" : "RRC filter rolloff factor in %"
}, },
"squelchGate" : {
"type" : "integer",
"description" : "Squelch trigger gate in 10s of ms"
},
"useReverseAPI" : { "useReverseAPI" : {
"type" : "integer", "type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)" "description" : "Synchronize with reverse API (1 for yes, 0 for no)"
@ -24919,7 +24924,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2019-05-05T01:27:03.875+02:00 Generated 2019-05-05T11:13:49.637+02:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -40,7 +40,7 @@ SWGFreqTrackerSettings::SWGFreqTrackerSettings() {
m_rgb_color_isSet = false; m_rgb_color_isSet = false;
title = nullptr; title = nullptr;
m_title_isSet = false; m_title_isSet = false;
alpha_ema = 0; alpha_ema = 0.0f;
m_alpha_ema_isSet = false; m_alpha_ema_isSet = false;
tracking = 0; tracking = 0;
m_tracking_isSet = false; m_tracking_isSet = false;
@ -52,6 +52,8 @@ SWGFreqTrackerSettings::SWGFreqTrackerSettings() {
m_rrc_isSet = false; m_rrc_isSet = false;
rrc_rolloff = 0; rrc_rolloff = 0;
m_rrc_rolloff_isSet = false; m_rrc_rolloff_isSet = false;
squelch_gate = 0;
m_squelch_gate_isSet = false;
use_reverse_api = 0; use_reverse_api = 0;
m_use_reverse_api_isSet = false; m_use_reverse_api_isSet = false;
reverse_api_address = nullptr; reverse_api_address = nullptr;
@ -82,7 +84,7 @@ SWGFreqTrackerSettings::init() {
m_rgb_color_isSet = false; m_rgb_color_isSet = false;
title = new QString(""); title = new QString("");
m_title_isSet = false; m_title_isSet = false;
alpha_ema = 0; alpha_ema = 0.0f;
m_alpha_ema_isSet = false; m_alpha_ema_isSet = false;
tracking = 0; tracking = 0;
m_tracking_isSet = false; m_tracking_isSet = false;
@ -94,6 +96,8 @@ SWGFreqTrackerSettings::init() {
m_rrc_isSet = false; m_rrc_isSet = false;
rrc_rolloff = 0; rrc_rolloff = 0;
m_rrc_rolloff_isSet = false; m_rrc_rolloff_isSet = false;
squelch_gate = 0;
m_squelch_gate_isSet = false;
use_reverse_api = 0; use_reverse_api = 0;
m_use_reverse_api_isSet = false; m_use_reverse_api_isSet = false;
reverse_api_address = new QString(""); reverse_api_address = new QString("");
@ -123,6 +127,7 @@ SWGFreqTrackerSettings::cleanup() {
if(reverse_api_address != nullptr) { if(reverse_api_address != nullptr) {
delete reverse_api_address; delete reverse_api_address;
} }
@ -154,7 +159,7 @@ SWGFreqTrackerSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
::SWGSDRangel::setValue(&alpha_ema, pJson["alphaEMA"], "qint32", ""); ::SWGSDRangel::setValue(&alpha_ema, pJson["alphaEMA"], "float", "");
::SWGSDRangel::setValue(&tracking, pJson["tracking"], "qint32", ""); ::SWGSDRangel::setValue(&tracking, pJson["tracking"], "qint32", "");
@ -166,6 +171,8 @@ SWGFreqTrackerSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&rrc_rolloff, pJson["rrcRolloff"], "qint32", ""); ::SWGSDRangel::setValue(&rrc_rolloff, pJson["rrcRolloff"], "qint32", "");
::SWGSDRangel::setValue(&squelch_gate, pJson["squelchGate"], "qint32", "");
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
@ -228,6 +235,9 @@ SWGFreqTrackerSettings::asJsonObject() {
if(m_rrc_rolloff_isSet){ if(m_rrc_rolloff_isSet){
obj->insert("rrcRolloff", QJsonValue(rrc_rolloff)); obj->insert("rrcRolloff", QJsonValue(rrc_rolloff));
} }
if(m_squelch_gate_isSet){
obj->insert("squelchGate", QJsonValue(squelch_gate));
}
if(m_use_reverse_api_isSet){ if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
} }
@ -307,12 +317,12 @@ SWGFreqTrackerSettings::setTitle(QString* title) {
this->m_title_isSet = true; this->m_title_isSet = true;
} }
qint32 float
SWGFreqTrackerSettings::getAlphaEma() { SWGFreqTrackerSettings::getAlphaEma() {
return alpha_ema; return alpha_ema;
} }
void void
SWGFreqTrackerSettings::setAlphaEma(qint32 alpha_ema) { SWGFreqTrackerSettings::setAlphaEma(float alpha_ema) {
this->alpha_ema = alpha_ema; this->alpha_ema = alpha_ema;
this->m_alpha_ema_isSet = true; this->m_alpha_ema_isSet = true;
} }
@ -367,6 +377,16 @@ SWGFreqTrackerSettings::setRrcRolloff(qint32 rrc_rolloff) {
this->m_rrc_rolloff_isSet = true; this->m_rrc_rolloff_isSet = true;
} }
qint32
SWGFreqTrackerSettings::getSquelchGate() {
return squelch_gate;
}
void
SWGFreqTrackerSettings::setSquelchGate(qint32 squelch_gate) {
this->squelch_gate = squelch_gate;
this->m_squelch_gate_isSet = true;
}
qint32 qint32
SWGFreqTrackerSettings::getUseReverseApi() { SWGFreqTrackerSettings::getUseReverseApi() {
return use_reverse_api; return use_reverse_api;
@ -434,6 +454,7 @@ SWGFreqTrackerSettings::isSet(){
if(m_pll_psk_order_isSet){ isObjectUpdated = true; break;} if(m_pll_psk_order_isSet){ isObjectUpdated = true; break;}
if(m_rrc_isSet){ isObjectUpdated = true; break;} if(m_rrc_isSet){ isObjectUpdated = true; break;}
if(m_rrc_rolloff_isSet){ isObjectUpdated = true; break;} if(m_rrc_rolloff_isSet){ isObjectUpdated = true; break;}
if(m_squelch_gate_isSet){ isObjectUpdated = true; break;}
if(m_use_reverse_api_isSet){ isObjectUpdated = true; break;} if(m_use_reverse_api_isSet){ isObjectUpdated = true; break;}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ isObjectUpdated = true; break;} if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ isObjectUpdated = true; break;}
if(m_reverse_api_port_isSet){ isObjectUpdated = true; break;} if(m_reverse_api_port_isSet){ isObjectUpdated = true; break;}

View File

@ -60,8 +60,8 @@ public:
QString* getTitle(); QString* getTitle();
void setTitle(QString* title); void setTitle(QString* title);
qint32 getAlphaEma(); float getAlphaEma();
void setAlphaEma(qint32 alpha_ema); void setAlphaEma(float alpha_ema);
qint32 getTracking(); qint32 getTracking();
void setTracking(qint32 tracking); void setTracking(qint32 tracking);
@ -78,6 +78,9 @@ public:
qint32 getRrcRolloff(); qint32 getRrcRolloff();
void setRrcRolloff(qint32 rrc_rolloff); void setRrcRolloff(qint32 rrc_rolloff);
qint32 getSquelchGate();
void setSquelchGate(qint32 squelch_gate);
qint32 getUseReverseApi(); qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api); void setUseReverseApi(qint32 use_reverse_api);
@ -115,7 +118,7 @@ private:
QString* title; QString* title;
bool m_title_isSet; bool m_title_isSet;
qint32 alpha_ema; float alpha_ema;
bool m_alpha_ema_isSet; bool m_alpha_ema_isSet;
qint32 tracking; qint32 tracking;
@ -133,6 +136,9 @@ private:
qint32 rrc_rolloff; qint32 rrc_rolloff;
bool m_rrc_rolloff_isSet; bool m_rrc_rolloff_isSet;
qint32 squelch_gate;
bool m_squelch_gate_isSet;
qint32 use_reverse_api; qint32 use_reverse_api;
bool m_use_reverse_api_isSet; bool m_use_reverse_api_isSet;