mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 01:39:05 -05:00
Local Sink: FFT filter bands
This commit is contained in:
parent
4d1ab5d413
commit
bf765a00ec
@ -76,6 +76,7 @@ bool LocalSinkGUI::handleMessage(const Message& message)
|
|||||||
m_basebandSampleRate = notif.getSampleRate();
|
m_basebandSampleRate = notif.getSampleRate();
|
||||||
updateAbsoluteCenterFrequency();
|
updateAbsoluteCenterFrequency();
|
||||||
displayRateAndShift();
|
displayRateAndShift();
|
||||||
|
displayFFTBand();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (LocalSink::MsgConfigureLocalSink::match(message))
|
else if (LocalSink::MsgConfigureLocalSink::match(message))
|
||||||
@ -106,6 +107,8 @@ LocalSinkGUI::LocalSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
|
|||||||
ui(new Ui::LocalSinkGUI),
|
ui(new Ui::LocalSinkGUI),
|
||||||
m_pluginAPI(pluginAPI),
|
m_pluginAPI(pluginAPI),
|
||||||
m_deviceUISet(deviceUISet),
|
m_deviceUISet(deviceUISet),
|
||||||
|
m_currentBandIndex(-1),
|
||||||
|
m_showFilterHighCut(false),
|
||||||
m_deviceCenterFrequency(0),
|
m_deviceCenterFrequency(0),
|
||||||
m_basebandSampleRate(0),
|
m_basebandSampleRate(0),
|
||||||
m_tickCount(0)
|
m_tickCount(0)
|
||||||
@ -194,9 +197,15 @@ void LocalSinkGUI::displaySettings()
|
|||||||
ui->localDevicePlay->setChecked(m_settings.m_play);
|
ui->localDevicePlay->setChecked(m_settings.m_play);
|
||||||
ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim);
|
ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim);
|
||||||
ui->dsp->setChecked(m_settings.m_dsp);
|
ui->dsp->setChecked(m_settings.m_dsp);
|
||||||
|
ui->gain->setValue(m_settings.m_gaindB);
|
||||||
ui->gainText->setText(tr("%1").arg(m_settings.m_gaindB));
|
ui->gainText->setText(tr("%1").arg(m_settings.m_gaindB));
|
||||||
|
ui->fft->setChecked(m_settings.m_fftOn);
|
||||||
|
ui->fftSize->setCurrentIndex(m_settings.m_log2FFT-6);
|
||||||
|
ui->fftWindow->setCurrentIndex((int) m_settings.m_fftWindow);
|
||||||
|
ui->filterF2orW->setChecked(m_showFilterHighCut);
|
||||||
applyDecimation();
|
applyDecimation();
|
||||||
updateIndexLabel();
|
updateIndexLabel();
|
||||||
|
displayFFTBand(false);
|
||||||
|
|
||||||
getRollupContents()->restoreState(m_rollupState);
|
getRollupContents()->restoreState(m_rollupState);
|
||||||
blockApplySettings(false);
|
blockApplySettings(false);
|
||||||
@ -215,6 +224,51 @@ void LocalSinkGUI::displayRateAndShift()
|
|||||||
m_channelMarker.setBandwidth(channelSampleRate);
|
m_channelMarker.setBandwidth(channelSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::displayFFTBand(bool blockApplySettings)
|
||||||
|
{
|
||||||
|
if (blockApplySettings) {
|
||||||
|
this->blockApplySettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->bandIndex->setMaximum(m_settings.m_fftBands.size() != 0 ? m_settings.m_fftBands.size() - 1 : 0);
|
||||||
|
ui->bandIndex->setEnabled(m_settings.m_fftBands.size() != 0);
|
||||||
|
ui->f1->setEnabled(m_settings.m_fftBands.size() != 0);
|
||||||
|
ui->bandWidth->setEnabled(m_settings.m_fftBands.size() != 0);
|
||||||
|
|
||||||
|
if ((m_settings.m_fftBands.size() != 0) && (m_currentBandIndex < 0)) {
|
||||||
|
m_currentBandIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_currentBandIndex >= 0)
|
||||||
|
{
|
||||||
|
ui->bandIndex->setValue(m_currentBandIndex);
|
||||||
|
m_currentBandIndex = ui->bandIndex->value();
|
||||||
|
ui->bandIndexText->setText(tr("%1").arg(m_currentBandIndex));
|
||||||
|
ui->f1->setValue(m_settings.m_fftBands[m_currentBandIndex].first*1000);
|
||||||
|
ui->bandWidth->setValue(m_settings.m_fftBands[m_currentBandIndex].second*1000);
|
||||||
|
double channelSampleRate = ((double) m_basebandSampleRate) / (1<<m_settings.m_log2Decim);
|
||||||
|
double f1 = (m_settings.m_fftBands[m_currentBandIndex].first)*channelSampleRate;
|
||||||
|
double w = (m_settings.m_fftBands[m_currentBandIndex].second)*channelSampleRate;
|
||||||
|
ui->f1Text->setText(displayScaled(f1, 5));
|
||||||
|
|
||||||
|
if (m_showFilterHighCut)
|
||||||
|
{
|
||||||
|
ui->bandwidthText->setToolTip("Filter high cut frequency");
|
||||||
|
double f2 = f1 + w;
|
||||||
|
ui->bandwidthText->setText(displayScaled(f2, 5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->bandwidthText->setToolTip("Filter width");
|
||||||
|
ui->bandwidthText->setText(displayScaled(w, 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockApplySettings) {
|
||||||
|
this->blockApplySettings(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int LocalSinkGUI::getLocalDeviceIndexInCombo(int localDeviceIndex)
|
int LocalSinkGUI::getLocalDeviceIndexInCombo(int localDeviceIndex)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@ -363,6 +417,75 @@ void LocalSinkGUI::on_gain_valueChanged(int value)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_fft_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_settings.m_fftOn = checked;
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_fftBandAdd_clicked()
|
||||||
|
{
|
||||||
|
if (m_settings.m_fftBands.size() == m_settings.m_maxFFTBands) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings.m_fftBands.push_back(std::pair<float,float>{-0.1f, 0.2f});
|
||||||
|
m_currentBandIndex = m_settings.m_fftBands.size()-1;
|
||||||
|
displayFFTBand();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_fftBandDel_clicked()
|
||||||
|
{
|
||||||
|
m_settings.m_fftBands.erase(m_settings.m_fftBands.begin() + m_currentBandIndex);
|
||||||
|
m_currentBandIndex--;
|
||||||
|
displayFFTBand();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_bandIndex_valueChanged(int value)
|
||||||
|
{
|
||||||
|
ui->bandIndexText->setText(tr("%1").arg(value));
|
||||||
|
m_currentBandIndex = value;
|
||||||
|
displayFFTBand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_f1_valueChanged(int value)
|
||||||
|
{
|
||||||
|
float f1 = value / 1000.0f;
|
||||||
|
m_settings.m_fftBands[m_currentBandIndex].first = f1;
|
||||||
|
float maxWidth = 0.5f - f1;
|
||||||
|
|
||||||
|
if (m_settings.m_fftBands[m_currentBandIndex].second > maxWidth) {
|
||||||
|
m_settings.m_fftBands[m_currentBandIndex].second = maxWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayFFTBand();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_bandWidth_valueChanged(int value)
|
||||||
|
{
|
||||||
|
float w = value / 1000.0f;
|
||||||
|
const float& f1 = m_settings.m_fftBands[m_currentBandIndex].first;
|
||||||
|
float maxWidth = 0.5f - f1;
|
||||||
|
|
||||||
|
if (w > maxWidth) {
|
||||||
|
m_settings.m_fftBands[m_currentBandIndex].second = maxWidth;
|
||||||
|
} else {
|
||||||
|
m_settings.m_fftBands[m_currentBandIndex].second = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayFFTBand();
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalSinkGUI::on_filterF2orW_toggled(bool checked)
|
||||||
|
{
|
||||||
|
m_showFilterHighCut = checked;
|
||||||
|
displayFFTBand();
|
||||||
|
}
|
||||||
|
|
||||||
void LocalSinkGUI::applyDecimation()
|
void LocalSinkGUI::applyDecimation()
|
||||||
{
|
{
|
||||||
uint32_t maxHash = 1;
|
uint32_t maxHash = 1;
|
||||||
@ -386,6 +509,7 @@ void LocalSinkGUI::applyPosition()
|
|||||||
|
|
||||||
updateAbsoluteCenterFrequency();
|
updateAbsoluteCenterFrequency();
|
||||||
displayRateAndShift();
|
displayRateAndShift();
|
||||||
|
displayFFTBand();
|
||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +527,14 @@ void LocalSinkGUI::makeUIConnections()
|
|||||||
QObject::connect(ui->localDevice, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_localDevice_currentIndexChanged);
|
QObject::connect(ui->localDevice, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_localDevice_currentIndexChanged);
|
||||||
QObject::connect(ui->localDevicePlay, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_localDevicePlay_toggled);
|
QObject::connect(ui->localDevicePlay, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_localDevicePlay_toggled);
|
||||||
QObject::connect(ui->dsp, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_dsp_toggled);
|
QObject::connect(ui->dsp, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_dsp_toggled);
|
||||||
QObject::connect(ui->gain, &QSlider::valueChanged, this, &LocalSinkGUI::on_gain_valueChanged);
|
QObject::connect(ui->gain, &QDial::valueChanged, this, &LocalSinkGUI::on_gain_valueChanged);
|
||||||
|
QObject::connect(ui->fft, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_fft_toggled);
|
||||||
|
QObject::connect(ui->fftBandAdd, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandAdd_clicked);
|
||||||
|
QObject::connect(ui->fftBandDel, &QPushButton::clicked, this, &LocalSinkGUI::on_fftBandDel_clicked);
|
||||||
|
QObject::connect(ui->bandIndex, &QSlider::valueChanged, this, &LocalSinkGUI::on_bandIndex_valueChanged);
|
||||||
|
QObject::connect(ui->f1, &QDial::valueChanged, this, &LocalSinkGUI::on_f1_valueChanged);
|
||||||
|
QObject::connect(ui->bandWidth, &QDial::valueChanged, this, &LocalSinkGUI::on_bandWidth_valueChanged);
|
||||||
|
QObject::connect(ui->filterF2orW, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_filterF2orW_toggled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalSinkGUI::updateAbsoluteCenterFrequency()
|
void LocalSinkGUI::updateAbsoluteCenterFrequency()
|
||||||
@ -411,3 +542,20 @@ void LocalSinkGUI::updateAbsoluteCenterFrequency()
|
|||||||
int shift = m_shiftFrequencyFactor * m_basebandSampleRate;
|
int shift = m_shiftFrequencyFactor * m_basebandSampleRate;
|
||||||
setStatusFrequency(m_deviceCenterFrequency + shift);
|
setStatusFrequency(m_deviceCenterFrequency + shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString LocalSinkGUI::displayScaled(int64_t value, int precision)
|
||||||
|
{
|
||||||
|
int64_t posValue = (value < 0) ? -value : value;
|
||||||
|
|
||||||
|
if (posValue < 1000) {
|
||||||
|
return tr("%1").arg(QString::number(value, 'g', precision));
|
||||||
|
} else if (posValue < 1000000) {
|
||||||
|
return tr("%1k").arg(QString::number(value / 1000.0, 'g', precision));
|
||||||
|
} else if (posValue < 1000000000) {
|
||||||
|
return tr("%1M").arg(QString::number(value / 1000000.0, 'g', precision));
|
||||||
|
} else if (posValue < 1000000000000) {
|
||||||
|
return tr("%1%2").arg(QString::number(value / 1000000000.0, 'g', precision)).arg("G");
|
||||||
|
} else {
|
||||||
|
return tr("%1").arg(QString::number(value, 'e', precision));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -68,6 +68,8 @@ private:
|
|||||||
ChannelMarker m_channelMarker;
|
ChannelMarker m_channelMarker;
|
||||||
RollupState m_rollupState;
|
RollupState m_rollupState;
|
||||||
LocalSinkSettings m_settings;
|
LocalSinkSettings m_settings;
|
||||||
|
int m_currentBandIndex;
|
||||||
|
bool m_showFilterHighCut;
|
||||||
qint64 m_deviceCenterFrequency;
|
qint64 m_deviceCenterFrequency;
|
||||||
int m_basebandSampleRate;
|
int m_basebandSampleRate;
|
||||||
double m_shiftFrequencyFactor; //!< Channel frequency shift factor
|
double m_shiftFrequencyFactor; //!< Channel frequency shift factor
|
||||||
@ -86,11 +88,13 @@ private:
|
|||||||
void applySettings(bool force = false);
|
void applySettings(bool force = false);
|
||||||
void displaySettings();
|
void displaySettings();
|
||||||
void displayRateAndShift();
|
void displayRateAndShift();
|
||||||
|
void displayFFTBand(bool blockApplySettings = true);
|
||||||
bool handleMessage(const Message& message);
|
bool handleMessage(const Message& message);
|
||||||
void makeUIConnections();
|
void makeUIConnections();
|
||||||
void updateAbsoluteCenterFrequency();
|
void updateAbsoluteCenterFrequency();
|
||||||
void updateDeviceSetList(const QList<int>& deviceSetIndexes);
|
void updateDeviceSetList(const QList<int>& deviceSetIndexes);
|
||||||
int getLocalDeviceIndexInCombo(int localDeviceIndex);
|
int getLocalDeviceIndexInCombo(int localDeviceIndex);
|
||||||
|
QString displayScaled(int64_t value, int precision);
|
||||||
|
|
||||||
void leaveEvent(QEvent*);
|
void leaveEvent(QEvent*);
|
||||||
void enterEvent(EnterEventType*);
|
void enterEvent(EnterEventType*);
|
||||||
@ -106,6 +110,13 @@ private slots:
|
|||||||
void on_localDevicePlay_toggled(bool checked);
|
void on_localDevicePlay_toggled(bool checked);
|
||||||
void on_dsp_toggled(bool checked);
|
void on_dsp_toggled(bool checked);
|
||||||
void on_gain_valueChanged(int value);
|
void on_gain_valueChanged(int value);
|
||||||
|
void on_fft_toggled(bool checked);
|
||||||
|
void on_fftBandAdd_clicked();
|
||||||
|
void on_fftBandDel_clicked();
|
||||||
|
void on_bandIndex_valueChanged(int value);
|
||||||
|
void on_f1_valueChanged(int value);
|
||||||
|
void on_bandWidth_valueChanged(int value);
|
||||||
|
void on_filterF2orW_toggled(bool checked);
|
||||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
void onMenuDialogCalled(const QPoint& p);
|
void onMenuDialogCalled(const QPoint& p);
|
||||||
void tick();
|
void tick();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>452</width>
|
<width>480</width>
|
||||||
<height>467</height>
|
<height>467</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>414</width>
|
<width>480</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>1</x>
|
<x>1</x>
|
||||||
<y>1</y>
|
<y>1</y>
|
||||||
<width>451</width>
|
<width>481</width>
|
||||||
<height>141</height>
|
<height>141</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -277,6 +277,12 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="localDevicePlay">
|
<widget class="ButtonSwitch" name="localDevicePlay">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Start/Stop processing</string>
|
<string>Start/Stop processing</string>
|
||||||
</property>
|
</property>
|
||||||
@ -292,6 +298,15 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="dsp">
|
<widget class="ButtonSwitch" name="dsp">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle DSP processing</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>DSP</string>
|
<string>DSP</string>
|
||||||
</property>
|
</property>
|
||||||
@ -353,6 +368,15 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="ButtonSwitch" name="fft">
|
<widget class="ButtonSwitch" name="fft">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle FFT filter</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>FFT</string>
|
<string>FFT</string>
|
||||||
</property>
|
</property>
|
||||||
@ -372,12 +396,6 @@
|
|||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>50</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>FFT size</string>
|
<string>FFT size</string>
|
||||||
</property>
|
</property>
|
||||||
@ -440,14 +458,8 @@
|
|||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>FFT filter window function</string>
|
<string>FFT filter bands window function</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeAdjustPolicy">
|
<property name="sizeAdjustPolicy">
|
||||||
<enum>QComboBox::AdjustToContents</enum>
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
@ -499,6 +511,22 @@
|
|||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ButtonSwitch" name="fftFilterReverse">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reverse filter bands (pass <-> cut)</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>R</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -517,9 +545,12 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="fftLayout">
|
<layout class="QHBoxLayout" name="fftLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="fftBandLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>FFT filter bands</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Band</string>
|
<string>FFT</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -551,6 +582,131 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="fftBandAddDel">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="fftBandAdd">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="palette">
|
||||||
|
<palette>
|
||||||
|
<active>
|
||||||
|
<colorrole role="ButtonText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>255</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</active>
|
||||||
|
<inactive>
|
||||||
|
<colorrole role="ButtonText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>255</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</inactive>
|
||||||
|
<disabled>
|
||||||
|
<colorrole role="ButtonText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>190</red>
|
||||||
|
<green>190</green>
|
||||||
|
<blue>190</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</disabled>
|
||||||
|
</palette>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Liberation Sans</family>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Add a new FFT band</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>+</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="fftBandDel">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>18</width>
|
||||||
|
<height>18</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="palette">
|
||||||
|
<palette>
|
||||||
|
<active>
|
||||||
|
<colorrole role="ButtonText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>255</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</active>
|
||||||
|
<inactive>
|
||||||
|
<colorrole role="ButtonText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>255</green>
|
||||||
|
<blue>255</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</inactive>
|
||||||
|
<disabled>
|
||||||
|
<colorrole role="ButtonText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>190</red>
|
||||||
|
<green>190</green>
|
||||||
|
<blue>190</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</disabled>
|
||||||
|
</palette>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Liberation Sans</family>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Remove current FFT band</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>-</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -572,17 +728,20 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>00</string>
|
<string>00</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="f1Label">
|
<widget class="QLabel" name="f1Label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>f1</string>
|
<string>F1</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDial" name="f1Bin">
|
<widget class="QDial" name="f1">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>24</width>
|
<width>24</width>
|
||||||
@ -596,13 +755,13 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Frequency limit #1 bin</string>
|
<string>Filter low cut frequency</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>0</number>
|
<number>-500</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>1023</number>
|
<number>500</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="pageStep">
|
<property name="pageStep">
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
@ -618,7 +777,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Frequency limit #1 frequency</string>
|
<string>Filter low cut frequency</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>100.00k</string>
|
<string>100.00k</string>
|
||||||
@ -636,14 +795,14 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="f2Label">
|
<widget class="QLabel" name="widthLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>f2</string>
|
<string>W</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDial" name="f2Bin">
|
<widget class="QDial" name="bandWidth">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>24</width>
|
<width>24</width>
|
||||||
@ -657,13 +816,13 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Frequency limit #2 bin</string>
|
<string>FFT band width</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>1023</number>
|
<number>1000</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="pageStep">
|
<property name="pageStep">
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
@ -671,7 +830,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="f2Text">
|
<widget class="QLabel" name="bandwidthText">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>50</width>
|
<width>50</width>
|
||||||
@ -679,7 +838,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Frequency limit #2 frequency</string>
|
<string>Filter width</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>100.00k</string>
|
<string>100.00k</string>
|
||||||
@ -689,6 +848,30 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="filterF2orW">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Filter width / high cut display toggle</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||||
|
<normaloff>:/arrow_2head_h.png</normaloff>
|
||||||
|
<normalon>:/arrow_down.png</normalon>:/arrow_2head_h.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
@ -40,6 +40,9 @@ void LocalSinkSettings::resetToDefaults()
|
|||||||
m_play = false;
|
m_play = false;
|
||||||
m_dsp = false;
|
m_dsp = false;
|
||||||
m_gaindB = 0;
|
m_gaindB = 0;
|
||||||
|
m_fftOn = false;
|
||||||
|
m_log2FFT = 10;
|
||||||
|
m_fftWindow = FFTWindow::Function::Bartlett;
|
||||||
m_streamIndex = 0;
|
m_streamIndex = 0;
|
||||||
m_useReverseAPI = false;
|
m_useReverseAPI = false;
|
||||||
m_reverseAPIAddress = "127.0.0.1";
|
m_reverseAPIAddress = "127.0.0.1";
|
||||||
@ -84,6 +87,23 @@ QByteArray LocalSinkSettings::serialize() const
|
|||||||
s.writeBlob(21, m_spectrumGUI->serialize());
|
s.writeBlob(21, m_spectrumGUI->serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.writeBool(22, m_fftOn);
|
||||||
|
s.writeU32(23, (int) m_fftWindow);
|
||||||
|
|
||||||
|
s.writeU32(99, m_fftBands.size());
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (auto fftBand : m_fftBands)
|
||||||
|
{
|
||||||
|
s.writeFloat(100 + 2*i, fftBand.first);
|
||||||
|
s.writeFloat(101 + 2*i, fftBand.second);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i == m_maxFFTBands) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return s.final();
|
return s.final();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +119,7 @@ bool LocalSinkSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
if(d.getVersion() == 1)
|
if(d.getVersion() == 1)
|
||||||
{
|
{
|
||||||
uint32_t tmp;
|
uint32_t utmp;
|
||||||
QString strtmp;
|
QString strtmp;
|
||||||
QByteArray bytetmp;
|
QByteArray bytetmp;
|
||||||
|
|
||||||
@ -115,20 +135,20 @@ bool LocalSinkSettings::deserialize(const QByteArray& data)
|
|||||||
d.readString(6, &m_title, "Local sink");
|
d.readString(6, &m_title, "Local sink");
|
||||||
d.readBool(7, &m_useReverseAPI, false);
|
d.readBool(7, &m_useReverseAPI, false);
|
||||||
d.readString(8, &m_reverseAPIAddress, "127.0.0.1");
|
d.readString(8, &m_reverseAPIAddress, "127.0.0.1");
|
||||||
d.readU32(9, &tmp, 0);
|
d.readU32(9, &utmp, 0);
|
||||||
|
|
||||||
if ((tmp > 1023) && (tmp < 65535)) {
|
if ((utmp > 1023) && (utmp < 65535)) {
|
||||||
m_reverseAPIPort = tmp;
|
m_reverseAPIPort = utmp;
|
||||||
} else {
|
} else {
|
||||||
m_reverseAPIPort = 8888;
|
m_reverseAPIPort = 8888;
|
||||||
}
|
}
|
||||||
|
|
||||||
d.readU32(10, &tmp, 0);
|
d.readU32(10, &utmp, 0);
|
||||||
m_reverseAPIDeviceIndex = tmp > 99 ? 99 : tmp;
|
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readU32(11, &tmp, 0);
|
d.readU32(11, &utmp, 0);
|
||||||
m_reverseAPIChannelIndex = tmp > 99 ? 99 : tmp;
|
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
|
||||||
d.readU32(12, &tmp, 0);
|
d.readU32(12, &utmp, 0);
|
||||||
m_log2Decim = tmp > 6 ? 6 : tmp;
|
m_log2Decim = utmp > 6 ? 6 : utmp;
|
||||||
d.readU32(13, &m_filterChainHash, 0);
|
d.readU32(13, &m_filterChainHash, 0);
|
||||||
d.readS32(14, &m_streamIndex, 0);
|
d.readS32(14, &m_streamIndex, 0);
|
||||||
|
|
||||||
@ -150,6 +170,24 @@ bool LocalSinkSettings::deserialize(const QByteArray& data)
|
|||||||
m_spectrumGUI->deserialize(bytetmp);
|
m_spectrumGUI->deserialize(bytetmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.readBool(22, &m_fftOn, false);
|
||||||
|
d.readU32(23, &utmp, 0);
|
||||||
|
m_fftWindow = (utmp > (uint32_t) FFTWindow::Function::BlackmanHarris7) ?
|
||||||
|
FFTWindow::Function::BlackmanHarris7 :
|
||||||
|
(FFTWindow::Function) utmp;
|
||||||
|
|
||||||
|
uint32_t nbBands;
|
||||||
|
d.readU32(99, &nbBands, 0);
|
||||||
|
m_fftBands.clear();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < std::min(nbBands, m_maxFFTBands); i++)
|
||||||
|
{
|
||||||
|
float f1, w;
|
||||||
|
d.readFloat(100 + 2*i, &f1, 0);
|
||||||
|
d.readFloat(101 + 2*i, &w, 0);
|
||||||
|
m_fftBands.push_back(std::pair<float, float>{f1, w});
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include "dsp/fftwindow.h"
|
||||||
|
|
||||||
class Serializable;
|
class Serializable;
|
||||||
|
|
||||||
struct LocalSinkSettings
|
struct LocalSinkSettings
|
||||||
@ -33,6 +35,11 @@ struct LocalSinkSettings
|
|||||||
bool m_play;
|
bool m_play;
|
||||||
bool m_dsp;
|
bool m_dsp;
|
||||||
int m_gaindB;
|
int m_gaindB;
|
||||||
|
bool m_fftOn;
|
||||||
|
uint32_t m_log2FFT;
|
||||||
|
FFTWindow::Function m_fftWindow;
|
||||||
|
static const uint32_t m_maxFFTBands = 20;
|
||||||
|
std::vector<std::pair<float, float>> m_fftBands;
|
||||||
int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
|
int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
|
||||||
bool m_useReverseAPI;
|
bool m_useReverseAPI;
|
||||||
QString m_reverseAPIAddress;
|
QString m_reverseAPIAddress;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "dsp/devicesamplesource.h"
|
#include "dsp/devicesamplesource.h"
|
||||||
#include "dsp/hbfilterchainconverter.h"
|
#include "dsp/hbfilterchainconverter.h"
|
||||||
#include "dsp/spectrumvis.h"
|
#include "dsp/spectrumvis.h"
|
||||||
|
#include "dsp/fftfilt.h"
|
||||||
#include "util/db.h"
|
#include "util/db.h"
|
||||||
|
|
||||||
#include "localsinkworker.h"
|
#include "localsinkworker.h"
|
||||||
@ -39,16 +40,49 @@ LocalSinkSink::LocalSinkSink() :
|
|||||||
m_deviceSampleRate(48000)
|
m_deviceSampleRate(48000)
|
||||||
{
|
{
|
||||||
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000));
|
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(4000000));
|
||||||
|
// m_fftFilter = new fftfilt(0.1f, 0.4f, 1<<m_settings.m_log2FFT);
|
||||||
|
m_fftFilter = new fftfilt(1<<m_settings.m_log2FFT);
|
||||||
applySettings(m_settings, true);
|
applySettings(m_settings, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalSinkSink::~LocalSinkSink()
|
LocalSinkSink::~LocalSinkSink()
|
||||||
{
|
{
|
||||||
|
delete m_fftFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalSinkSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
|
void LocalSinkSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
|
||||||
{
|
{
|
||||||
if (m_settings.m_dsp && (m_settings.m_gaindB != 0))
|
if (m_settings.m_dsp && m_settings.m_fftOn)
|
||||||
|
{
|
||||||
|
fftfilt::cmplx *rf;
|
||||||
|
int rf_out;
|
||||||
|
|
||||||
|
for (SampleVector::const_iterator it = begin; it != end; ++it)
|
||||||
|
{
|
||||||
|
Complex c(it->real(), it->imag());
|
||||||
|
rf_out = m_fftFilter->runFilt(c, &rf); // filter RF
|
||||||
|
|
||||||
|
if (rf_out > 0)
|
||||||
|
{
|
||||||
|
m_spectrumBuffer.resize(rf_out);
|
||||||
|
std::transform(
|
||||||
|
rf,
|
||||||
|
rf + rf_out,
|
||||||
|
m_spectrumBuffer.begin(),
|
||||||
|
[this](const fftfilt::cmplx& c) -> Sample {
|
||||||
|
return Sample(c.real()*m_gain, c.imag()*m_gain);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (m_running && m_deviceSource) {
|
||||||
|
m_deviceSource->getSampleFifo()->write(m_spectrumBuffer.begin(), m_spectrumBuffer.begin() + rf_out);
|
||||||
|
}
|
||||||
|
if (m_spectrumSink) {
|
||||||
|
m_spectrumSink->feed(m_spectrumBuffer.begin(), m_spectrumBuffer.begin() + rf_out, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_settings.m_dsp && (m_settings.m_gaindB != 0))
|
||||||
{
|
{
|
||||||
m_spectrumBuffer.resize(end - begin);
|
m_spectrumBuffer.resize(end - begin);
|
||||||
std::transform(
|
std::transform(
|
||||||
@ -74,11 +108,11 @@ void LocalSinkSink::feed(const SampleVector::const_iterator& begin, const Sample
|
|||||||
if (m_running && m_deviceSource) {
|
if (m_running && m_deviceSource) {
|
||||||
m_deviceSource->getSampleFifo()->write(begin, end);
|
m_deviceSource->getSampleFifo()->write(begin, end);
|
||||||
}
|
}
|
||||||
|
if (m_spectrumSink) {
|
||||||
|
m_spectrumSink->feed(begin, end, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_spectrumSink) {
|
|
||||||
m_spectrumSink->feed(begin, end, false);
|
|
||||||
}
|
|
||||||
// m_sampleFifo.write(begin, end);
|
// m_sampleFifo.write(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,12 +187,22 @@ void LocalSinkSink::applySettings(const LocalSinkSettings& settings, bool force)
|
|||||||
qDebug() << "LocalSinkSink::applySettings:"
|
qDebug() << "LocalSinkSink::applySettings:"
|
||||||
<< " m_localDeviceIndex: " << settings.m_localDeviceIndex
|
<< " m_localDeviceIndex: " << settings.m_localDeviceIndex
|
||||||
<< " m_streamIndex: " << settings.m_streamIndex
|
<< " m_streamIndex: " << settings.m_streamIndex
|
||||||
|
<< " m_dsp: " << settings.m_dsp
|
||||||
|
<< " m_gaindB: " << settings.m_gaindB
|
||||||
|
<< " m_fftOn: " << settings.m_fftOn
|
||||||
<< " force: " << force;
|
<< " force: " << force;
|
||||||
|
|
||||||
if ((settings.m_gaindB != m_settings.m_gaindB) || force) {
|
if ((settings.m_gaindB != m_settings.m_gaindB) || force) {
|
||||||
m_gain = CalcDb::powerFromdB(settings.m_gaindB/2.0); // Amplitude gain
|
m_gain = CalcDb::powerFromdB(settings.m_gaindB/2.0); // Amplitude gain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((settings.m_fftOn != m_settings.m_fftOn) || force)
|
||||||
|
{
|
||||||
|
if (settings.m_fftOn) {
|
||||||
|
m_fftFilter->create_filter(m_settings.m_fftBands, true, FFTWindow::Function::Rectangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
class DeviceSampleSource;
|
class DeviceSampleSource;
|
||||||
class LocalSinkWorker;
|
class LocalSinkWorker;
|
||||||
class SpectrumVis;
|
class SpectrumVis;
|
||||||
|
class fftfilt;
|
||||||
|
|
||||||
class LocalSinkSink : public QObject, public ChannelSampleSink {
|
class LocalSinkSink : public QObject, public ChannelSampleSink {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -54,6 +55,7 @@ private:
|
|||||||
SampleVector m_spectrumBuffer;
|
SampleVector m_spectrumBuffer;
|
||||||
bool m_running;
|
bool m_running;
|
||||||
float m_gain; //!< Amplitude gain
|
float m_gain; //!< Amplitude gain
|
||||||
|
fftfilt* m_fftFilter;
|
||||||
|
|
||||||
uint64_t m_centerFrequency;
|
uint64_t m_centerFrequency;
|
||||||
int64_t m_frequencyOffset;
|
int64_t m_frequencyOffset;
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -156,6 +157,87 @@ void fftfilt::create_filter(float f1, float f2, FFTWindow::Function wf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fftfilt::create_filter(const std::vector<std::pair<float, float>>& limits, bool pass, FFTWindow::Function wf)
|
||||||
|
{
|
||||||
|
// initialize the filter canvas
|
||||||
|
std::vector<int> canvas(flen, pass ? 0 : 1);
|
||||||
|
fftfilt::cmplx* xfilter = new fftfilt::cmplx[flen];
|
||||||
|
|
||||||
|
for (const auto& fs : limits)
|
||||||
|
{
|
||||||
|
const float& f1 = fs.first + 0.5;
|
||||||
|
const float& w = fs.second > 0.0 ? fs.second : 0.0;
|
||||||
|
const float& f2 = f1 + w;
|
||||||
|
|
||||||
|
for (int i = 0; i < flen; i++)
|
||||||
|
{
|
||||||
|
if (pass) // pass
|
||||||
|
{
|
||||||
|
if ((i >= f1*flen) && (i <= f2*flen)) {
|
||||||
|
canvas[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // reject
|
||||||
|
{
|
||||||
|
if ((i >= f1*flen) && (i <= f2*flen)) {
|
||||||
|
canvas[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<int,int>> indexes;
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < flen; i++)
|
||||||
|
{
|
||||||
|
if ((canvas[i] == 1) && (c == 0)) {
|
||||||
|
indexes.push_back(std::pair<int,int>{i, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((canvas[i] == 0) && (c == 1)) {
|
||||||
|
indexes.back().second = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfilter[i] = cmplx(canvas[i], 0);
|
||||||
|
c = canvas[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply window
|
||||||
|
for (const auto& wband : indexes)
|
||||||
|
{
|
||||||
|
FFTWindow fwin;
|
||||||
|
fwin.create(wf, wband.second - wband.first);
|
||||||
|
fwin.apply(&xfilter[wband.first]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rearrange
|
||||||
|
std::copy(&xfilter[flen2], &xfilter[flen-1], filter);
|
||||||
|
std::copy(&xfilter[0], &xfilter[flen2-1], &filter[flen2]);
|
||||||
|
|
||||||
|
|
||||||
|
// // normalize the output filter for unity gain
|
||||||
|
// float scale = 0, mag;
|
||||||
|
|
||||||
|
// for (int i = 0; i < flen2; i++)
|
||||||
|
// {
|
||||||
|
// mag = abs(filter[i]);
|
||||||
|
|
||||||
|
// if (mag > scale) {
|
||||||
|
// scale = mag;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (scale != 0)
|
||||||
|
// {
|
||||||
|
// for (int i = 0; i < flen; i++) {
|
||||||
|
// filter[i] /= scale;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
delete[] xfilter;
|
||||||
|
}
|
||||||
|
|
||||||
// Double the size of FFT used for equivalent SSB filter or assume FFT is half the size of the one used for SSB
|
// Double the size of FFT used for equivalent SSB filter or assume FFT is half the size of the one used for SSB
|
||||||
void fftfilt::create_dsb_filter(float f2, FFTWindow::Function wf)
|
void fftfilt::create_dsb_filter(float f2, FFTWindow::Function wf)
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,7 @@ public:
|
|||||||
// f1 < f2 ==> bandpass
|
// f1 < f2 ==> bandpass
|
||||||
// f1 > f2 ==> band reject
|
// f1 > f2 ==> band reject
|
||||||
void create_filter(float f1, float f2, FFTWindow::Function wf = FFTWindow::Blackman);
|
void create_filter(float f1, float f2, FFTWindow::Function wf = FFTWindow::Blackman);
|
||||||
|
void create_filter(const std::vector<std::pair<float, float>>& limits, bool pass = true, FFTWindow::Function wf = FFTWindow::Blackman);
|
||||||
void create_dsb_filter(float f2, FFTWindow::Function wf = FFTWindow::Blackman);
|
void create_dsb_filter(float f2, FFTWindow::Function wf = FFTWindow::Blackman);
|
||||||
void create_asym_filter(float fopp, float fin, FFTWindow::Function wf = FFTWindow::Blackman); //!< two different filters for in band and opposite band
|
void create_asym_filter(float fopp, float fin, FFTWindow::Function wf = FFTWindow::Blackman); //!< two different filters for in band and opposite band
|
||||||
void create_rrc_filter(float fb, float a); //!< root raised cosine. fb is half the band pass
|
void create_rrc_filter(float fb, float a); //!< root raised cosine. fb is half the band pass
|
||||||
|
BIN
sdrgui/resources/arrow_2head_h.png
Normal file
BIN
sdrgui/resources/arrow_2head_h.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 774 B |
@ -1,5 +1,6 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
|
<file>arrow_2head_h.png</file>
|
||||||
<file>truncate.png</file>
|
<file>truncate.png</file>
|
||||||
<file>caliper.png</file>
|
<file>caliper.png</file>
|
||||||
<file>flip_windows.png</file>
|
<file>flip_windows.png</file>
|
||||||
|
Loading…
Reference in New Issue
Block a user