1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-05-30 22:02:26 -04:00

Channel analyzer NG: implemented optional RRC filter

This commit is contained in:
f4exb 2018-05-22 02:20:36 +02:00
parent 1dcb84ef8f
commit 775a9775eb
8 changed files with 104 additions and 4 deletions

View File

@ -52,6 +52,7 @@ ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_inputSampleRate, m_settings.m_bandwidth / m_inputSampleRate, ssbFftLen); SSBFilter = new fftfilt(m_settings.m_lowCutoff / m_inputSampleRate, m_settings.m_bandwidth / m_inputSampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen); DSBFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen);
RRCFilter = new fftfilt(m_settings.m_bandwidth / m_inputSampleRate, 2*ssbFftLen);
m_corr = new fftcorr(8*ssbFftLen); // 8k for 4k effective samples m_corr = new fftcorr(8*ssbFftLen); // 8k for 4k effective samples
m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain
@ -72,6 +73,7 @@ ChannelAnalyzerNG::~ChannelAnalyzerNG()
delete m_channelizer; delete m_channelizer;
delete SSBFilter; delete SSBFilter;
delete DSBFilter; delete DSBFilter;
delete RRCFilter;
} }
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue, void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
@ -129,10 +131,17 @@ void ChannelAnalyzerNG::processOneSample(Complex& c, fftfilt::cmplx *sideband)
int n_out; int n_out;
int decim = 1<<m_settings.m_spanLog2; int decim = 1<<m_settings.m_spanLog2;
if (m_settings.m_ssb) { if (m_settings.m_ssb)
{
n_out = SSBFilter->runSSB(c, &sideband, m_usb); n_out = SSBFilter->runSSB(c, &sideband, m_usb);
} else { }
n_out = DSBFilter->runDSB(c, &sideband); else
{
if (m_settings.m_rrc) {
n_out = RRCFilter->runFilt(c, &sideband);
} else {
n_out = DSBFilter->runDSB(c, &sideband);
}
} }
for (int i = 0; i < n_out; i++) for (int i = 0; i < n_out; i++)
@ -293,6 +302,7 @@ void ChannelAnalyzerNG::setFilters(int sampleRate, float bandwidth, float lowCut
SSBFilter->create_filter(lowCutoff / sampleRate, bandwidth / sampleRate); SSBFilter->create_filter(lowCutoff / sampleRate, bandwidth / sampleRate);
DSBFilter->create_dsb_filter(bandwidth / sampleRate); DSBFilter->create_dsb_filter(bandwidth / sampleRate);
RRCFilter->create_rrc_filter(bandwidth / sampleRate, m_settings.m_rrcRolloff / 100.0);
} }
void ChannelAnalyzerNG::applySettings(const ChannelAnalyzerNGSettings& settings, bool force) void ChannelAnalyzerNG::applySettings(const ChannelAnalyzerNGSettings& settings, bool force)
@ -300,6 +310,8 @@ void ChannelAnalyzerNG::applySettings(const ChannelAnalyzerNGSettings& settings,
qDebug() << "ChannelAnalyzerNG::applySettings:" qDebug() << "ChannelAnalyzerNG::applySettings:"
<< " m_downSample: " << settings.m_downSample << " m_downSample: " << settings.m_downSample
<< " m_downSampleRate: " << settings.m_downSampleRate << " m_downSampleRate: " << settings.m_downSampleRate
<< " m_rcc: " << settings.m_rrc
<< " m_rrcRolloff: " << settings.m_rrcRolloff / 100.0
<< " m_bandwidth: " << settings.m_bandwidth << " m_bandwidth: " << settings.m_bandwidth
<< " m_lowCutoff: " << settings.m_lowCutoff << " m_lowCutoff: " << settings.m_lowCutoff
<< " m_spanLog2: " << settings.m_spanLog2 << " m_spanLog2: " << settings.m_spanLog2
@ -338,6 +350,14 @@ void ChannelAnalyzerNG::applySettings(const ChannelAnalyzerNGSettings& settings,
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
if ((settings.m_rrcRolloff != m_settings.m_rrcRolloff) || force)
{
float sampleRate = settings.m_downSample ? (float) settings.m_downSampleRate : (float) m_inputSampleRate;
m_settingsMutex.lock();
RRCFilter->create_rrc_filter(settings.m_bandwidth / sampleRate, settings.m_rrcRolloff / 100.0);
m_settingsMutex.unlock();
}
if ((settings.m_spanLog2 != m_settings.m_spanLog2) || force) if ((settings.m_spanLog2 != m_settings.m_spanLog2) || force)
{ {
int sampleRate = (settings.m_downSample ? settings.m_downSampleRate : m_inputSampleRate) / (1<<m_settings.m_spanLog2); int sampleRate = (settings.m_downSample ? settings.m_downSampleRate : m_inputSampleRate) / (1<<m_settings.m_spanLog2);

View File

@ -231,6 +231,7 @@ private:
fftfilt* SSBFilter; fftfilt* SSBFilter;
fftfilt* DSBFilter; fftfilt* DSBFilter;
fftfilt* RRCFilter;
fftcorr* m_corr; fftcorr* m_corr;
BasebandSampleSink* m_sampleSink; BasebandSampleSink* m_sampleSink;

View File

@ -114,6 +114,9 @@ void ChannelAnalyzerNGGUI::displaySettings()
ui->spanLog2->setCurrentIndex(m_settings.m_spanLog2); ui->spanLog2->setCurrentIndex(m_settings.m_spanLog2);
displayPLLSettings(); displayPLLSettings();
ui->signalSelect->setCurrentIndex((int) m_settings.m_inputType); ui->signalSelect->setCurrentIndex((int) m_settings.m_inputType);
ui->rrcFilter->setChecked(m_settings.m_rrc);
QString rolloffStr = QString::number(m_settings.m_rrcRolloff/100.0, 'f', 2);
ui->rrcRolloffText->setText(rolloffStr);
blockApplySettings(false); blockApplySettings(false);
} }
@ -291,6 +294,20 @@ void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(qint64 value)
applySettings(); applySettings();
} }
void ChannelAnalyzerNGGUI::on_rrcFilter_toggled(bool checked)
{
m_settings.m_rrc = checked;
applySettings();
}
void ChannelAnalyzerNGGUI::on_rrcRolloff_valueChanged(int value)
{
m_settings.m_rrcRolloff = value;
QString rolloffStr = QString::number(value/100.0, 'f', 2);
ui->rrcRolloffText->setText(rolloffStr);
applySettings();
}
void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value __attribute__((unused))) void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value __attribute__((unused)))
{ {
setFiltersUIBoundaries(); setFiltersUIBoundaries();

View File

@ -99,6 +99,8 @@ private slots:
void on_pllPskOrder_currentIndexChanged(int index); void on_pllPskOrder_currentIndexChanged(int index);
void on_useRationalDownsampler_toggled(bool checked); void on_useRationalDownsampler_toggled(bool checked);
void on_signalSelect_currentIndexChanged(int index); void on_signalSelect_currentIndexChanged(int index);
void on_rrcFilter_toggled(bool checked);
void on_rrcRolloff_valueChanged(int value);
void on_BW_valueChanged(int value); void on_BW_valueChanged(int value);
void on_lowCut_valueChanged(int value); void on_lowCut_valueChanged(int value);
void on_spanLog2_currentIndexChanged(int index); void on_spanLog2_currentIndexChanged(int index);

View File

@ -419,6 +419,58 @@
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="BWLayout"> <layout class="QHBoxLayout" name="BWLayout">
<item>
<widget class="ButtonSwitch" name="rrcFilter">
<property name="toolTip">
<string>Toggle RRC filter</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/dsb.png</normaloff>:/dsb.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="rrcRolloff">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Tune RRC filter rolloff factor</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rrcRolloffText">
<property name="toolTip">
<string>RRC filter rolloff factor value</string>
</property>
<property name="text">
<string>0.00</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="BWLabel"> <widget class="QLabel" name="BWLabel">
<property name="minimumSize"> <property name="minimumSize">

View File

@ -40,6 +40,8 @@ void ChannelAnalyzerNGSettings::resetToDefaults()
m_ssb = false; m_ssb = false;
m_pll = false; m_pll = false;
m_fll = false; m_fll = false;
m_rrc = false;
m_rrcRolloff = 30; // 0.3
m_pllPskOrder = 1; m_pllPskOrder = 1;
m_inputType = InputSignal; m_inputType = InputSignal;
m_rgbColor = QColor(128, 128, 128).rgb(); m_rgbColor = QColor(128, 128, 128).rgb();
@ -65,6 +67,8 @@ QByteArray ChannelAnalyzerNGSettings::serialize() const
s.writeU32(13, m_pllPskOrder); s.writeU32(13, m_pllPskOrder);
s.writeS32(14, (int) m_inputType); s.writeS32(14, (int) m_inputType);
s.writeString(15, m_title); s.writeString(15, m_title);
s.writeBool(16, m_rrc);
s.writeU32(17, m_rrcRolloff);
return s.final(); return s.final();
} }
@ -110,6 +114,8 @@ bool ChannelAnalyzerNGSettings::deserialize(const QByteArray& data)
d.readS32(14, &tmp, 0); d.readS32(14, &tmp, 0);
m_inputType = (InputType) tmp; m_inputType = (InputType) tmp;
d.readString(15, &m_title, "Channel Analyzer NG"); d.readString(15, &m_title, "Channel Analyzer NG");
d.readBool(16, &m_rrc, false);
d.readU32(17, &m_rrcRolloff, 30);
return true; return true;
} }

View File

@ -39,6 +39,8 @@ struct ChannelAnalyzerNGSettings
bool m_ssb; bool m_ssb;
bool m_pll; bool m_pll;
bool m_fll; bool m_fll;
bool m_rrc;
quint32 m_rrcRolloff; //!< in 100ths
unsigned int m_pllPskOrder; unsigned int m_pllPskOrder;
InputType m_inputType; InputType m_inputType;
quint32 m_rgbColor; quint32 m_rgbColor;

View File

@ -69,7 +69,7 @@ protected:
{ {
float x = i/(float)len; // normalize to [0..1] float x = i/(float)len; // normalize to [0..1]
x = 0.5-fabs(x-0.5); // apply symmetry: now both halves overlap near 0 x = 0.5-fabs(x-0.5); // apply symmetry: now both halves overlap near 0
float tr = (fb*a)/2.0; // half the transition zone float tr = fb*a; // half the transition zone
if (x < fb-tr) if (x < fb-tr)
{ {