1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-05-23 08:37:06 -04:00

Freq scanner: implemented device frequency locking

This commit is contained in:
f4exb 2026-02-21 03:17:15 +01:00
parent ceb602283a
commit 98c703bfbf
6 changed files with 148 additions and 50 deletions

View File

@ -314,7 +314,7 @@ void FreqScanner::initScan()
// }
mute(m_scanDeviceSetIndex, m_scanChannelIndex);
if (m_centerFrequency != m_stepStartFrequency) {
if (!m_settings.m_lockDeviceFrequency && (m_centerFrequency != m_stepStartFrequency)) {
setDeviceCenterFrequency(m_stepStartFrequency);
}
@ -386,54 +386,77 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
}
// Calculate next center frequency
bool complete = false; // Have all frequencies been scanned?
bool freqInRange = false;
const bool lockDeviceFrequency = m_settings.m_lockDeviceFrequency;
const qint64 currentCenterFrequency = m_centerFrequency;
bool complete = lockDeviceFrequency; // Have all frequencies been scanned?
bool freqInRange = lockDeviceFrequency;
qint64 nextCenterFrequency = m_centerFrequency;
int usableBW = (m_scannerSampleRate * 3 / 4) & ~1;
int nextFrequencyIndex = 0;
do
int nextFrequencyIndex = -1;
const auto isInCurrentScanRange = [currentCenterFrequency, usableBW](qint64 frequency)
{
if (nextCenterFrequency + usableBW / 2 > m_stepStopFrequency)
{
nextCenterFrequency = m_stepStartFrequency;
complete = true;
}
else
{
nextCenterFrequency += usableBW;
complete = false;
}
return (frequency >= currentCenterFrequency - usableBW / 2)
&& (frequency < currentCenterFrequency + usableBW / 2);
};
// Are any frequencies in this new range?
if (!lockDeviceFrequency)
{
do
{
if (nextCenterFrequency + usableBW / 2 > m_stepStopFrequency)
{
nextCenterFrequency = m_stepStartFrequency;
complete = true;
}
else
{
nextCenterFrequency += usableBW;
complete = false;
}
// Are any frequencies in this new range?
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
{
if (m_settings.m_frequencySettings[i].m_enabled
&& (m_settings.m_frequencySettings[i].m_frequency >= nextCenterFrequency - usableBW / 2)
&& (m_settings.m_frequencySettings[i].m_frequency < nextCenterFrequency + usableBW / 2))
{
freqInRange = true;
nextFrequencyIndex = i;
// Do we need to realign for frequencies with wider bandwidths than default
if (!m_settings.m_frequencySettings[i].m_channelBandwidth.isEmpty())
{
bool ok;
int channelBW = m_settings.m_frequencySettings[i].m_channelBandwidth.toInt(&ok);
if (ok)
{
if (channelBW >= usableBW) {
nextCenterFrequency = m_settings.m_frequencySettings[i].m_frequency;
} else if (m_settings.m_frequencySettings[i].m_frequency - channelBW / 2 < nextCenterFrequency - usableBW / 2) {
nextCenterFrequency = m_settings.m_frequencySettings[i].m_frequency - channelBW / 2;
}
}
}
break;
}
}
}
while (!complete && !freqInRange);
}
else
{
for (int i = 0; i < m_settings.m_frequencySettings.size(); i++)
{
if (m_settings.m_frequencySettings[i].m_enabled
&& (m_settings.m_frequencySettings[i].m_frequency >= nextCenterFrequency - usableBW / 2)
&& (m_settings.m_frequencySettings[i].m_frequency < nextCenterFrequency + usableBW / 2))
&& isInCurrentScanRange(m_settings.m_frequencySettings[i].m_frequency))
{
freqInRange = true;
nextFrequencyIndex = i;
// Do we need to realign for frequencies with wider bandwidths than default
if (!m_settings.m_frequencySettings[i].m_channelBandwidth.isEmpty())
{
bool ok;
int channelBW = m_settings.m_frequencySettings[i].m_channelBandwidth.toInt(&ok);
if (ok)
{
if (channelBW >= usableBW) {
nextCenterFrequency = m_settings.m_frequencySettings[i].m_frequency;
} else if (m_settings.m_frequencySettings[i].m_frequency - channelBW / 2 < nextCenterFrequency - usableBW / 2) {
nextCenterFrequency = m_settings.m_frequencySettings[i].m_frequency - channelBW / 2;
}
}
}
break;
}
}
}
while (!complete && !freqInRange);
if (complete || (m_settings.m_mode == FreqScannerSettings::MULTIPLEX))
{
@ -454,8 +477,11 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
if (m_settings.m_mode == FreqScannerSettings::MULTIPLEX)
{
activeFrequencySettings = &m_settings.m_frequencySettings[nextFrequencyIndex];
frequency = activeFrequencySettings->m_frequency;
if (nextFrequencyIndex >= 0)
{
activeFrequencySettings = &m_settings.m_frequencySettings[nextFrequencyIndex];
frequency = activeFrequencySettings->m_frequency;
}
}
else if (m_settings.m_priority == FreqScannerSettings::MAX_POWER)
{
@ -464,6 +490,10 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
// Find frequency with max power that exceeds thresholds
for (int i = 0; i < m_scanResults.size(); i++)
{
if (lockDeviceFrequency && !isInCurrentScanRange(m_scanResults[i].m_frequency)) {
continue;
}
frequencySettings = m_settings.getFrequencySettings(m_scanResults[i].m_frequency);
Real threshold = m_settings.getThreshold(frequencySettings);
@ -486,6 +516,11 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
{
int j = m_settings.m_voiceSquelchType == FreqScannerSettings::VoiceSquelchType::VoiceLsb ?
m_scanResults.size()-1 - i : i;
if (lockDeviceFrequency && !isInCurrentScanRange(m_scanResults[j].m_frequency)) {
continue;
}
frequencySettings = m_settings.getFrequencySettings(m_scanResults[j].m_frequency);
Real threshold = m_settings.getThreshold(frequencySettings);
@ -520,20 +555,23 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
}
// Ensure we have minimum offset from DC
if (offset >= 0)
if (!lockDeviceFrequency)
{
while (offset < m_settings.m_channelFrequencyOffset)
if (offset >= 0)
{
nextCenterFrequency -= m_settings.m_channelBandwidth;
offset += m_settings.m_channelBandwidth;
while (offset < m_settings.m_channelFrequencyOffset)
{
nextCenterFrequency -= m_settings.m_channelBandwidth;
offset += m_settings.m_channelBandwidth;
}
}
}
else
{
while (abs(offset) < m_settings.m_channelFrequencyOffset)
else
{
nextCenterFrequency += m_settings.m_channelBandwidth;
offset -= m_settings.m_channelBandwidth;
while (abs(offset) < m_settings.m_channelFrequencyOffset)
{
nextCenterFrequency += m_settings.m_channelBandwidth;
offset -= m_settings.m_channelBandwidth;
}
}
}
@ -599,7 +637,12 @@ void FreqScanner::processScanResults(const QDateTime& fftStartTime, const QList<
}
}
if (nextCenterFrequency != m_centerFrequency) {
if (m_settings.m_lockDeviceFrequency) {
nextCenterFrequency = m_centerFrequency;
}
if (nextCenterFrequency != m_centerFrequency)
{
setDeviceCenterFrequency(nextCenterFrequency);
}

View File

@ -197,6 +197,8 @@ bool FreqScannerGUI::handleMessage(const Message& message)
int row = item->row();
QTableWidgetItem* powerItem = ui->table->item(row, COL_POWER);
powerItem->setData(Qt::DisplayRole, results[i].m_power);
QTableWidgetItem* vadItem = ui->table->item(row, COL_VAD);
vadItem->setData(Qt::DisplayRole, results[i].m_voiceActivityLevel);
FreqScannerSettings::FrequencySettings *frequencySettings = m_settings.getFrequencySettings(freq);
Real threshold = m_settings.getThreshold(frequencySettings);
bool active = results[i].m_power >= threshold;
@ -405,6 +407,12 @@ void FreqScannerGUI::on_voiceSquelchType_currentIndexChanged(int index)
applySettings(settingsKeys);
}
void FreqScannerGUI::on_lockDeviceFrequency_toggled(bool checked)
{
m_settings.m_lockDeviceFrequency = checked;
applySetting("lockDeviceFrequency");
}
void FreqScannerGUI::on_priority_currentIndexChanged(int index)
{
m_settings.m_priority = (FreqScannerSettings::Priority)index;
@ -584,6 +592,7 @@ FreqScannerGUI::FreqScannerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
ui->table->setItemDelegateForColumn(COL_FREQUENCY, new FrequencyDelegate("Auto", 3, true, ui->table));
ui->table->setItemDelegateForColumn(COL_POWER, new DecimalDelegate(1, ui->table));
ui->table->setItemDelegateForColumn(COL_VAD, new DecimalDelegate(2, ui->table));
ui->table->setItemDelegateForColumn(COL_CHANNEL_BW, new Int64Delegate(0, 10000000, ui->table));
ui->table->setItemDelegateForColumn(COL_TH, new DecimalDelegate(1, -120.0, 0.0, ui->table));
ui->table->setItemDelegateForColumn(COL_SQ, new DecimalDelegate(1, -120.0, 0.0, ui->table));
@ -641,6 +650,7 @@ void FreqScannerGUI::displaySettings()
ui->channels->setCurrentIndex(channelIndex);
}
ui->deltaFrequency->setValue(m_settings.m_channelFrequencyOffset);
ui->deviceFreqLock->setChecked(m_settings.m_lockDeviceFrequency);
ui->channelBandwidth->setValue(m_settings.m_channelBandwidth);
ui->channelShift->setValue(m_settings.m_channelShift);
ui->scanTime->setValue(m_settings.m_scanTime * 10.0);
@ -740,6 +750,10 @@ void FreqScannerGUI::addRow(const FreqScannerSettings::FrequencySettings& freque
powerItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->table->setItem(row, COL_POWER, powerItem);
QTableWidgetItem* vadItem = new QTableWidgetItem();
vadItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->table->setItem(row, COL_VAD, vadItem);
QTableWidgetItem *activeCountItem = new QTableWidgetItem();
activeCountItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
ui->table->setItem(row, COL_ACTIVE_COUNT, activeCountItem);
@ -1296,6 +1310,7 @@ void FreqScannerGUI::resizeTable()
ui->table->setItem(row, COL_ANNOTATION, new QTableWidgetItem("London VOLMET"));
ui->table->setItem(row, COL_ENABLE, new QTableWidgetItem("Enable"));
ui->table->setItem(row, COL_POWER, new QTableWidgetItem("-100.0"));
ui->table->setItem(row, COL_VAD, new QTableWidgetItem("0.00"));
ui->table->setItem(row, COL_ACTIVE_COUNT, new QTableWidgetItem("10000"));
ui->table->setItem(row, COL_NOTES, new QTableWidgetItem("A channel name"));
ui->table->setItem(row, COL_CHANNEL, new QTableWidgetItem("Enter some notes"));
@ -1318,6 +1333,7 @@ void FreqScannerGUI::makeUIConnections()
QObject::connect(ui->thresh, &QDial::valueChanged, this, &FreqScannerGUI::on_thresh_valueChanged);
QObject::connect(ui->voiceSquelch, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_voiceSquelchType_currentIndexChanged);
QObject::connect(ui->voiceThreshold, &QDial::valueChanged, this, &FreqScannerGUI::on_voiceThreshold_valueChanged);
QObject::connect(ui->deviceFreqLock, &QToolButton::toggled, this, &FreqScannerGUI::on_lockDeviceFrequency_toggled);
QObject::connect(ui->priority, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_priority_currentIndexChanged);
QObject::connect(ui->measurement, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_measurement_currentIndexChanged);
QObject::connect(ui->mode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FreqScannerGUI::on_mode_currentIndexChanged);

View File

@ -115,6 +115,7 @@ private:
COL_ANNOTATION,
COL_ENABLE,
COL_POWER,
COL_VAD,
COL_ACTIVE_COUNT,
COL_NOTES,
COL_CHANNEL,
@ -134,6 +135,7 @@ private slots:
void on_thresh_valueChanged(int value);
void on_voiceThreshold_valueChanged(int value);
void on_voiceSquelchType_currentIndexChanged(int index);
void on_lockDeviceFrequency_toggled(bool checked);
void on_priority_currentIndexChanged(int index);
void on_measurement_currentIndexChanged(int index);
void on_mode_currentIndexChanged(int index);

View File

@ -157,6 +157,24 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="deviceFreqLock">
<property name="toolTip">
<string>Lock device frequency to current value</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/unlocked.png</normaloff>
<normalon>:/locked.png</normalon>:/unlocked.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
@ -302,7 +320,7 @@
<number>0</number>
</property>
<property name="maximum">
<number>2000</number>
<number>1000</number>
</property>
<property name="pageStep">
<number>1</number>
@ -795,6 +813,14 @@
<string>Channel power in decibels during the previous scan</string>
</property>
</column>
<column>
<property name="text">
<string>VAD</string>
</property>
<property name="toolTip">
<string>Voice level</string>
</property>
</column>
<column>
<property name="text">
<string>Active Count</string>

View File

@ -48,6 +48,7 @@ void FreqScannerSettings::resetToDefaults()
m_tuneTime = 100;
m_voiceSquelchThreshold = 0.5f;
m_voiceSquelchType = None;
m_lockDeviceFrequency = false;
m_priority = MAX_POWER;
m_measurement = PEAK;
m_mode = CONTINUOUS;
@ -89,6 +90,7 @@ QByteArray FreqScannerSettings::serialize() const
s.writeS32(14, (int)m_mode);
s.writeList(15, m_frequencySettings);
s.writeS32(16, m_channelShift);
s.writeBool(17, m_lockDeviceFrequency);
s.writeList(20, m_columnIndexes);
s.writeList(21, m_columnSizes);
@ -145,6 +147,7 @@ bool FreqScannerSettings::deserialize(const QByteArray& data)
d.readS32(14, (int*)&m_mode, (int)CONTINUOUS);
d.readList(15, &m_frequencySettings);
d.readS32(16, &m_channelShift, 0);
d.readBool(17, &m_lockDeviceFrequency, false);
if (m_frequencySettings.size() == 0)
{
@ -234,6 +237,9 @@ void FreqScannerSettings::applySettings(const QStringList& settingsKeys, const F
if (settingsKeys.contains("voiceSquelchType")) {
m_voiceSquelchType = settings.m_voiceSquelchType;
}
if (settingsKeys.contains("lockDeviceFrequency")) {
m_lockDeviceFrequency = settings.m_lockDeviceFrequency;
}
if (settingsKeys.contains("frequencySettings")) {
m_frequencySettings = settings.m_frequencySettings;
}
@ -321,6 +327,9 @@ QString FreqScannerSettings::getDebugString(const QStringList& settingsKeys, boo
if (settingsKeys.contains("voiceSquelchType") || force) {
ostr << " m_voiceSquelchType: " << m_voiceSquelchType;
}
if (settingsKeys.contains("lockDeviceFrequency") || force) {
ostr << " m_lockDeviceFrequency: " << m_lockDeviceFrequency;
}
if (settingsKeys.contains("frequencySettings") || force)
{
QStringList s;

View File

@ -74,6 +74,8 @@ struct FreqScannerSettings
SCAN_ONLY,
MULTIPLEX
} m_mode; //!< Whether to run a single or many scans
bool m_lockDeviceFrequency; //!< Whether to lock device frequency to the initial center frequency of the first scan,
//!< or allow it to be shifted by the channel shift setting
QList<int> m_columnIndexes;//!< How the columns are ordered in the table
QList<int> m_columnSizes; //!< Size of the coumns in the table