Noise Figure plugin - add support for sweeping gain and other device settings.

pull/1020/head
Jon Beniston 2021-10-26 21:50:38 +01:00
rodzic 54d880ac56
commit 6717abe877
12 zmienionych plików z 363 dodań i 207 usunięć

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 24 KiB

Wyświetl plik

@ -200,6 +200,7 @@ double NoiseFigure::calcENR(double frequency)
// FSM for running measurements over multiple frequencies
void NoiseFigure::nextState()
{
double scaleFactor = m_settings.m_setting == "centerFrequency" ? 1e6 : 1.0;
switch (m_state)
{
case IDLE:
@ -211,69 +212,69 @@ void NoiseFigure::nextState()
return;
}
m_step = 0;
if (m_settings.m_frequencySpec == NoiseFigureSettings::LIST)
if (m_settings.m_sweepSpec == NoiseFigureSettings::LIST)
{
// Create list of frequencies from string
// Create list of sweep values from string
QRegExp separator("[( |,|\t|)]");
QStringList freqStrings = m_settings.m_frequencies.trimmed().split(separator);
m_freqs.clear();
for (int i = 0; i < freqStrings.size(); i++)
QStringList valueStrings = m_settings.m_sweepList.trimmed().split(separator);
m_values.clear();
for (int i = 0; i < valueStrings.size(); i++)
{
QString freqString = freqStrings[i].trimmed();
if (!freqString.isEmpty())
QString valueString = valueStrings[i].trimmed();
if (!valueString.isEmpty())
{
bool ok;
double freq = freqString.toDouble(&ok);
double value = valueString.toDouble(&ok);
if (ok) {
m_freqs.append(freq * 1e6);
m_values.append(value * scaleFactor);
} else {
qDebug() << "NoiseFigure::nextState: Invalid frequency: " << freqString;
qDebug() << "NoiseFigure::nextState: Invalid value: " << valueString;
}
}
}
if (m_freqs.size() == 0)
if (m_values.size() == 0)
{
qDebug() << "NoiseFigure::nextState: No frequencies in list";
qDebug() << "NoiseFigure::nextState: Sweep list is empty";
if (getMessageQueueToGUI()) {
getMessageQueueToGUI()->push(MsgFinished::create("No frequencies in list"));
getMessageQueueToGUI()->push(MsgFinished::create("Sweep list is empty"));
}
return;
}
// Set start frequency and number of frequencies to step through
m_measurementFrequency = m_freqs[0];
m_steps = m_freqs.size();
// Set start value and number of values to step through
m_sweepValue = m_values[0];
m_steps = m_values.size();
}
else
{
if (m_settings.m_stopFrequency < m_settings.m_startFrequency)
if (m_settings.m_stopValue < m_settings.m_startValue)
{
if (getMessageQueueToGUI()) {
getMessageQueueToGUI()->push(MsgFinished::create("Stop frequency must be greater or equal to start frequency"));
getMessageQueueToGUI()->push(MsgFinished::create("Stop value must be greater or equal to start value"));
}
return;
}
// Set start frequency and number of frequencies to step through
m_measurementFrequency = m_settings.m_startFrequency * 1.e6;
if (m_settings.m_frequencySpec == NoiseFigureSettings::RANGE) {
// Set start value and number of values to step through
m_sweepValue = m_settings.m_startValue * scaleFactor;
if (m_settings.m_sweepSpec == NoiseFigureSettings::RANGE) {
m_steps = m_settings.m_steps;
} else {
m_steps = (m_settings.m_stopFrequency - m_settings.m_startFrequency) / m_settings.m_step + 1;
m_steps = (m_settings.m_stopValue - m_settings.m_startValue) / m_settings.m_step + 1;
}
}
m_state = SET_FREQUENCY;
m_state = SET_SWEEP_VALUE;
QTimer::singleShot(0, this, SLOT(nextState()));
break;
case SET_FREQUENCY:
// Set radio centre frequency
if (ChannelWebAPIUtils::setCenterFrequency(getDeviceSetIndex(), m_measurementFrequency))
case SET_SWEEP_VALUE:
// Set device setting that is being swept
if (ChannelWebAPIUtils::patchDeviceSetting(getDeviceSetIndex(), m_settings.m_setting, m_sweepValue))
{
qDebug() << "NoiseFigure::nextState: Set center frequency: " << m_measurementFrequency;
qDebug() << "NoiseFigure::nextState: Set " << m_settings.m_setting << " to " << m_sweepValue;
m_state = POWER_ON;
QTimer::singleShot(100, this, SLOT(nextState()));
} else
{
qDebug() << "NoiseFigure::nextState: Unable to set center frequency: " << m_measurementFrequency;
qDebug() << "NoiseFigure::nextState: Unable to set " << m_settings.m_setting << " to " << m_sweepValue;
}
break;
@ -309,7 +310,7 @@ void NoiseFigure::nextState()
double k = 1.38064852e-23;
double bw = 1;
double y = m_onPower - m_offPower;
double enr = calcENR(m_measurementFrequency/1e6);
double enr = calcENR(m_centerFrequency/1e6);
double nf = 10.0*log10(pow(10.0, enr/10.0)/(pow(10.0, y/10.0)-1.0));
double temp = t*(pow(10.0, nf/10.0)-1.0);
double floor = 10.0*log10(1000.0*k*t) + nf + 10*log10(bw);
@ -317,14 +318,14 @@ void NoiseFigure::nextState()
// Send result to GUI
if (getMessageQueueToGUI())
{
MsgNFMeasurement *msg = MsgNFMeasurement::create(m_measurementFrequency/1e6, nf, temp, y, enr, floor);
MsgNFMeasurement *msg = MsgNFMeasurement::create(m_sweepValue/scaleFactor, nf, temp, y, enr, floor);
getMessageQueueToGUI()->push(msg);
}
m_step++;
if (m_step >= m_steps)
{
// All frequencies measured
// All values swept
closeVISADevice();
m_state = IDLE;
if (getMessageQueueToGUI()) {
@ -333,15 +334,15 @@ void NoiseFigure::nextState()
}
else
{
// Move to next frequency
if (m_settings.m_frequencySpec == NoiseFigureSettings::LIST) {
m_measurementFrequency = m_freqs[m_step];
} else if (m_settings.m_frequencySpec == NoiseFigureSettings::RANGE) {
m_measurementFrequency += 1e6 * (m_settings.m_stopFrequency - m_settings.m_startFrequency) / (m_settings.m_steps - 1);
// Move to next value in sweep
if (m_settings.m_sweepSpec == NoiseFigureSettings::LIST) {
m_sweepValue = m_values[m_step];
} else if (m_settings.m_sweepSpec == NoiseFigureSettings::RANGE) {
m_sweepValue += scaleFactor * (m_settings.m_stopValue - m_settings.m_startValue) / (m_settings.m_steps - 1);
} else {
m_measurementFrequency += m_settings.m_step * 1e6;
m_sweepValue += m_settings.m_step * scaleFactor;
}
m_state = SET_FREQUENCY;
m_state = SET_SWEEP_VALUE;
QTimer::singleShot(0, this, SLOT(nextState()));
}
break;
@ -454,12 +455,13 @@ void NoiseFigure::applySettings(const NoiseFigureSettings& settings, bool force)
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_fftSize: " << settings.m_fftSize
<< " m_fftCount: " << settings.m_fftCount
<< " m_frequencySpec: " << settings.m_frequencySpec
<< " m_startFrequency: " << settings.m_startFrequency
<< " m_stopFrequency: " << settings.m_stopFrequency
<< " m_sweepSpec: " << settings.m_sweepSpec
<< " m_startValue: " << settings.m_startValue
<< " m_stopValue: " << settings.m_stopValue
<< " m_steps: " << settings.m_steps
<< " m_step: " << settings.m_step
<< " m_frequencies: " << settings.m_frequencies
<< " m_sweepList: " << settings.m_sweepList
<< " m_setting: " << settings.m_setting
<< " m_visaDevice: " << settings.m_visaDevice
<< " m_powerOnSCPI: " << settings.m_powerOnSCPI
<< " m_powerOffSCPI: " << settings.m_powerOffSCPI
@ -578,14 +580,14 @@ void NoiseFigure::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("fftSize")) {
settings.m_fftSize = response.getNoiseFigureSettings()->getFftSize();
}
if (channelSettingsKeys.contains("frequencySpec")) {
settings.m_frequencySpec = (NoiseFigureSettings::FrequencySpec)response.getNoiseFigureSettings()->getFrequencySpec();
if (channelSettingsKeys.contains("sweepSpec")) {
settings.m_sweepSpec = (NoiseFigureSettings::SweepSpec)response.getNoiseFigureSettings()->getSweepSpec();
}
if (channelSettingsKeys.contains("startFrequency")) {
settings.m_startFrequency = response.getNoiseFigureSettings()->getStartFrequency();
if (channelSettingsKeys.contains("startValue")) {
settings.m_startValue = response.getNoiseFigureSettings()->getStartValue();
}
if (channelSettingsKeys.contains("stopFrequency")) {
settings.m_stopFrequency = response.getNoiseFigureSettings()->getStopFrequency();
if (channelSettingsKeys.contains("stopValue")) {
settings.m_stopValue = response.getNoiseFigureSettings()->getStopValue();
}
if (channelSettingsKeys.contains("steps")) {
settings.m_steps = response.getNoiseFigureSettings()->getSteps();
@ -593,8 +595,11 @@ void NoiseFigure::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("step")) {
settings.m_step = response.getNoiseFigureSettings()->getStep();
}
if (channelSettingsKeys.contains("frequencies")) {
settings.m_frequencies = *response.getNoiseFigureSettings()->getFrequencies();
if (channelSettingsKeys.contains("list")) {
settings.m_sweepList = *response.getNoiseFigureSettings()->getList();
}
if (channelSettingsKeys.contains("setting")) {
settings.m_setting = *response.getNoiseFigureSettings()->getSetting();
}
if (channelSettingsKeys.contains("visaDevice")) {
settings.m_visaDevice = *response.getNoiseFigureSettings()->getVisaDevice();
@ -715,11 +720,14 @@ void NoiseFigure::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("fftCount") || force) {
swgNoiseFigureSettings->setFftCount(settings.m_fftCount);
}
if (channelSettingsKeys.contains("frequencySpec") || force) {
swgNoiseFigureSettings->setFrequencySpec((int)settings.m_frequencySpec);
if (channelSettingsKeys.contains("sweepSpec") || force) {
swgNoiseFigureSettings->setSweepSpec((int)settings.m_sweepSpec);
}
if (channelSettingsKeys.contains("stopFrequency") || force) {
swgNoiseFigureSettings->setStopFrequency(settings.m_stopFrequency);
if (channelSettingsKeys.contains("startValue") || force) {
swgNoiseFigureSettings->setStartValue(settings.m_startValue);
}
if (channelSettingsKeys.contains("stopValue") || force) {
swgNoiseFigureSettings->setStopValue(settings.m_stopValue);
}
if (channelSettingsKeys.contains("steps") || force) {
swgNoiseFigureSettings->setSteps(settings.m_steps);
@ -727,8 +735,11 @@ void NoiseFigure::webapiFormatChannelSettings(
if (channelSettingsKeys.contains("step") || force) {
swgNoiseFigureSettings->setStep(settings.m_step);
}
if (channelSettingsKeys.contains("frequencies") || force) {
swgNoiseFigureSettings->setFrequencies(new QString(settings.m_frequencies));
if (channelSettingsKeys.contains("list") || force) {
swgNoiseFigureSettings->setList(new QString(settings.m_sweepList));
}
if (channelSettingsKeys.contains("setting") || force) {
swgNoiseFigureSettings->setSetting(new QString(settings.m_setting));
}
if (channelSettingsKeys.contains("visaDevice") || force) {
swgNoiseFigureSettings->setVisaDevice(new QString(settings.m_visaDevice));

Wyświetl plik

@ -90,29 +90,29 @@ public:
MESSAGE_CLASS_DECLARATION
public:
double getFrequency() const { return m_frequency; }
double getSweepValue() const { return m_sweepValue; }
double getNF() const { return m_nf; }
double getTemp() const { return m_temp; }
double getY() const { return m_y; }
double getENR() const { return m_enr; }
double getFloor() const { return m_floor; }
static MsgNFMeasurement* create(double frequency, double nf, double temp, double y, double enr, double floor)
static MsgNFMeasurement* create(double sweepValue, double nf, double temp, double y, double enr, double floor)
{
return new MsgNFMeasurement(frequency, nf, temp, y, enr, floor);
return new MsgNFMeasurement(sweepValue, nf, temp, y, enr, floor);
}
private:
double m_frequency; // In MHz
double m_sweepValue;// In MHz for centerFrequency
double m_nf; // In dB
double m_temp; // In Kelvin
double m_y; // In dB
double m_enr; // In dB
double m_floor; // In dBm
MsgNFMeasurement(double frequency, double nf, double temp, double y, double enr, double floor) :
MsgNFMeasurement(double sweepValue, double nf, double temp, double y, double enr, double floor) :
Message(),
m_frequency(frequency),
m_sweepValue(sweepValue),
m_nf(nf),
m_temp(temp),
m_y(y),
@ -257,17 +257,17 @@ private:
enum State {
IDLE,
SET_FREQUENCY,
SET_SWEEP_VALUE,
POWER_ON,
MEASURE_ON,
POWER_OFF,
MEASURE_OFF,
COMPLETE
} m_state;
double m_measurementFrequency; // In Hz
QList<double> m_freqs; // In Hz
int m_step; // Current frequency step
int m_steps; // Number of frequencies to test
double m_sweepValue; // Current sweep value
QList<double> m_values; // Sweep values
int m_step; // Current sweep step
int m_steps; // Number of settings to sweep
double m_onPower;
double m_offPower;
ViSession m_session;

Wyświetl plik

@ -66,7 +66,7 @@ void NoiseFigureGUI::resizeTable()
// Trailing spaces are for sort arrow
int row = ui->results->rowCount();
ui->results->setRowCount(row + 1);
ui->results->setItem(row, RESULTS_COL_FREQ, new QTableWidgetItem("2000.000"));
ui->results->setItem(row, RESULTS_COL_SETTING, new QTableWidgetItem("2000.000"));
ui->results->setItem(row, RESULTS_COL_NF, new QTableWidgetItem("10.00"));
ui->results->setItem(row, RESULTS_COL_TEMP, new QTableWidgetItem("10000"));
ui->results->setItem(row, RESULTS_COL_Y, new QTableWidgetItem("10.00"));
@ -78,24 +78,30 @@ void NoiseFigureGUI::resizeTable()
void NoiseFigureGUI::measurementReceived(NoiseFigure::MsgNFMeasurement& report)
{
if (m_settings.m_setting == "centerFrequency") {
ui->results->horizontalHeaderItem(0)->setText("Freq (MHz)");
} else {
ui->results->horizontalHeaderItem(0)->setText(m_settings.m_setting);
}
ui->results->setSortingEnabled(false);
int row = ui->results->rowCount();
ui->results->setRowCount(row + 1);
QTableWidgetItem *freqItem = new QTableWidgetItem();
QTableWidgetItem *sweepItem = new QTableWidgetItem();
QTableWidgetItem *nfItem = new QTableWidgetItem();
QTableWidgetItem *tempItem = new QTableWidgetItem();
QTableWidgetItem *yItem = new QTableWidgetItem();
QTableWidgetItem *enrItem = new QTableWidgetItem();
QTableWidgetItem *floorItem = new QTableWidgetItem();
ui->results->setItem(row, RESULTS_COL_FREQ, freqItem);
ui->results->setItem(row, RESULTS_COL_SETTING, sweepItem);
ui->results->setItem(row, RESULTS_COL_NF, nfItem);
ui->results->setItem(row, RESULTS_COL_TEMP, tempItem);
ui->results->setItem(row, RESULTS_COL_Y, yItem);
ui->results->setItem(row, RESULTS_COL_ENR, enrItem);
ui->results->setItem(row, RESULTS_COL_FLOOR, floorItem);
freqItem->setData(Qt::DisplayRole, report.getFrequency());
sweepItem->setData(Qt::DisplayRole, report.getSweepValue());
nfItem->setData(Qt::DisplayRole, report.getNF());
tempItem->setData(Qt::DisplayRole, report.getTemp());
yItem->setData(Qt::DisplayRole, report.getY());
@ -134,10 +140,10 @@ void NoiseFigureGUI::plotChart()
series->setName("Measurement");
for (int i = 0; i < ui->results->rowCount(); i++)
{
double freq = ui->results->item(i, RESULTS_COL_FREQ)->data(Qt::DisplayRole).toDouble();
double sweepValue = ui->results->item(i, RESULTS_COL_SETTING)->data(Qt::DisplayRole).toDouble();
double val = ui->results->item(i, ui->chartSelect->currentIndex() + RESULTS_COL_NF)->data(Qt::DisplayRole).toDouble();
series->append(freq, val);
series->append(sweepValue, val);
}
QValueAxis *xAxis = new QValueAxis();
@ -146,7 +152,11 @@ void NoiseFigureGUI::plotChart()
m_chart->addAxis(xAxis, Qt::AlignBottom);
m_chart->addAxis(yAxis, Qt::AlignLeft);
xAxis->setTitleText("Frequency (MHz)");
if (m_settings.m_setting == "centerFrequency") {
xAxis->setTitleText("Frequency (MHz)");
} else {
xAxis->setTitleText(m_settings.m_setting);
}
yAxis->setTitleText(ui->chartSelect->currentText());
m_chart->addSeries(series);
@ -341,11 +351,17 @@ void NoiseFigureGUI::on_fftCount_valueChanged(int value)
applySettings();
}
void NoiseFigureGUI::on_setting_currentTextChanged(const QString& text)
{
m_settings.m_setting = text;
applySettings();
}
void NoiseFigureGUI::updateFreqWidgets()
{
bool range = m_settings.m_frequencySpec == NoiseFigureSettings::RANGE;
bool step = m_settings.m_frequencySpec == NoiseFigureSettings::STEP;
bool list = m_settings.m_frequencySpec == NoiseFigureSettings::LIST;
bool range = m_settings.m_sweepSpec == NoiseFigureSettings::RANGE;
bool step = m_settings.m_sweepSpec == NoiseFigureSettings::STEP;
bool list = m_settings.m_sweepSpec == NoiseFigureSettings::LIST;
ui->startLabel->setVisible(range || step);
ui->start->setVisible(range || step);
ui->stopLabel->setVisible(range || step);
@ -354,26 +370,25 @@ void NoiseFigureGUI::updateFreqWidgets()
ui->steps->setVisible(range);
ui->stepLabel->setVisible(step);
ui->step->setVisible(step);
ui->frequenciesLabel->setVisible(list);
ui->frequencies->setVisible(list);
ui->list->setVisible(list);
}
void NoiseFigureGUI::on_frequencySpec_currentIndexChanged(int index)
{
m_settings.m_frequencySpec = (NoiseFigureSettings::FrequencySpec)index;
m_settings.m_sweepSpec = (NoiseFigureSettings::SweepSpec)index;
updateFreqWidgets();
applySettings();
}
void NoiseFigureGUI::on_start_valueChanged(double value)
{
m_settings.m_startFrequency = value;
m_settings.m_startValue = value;
applySettings();
}
void NoiseFigureGUI::on_stop_valueChanged(double value)
{
m_settings.m_stopFrequency = value;
m_settings.m_stopValue = value;
applySettings();
}
@ -389,9 +404,9 @@ void NoiseFigureGUI::on_step_valueChanged(double value)
applySettings();
}
void NoiseFigureGUI::on_frequencies_editingFinished()
void NoiseFigureGUI::on_list_editingFinished()
{
m_settings.m_frequencies = ui->frequencies->text().trimmed();
m_settings.m_sweepList = ui->list->text().trimmed();
applySettings();
}
@ -441,7 +456,7 @@ void NoiseFigureGUI::on_saveResults_clicked()
QTextStream out(&file);
// Create a CSV file from the values in the table
out << "Frequency (MHz),NF (dB),Noise Temp (K),Y (dB),ENR (dB)\n";
out << ui->results->horizontalHeaderItem(0)->text() << ",NF (dB),Noise Temp (K),Y (dB),ENR (dB)\n";
for (int i = 0; i < ui->results->rowCount(); i++)
{
for (int j = 0; j < NOISEFIGURE_COLUMNS; j++)
@ -712,13 +727,15 @@ void NoiseFigureGUI::displaySettings()
ui->fftCountText->setText(QString("%1k").arg(m_settings.m_fftCount / 1000));
ui->fftCount->setValue(m_settings.m_fftCount / 10000);
ui->frequencySpec->setCurrentIndex((int)m_settings.m_frequencySpec);
ui->setting->setCurrentText(m_settings.m_setting);
ui->frequencySpec->setCurrentIndex((int)m_settings.m_sweepSpec);
updateFreqWidgets();
ui->start->setValue(m_settings.m_startFrequency);
ui->stop->setValue(m_settings.m_stopFrequency);
ui->start->setValue(m_settings.m_startValue);
ui->stop->setValue(m_settings.m_stopValue);
ui->steps->setValue(m_settings.m_steps);
ui->step->setValue(m_settings.m_step);
ui->frequencies->setText(m_settings.m_frequencies);
ui->list->setText(m_settings.m_sweepList);
ui->fftSize->setCurrentIndex(log2(m_settings.m_fftSize) - 6);
updateBW();

Wyświetl plik

@ -102,7 +102,7 @@ private:
void plotChart();
enum MessageCol {
RESULTS_COL_FREQ,
RESULTS_COL_SETTING,
RESULTS_COL_NF,
RESULTS_COL_TEMP,
RESULTS_COL_Y,
@ -113,12 +113,13 @@ private:
private slots:
void on_deltaFrequency_changed(qint64 value);
void on_fftCount_valueChanged(int value);
void on_setting_currentTextChanged(const QString& text);
void on_frequencySpec_currentIndexChanged(int index);
void on_start_valueChanged(double value);
void on_stop_valueChanged(double value);
void on_steps_valueChanged(int value);
void on_step_valueChanged(double value);
void on_frequencies_editingFinished();
void on_list_editingFinished();
void on_fftSize_currentIndexChanged(int index);
void on_startStop_clicked();
void on_saveResults_clicked();

Wyświetl plik

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>404</width>
<height>642</height>
<height>693</height>
</rect>
</property>
<property name="sizePolicy">
@ -43,7 +43,7 @@
<x>0</x>
<y>0</y>
<width>390</width>
<height>151</height>
<height>181</height>
</rect>
</property>
<property name="minimumSize">
@ -366,6 +366,13 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_7">
<property name="orientation">
@ -382,6 +389,56 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="parameterLabel">
<property name="text">
<string>Sweep</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="setting">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Device parameter to sweep</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>centerFrequency</string>
</property>
</item>
<item>
<property name="text">
<string>gain</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="freqLayout">
<item>
@ -502,19 +559,25 @@
</widget>
</item>
<item>
<widget class="QLabel" name="frequenciesLabel">
<property name="text">
<string>Freqs</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="frequencies">
<widget class="QLineEdit" name="list">
<property name="toolTip">
<string>List of frequencies in MHz to measure NF at</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
@ -618,7 +681,7 @@
<property name="geometry">
<rect>
<x>0</x>
<y>450</y>
<y>500</y>
<width>391</width>
<height>171</height>
</rect>
@ -712,7 +775,7 @@
<property name="geometry">
<rect>
<x>0</x>
<y>160</y>
<y>210</y>
<width>391</width>
<height>268</height>
</rect>
@ -867,7 +930,7 @@
<tabstop>stop</tabstop>
<tabstop>steps</tabstop>
<tabstop>step</tabstop>
<tabstop>frequencies</tabstop>
<tabstop>list</tabstop>
<tabstop>startStop</tabstop>
<tabstop>saveResults</tabstop>
<tabstop>clearResults</tabstop>
@ -877,7 +940,6 @@
<tabstop>openReference</tabstop>
<tabstop>clearReference</tabstop>
<tabstop>chart</tabstop>
<tabstop>results</tabstop>
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>

Wyświetl plik

@ -40,12 +40,12 @@ void NoiseFigureSettings::resetToDefaults()
m_inputFrequencyOffset = 0;
m_fftSize = 64;
m_fftCount = 20000.0f;
m_frequencySpec = RANGE;
m_startFrequency = 430.0;
m_stopFrequency = 440.0;
m_sweepSpec = RANGE;
m_startValue = 430.0;
m_stopValue = 440.0;
m_steps = 3;
m_step = 5.0f;
m_frequencies = DEFAULT_FREQUENCIES;
m_sweepList = DEFAULT_FREQUENCIES;
m_visaDevice = DEFAULT_VISA_DEVICE;
m_powerOnSCPI = DEFAULT_POWER_ON;
m_powerOffSCPI = DEFAULT_POWER_OFF;
@ -55,6 +55,7 @@ void NoiseFigureSettings::resetToDefaults()
qDeleteAll(m_enr);
m_enr << new ENR(1000.0, 15.0);
m_interpolation = LINEAR;
m_setting = "centerFrequency";
m_rgbColor = QColor(0, 100, 200).rgb();
m_title = "Noise Figure";
m_streamIndex = 0;
@ -79,12 +80,12 @@ QByteArray NoiseFigureSettings::serialize() const
s.writeS32(2, m_fftSize);
s.writeFloat(3, m_fftCount);
s.writeS32(4, (int)m_frequencySpec);
s.writeDouble(5, m_startFrequency);
s.writeDouble(6, m_stopFrequency);
s.writeS32(4, (int)m_sweepSpec);
s.writeDouble(5, m_startValue);
s.writeDouble(6, m_stopValue);
s.writeS32(7, m_steps);
s.writeDouble(8, m_step);
s.writeString(9, m_frequencies);
s.writeString(9, m_sweepList);
s.writeString(10, m_visaDevice);
s.writeString(11, m_powerOnSCPI);
@ -109,6 +110,8 @@ QByteArray NoiseFigureSettings::serialize() const
s.writeS32(26, (int)m_interpolation);
s.writeString(27, m_setting);
for (int i = 0; i < NOISEFIGURE_COLUMNS; i++) {
s.writeS32(100 + i, m_resultsColumnIndexes[i]);
}
@ -140,12 +143,12 @@ bool NoiseFigureSettings::deserialize(const QByteArray& data)
d.readS32(2, &m_fftSize, 64);
d.readFloat(3, &m_fftCount, 10000.0f);
d.readS32(4, (int*)&m_frequencySpec, NoiseFigureSettings::RANGE);
d.readDouble(5, &m_startFrequency, 430.0);
d.readDouble(6, &m_stopFrequency, 440.0);
d.readS32(4, (int*)&m_sweepSpec, NoiseFigureSettings::RANGE);
d.readDouble(5, &m_startValue, 430.0);
d.readDouble(6, &m_stopValue, 440.0);
d.readS32(7, &m_steps, 3);
d.readDouble(8, &m_step, 5.0);
d.readString(9, &m_frequencies, DEFAULT_FREQUENCIES);
d.readString(9, &m_sweepList, DEFAULT_FREQUENCIES);
d.readString(10, &m_visaDevice, DEFAULT_VISA_DEVICE);
d.readString(11, &m_powerOnSCPI, DEFAULT_POWER_ON);
@ -179,6 +182,8 @@ bool NoiseFigureSettings::deserialize(const QByteArray& data)
d.readS32(26, (int*)&m_interpolation, LINEAR);
d.readString(27, &m_setting, "centerFrequency");
for (int i = 0; i < NOISEFIGURE_COLUMNS; i++) {
d.readS32(100 + i, &m_resultsColumnIndexes[i], i);
}

Wyświetl plik

@ -50,16 +50,16 @@ struct NoiseFigureSettings
int m_fftSize;
Real m_fftCount; //!< Number of FFT bins to average
enum FrequencySpec {
enum SweepSpec {
RANGE,
STEP,
LIST
} m_frequencySpec;
double m_startFrequency;
double m_stopFrequency;
} m_sweepSpec;
double m_startValue;
double m_stopValue;
int m_steps;
double m_step;
QString m_frequencies;
QString m_sweepList;
QString m_visaDevice;
QString m_powerOnSCPI;
@ -74,6 +74,8 @@ struct NoiseFigureSettings
BARYCENTRIC
} m_interpolation;
QString m_setting; //<! Device setting to sweep
quint32 m_rgbColor;
QString m_title;
Serializable *m_channelMarker;

Wyświetl plik

@ -40,27 +40,44 @@ Displays the measurement bandwidth in Hz as determined by the FFT size (4) and t
Determines the number of FFTs that are used to measure the average noise power. Using more FFTs can improve accuracy, at the expense of increased measurement time.
<h3>7: Frequency range</h3>
<h3>7: Sweep setting</h3>
Specifies the frequencies to measure the noise figure at. This can be specified as a:
The device setting to sweep should be entered. Predefined values include "centerFrequency" and "gain", but it is possible to
enter any setting supported by the device (that is accessible via the Web API). Not all devices support the "gain" setting.
When "centerFrequency" is set, sweep ranges and values are in MHz. For all other settings, the values are used without any scaling.
Note that some device settings are scaled in the SDRangel GUI compared to the values in the Web API. For example, RTL SDR gain setting of
40.2 in the GUI, is 402 in the Web API.
<h3>8: Sweep range</h3>
Specifies the values of setting (E.g. centerFrequency of gain) to measure the noise figure at. This can be specified as a:
When the sweep setting (7) is "centerFrequency":
* Range - Specify start frequency in MHz, stop frequency in MHz and the number of steps. 100, 200, 5, would measure at 100MHz, 125MHz, 150MHz, 175MHz and 200MHz.
* Step - Specify start frequency in MHz, stop frequency in MHz and the step frequency in MHz. 100, 200, 25, would measure at 100MHz, 125MHz, 150MHz, 175MHz and 200MHz.
* List - Specify a space or comma separated list of frequencies in MHz. "100 125 150 175 200", would measure at 100MHz, 125MHz, 150MHz, 175MHz and 200MHz.
<h3>8: Start/stop noise figure measurement</h3>
For other settings:
* Range - Specify start value, stop value and the number of steps. 100, 200, 5, would measure at 100, 125, 150, 175 and 200.
* Step - Specify start value, stop value and the step. 100, 200, 25, would measure at 100, 125, 150, 175 and 200.
* List - Specify a space or comma separated list of values. "100 125 150 175 200", would measure at 100, 125, 150, 175 and 200.
<h3>9: Start/stop noise figure measurement</h3>
Starts or stops the noise figure measurement. When starting a new measurement, existing results are cleared.
<h3>9: Save results</h3>
<h3>10: Save results</h3>
Saves the results in the table to a .csv file.
<h3>10: Clear results</h3>
<h3>11: Clear results</h3>
Clears the current results from the table and chart.
<h3>11: Open ENR dialog</h3>
<h3>12: Open ENR dialog</h3>
Opens the ENR dialog to allow entering the Excess Noise Ratios (ENRs) for noise source. ENR specifies the difference in noise source power output in dB from when the source is powered off compared to when it is powered on.
This typically varies with frequency, so values should be entered for each calibrated frequency. When a measurement is attempted at a frequency for which a value is not specified, an interpolated value will be used.
@ -68,7 +85,7 @@ You can choose between linear and barycentric rational interpolation, and the di
![Noise figure ENR dialog](../../../doc/img/NoiseFigure_plugin_enr.png)
<h3>12: Open Noise Source Control dialog</h3>
<h3>13: Open Noise Source Control dialog</h3>
Opens the noise source control dialog, to allow setting how the plugin turns the power to the noise source off and on. Two control methods are supported: A program or script can be run to turn the power on or off,
or the VISA library (if installed) can be used to send SCPI commands to a programmable power supply or other test equipment. If a VISA library is not found, the VISA and SCPI fields will be disabled.
@ -78,11 +95,11 @@ not too long so that tests over a large number of frequencies take a long time t
![Noise source control dialog](../../../doc/img/NoiseFigure_plugin_control.png)
<h3>13: Results Table</h3>
<h3>14: Results Table</h3>
Displays measurement results.
* Frequency - Frequency of the measurement in MHz.
* Frequency/gain - Frequency of the measurement in MHz, gain or other setting as per (7).
* NF - Calculated noise figure in dB.
* T - Calculated noise temperature in Kelvin with a reference temperature of 290K.
* Y - Measured Y factor in dB (difference in measured power when the noise source is on and off).
@ -91,11 +108,11 @@ Displays measurement results.
![Noise figure results table](../../../doc/img/NoiseFigure_plugin_results.png)
<h3>14: Results Chart</h3>
<h3>15: Results Chart</h3>
Plots the results (NF, T or Y) vs frequency as a line chart.
<h3>15: Open reference data</h3>
<h3>16: Open reference data</h3>
A set of reference data in .csv format can be loaded for comparisons with the measurement results. The first column of the .csv file should contain frequency and the second the noise figure in dB. The first row should contain a header (E.g. "Frequency,NF" allthough the exact text is ignored).
@ -149,6 +166,12 @@ as the total NF is primarily determined by the LNA, if it has a decent amount of
![LNA comparison](../../../doc/img/NoiseFigure_plugin_lna_comparison.png)
In these plots, gain is swept at a single frequency (1420MHz), firstly for a B210 on its own, and then a B210 with a Nooelec H1 LNA.
While the NF is lowest at maximum gain for the standalone B210, due to the high gain of the LNA, the lowest NF for the combined devices is actually
well below the maximum B210 gain setting.
![NF vs Gain comparison](../../../doc/img/NoiseFigure_plugin_gain_comparison.png)
<h2>VISA libraries</h2>
VISA libraries are available for Windows, Linux and MacOS from:

Wyświetl plik

@ -8,12 +8,13 @@ NoiseFigureSettings:
type: integer
fftCount:
type: integer
frequencySpec:
sweepSpec:
description: "(0 - Range, 1 - Step, 2 - List)"
type: integer
startFrequency:
startValue:
type: number
format: float
stopFrequency:
stopValue:
type: number
format: float
steps:
@ -21,7 +22,10 @@ NoiseFigureSettings:
step:
type: number
format: float
frequencies:
list:
type: string
setting:
description: "The device setting to sweep (E.g. centerFrequency or gain)"
type: string
visaDevice:
type: string

Wyświetl plik

@ -34,18 +34,20 @@ SWGNoiseFigureSettings::SWGNoiseFigureSettings() {
m_fft_size_isSet = false;
fft_count = 0;
m_fft_count_isSet = false;
frequency_spec = 0;
m_frequency_spec_isSet = false;
start_frequency = 0.0f;
m_start_frequency_isSet = false;
stop_frequency = 0.0f;
m_stop_frequency_isSet = false;
sweep_spec = 0;
m_sweep_spec_isSet = false;
start_value = 0.0f;
m_start_value_isSet = false;
stop_value = 0.0f;
m_stop_value_isSet = false;
steps = 0;
m_steps_isSet = false;
step = 0.0f;
m_step_isSet = false;
frequencies = nullptr;
m_frequencies_isSet = false;
list = nullptr;
m_list_isSet = false;
setting = nullptr;
m_setting_isSet = false;
visa_device = nullptr;
m_visa_device_isSet = false;
power_on_scpi = nullptr;
@ -88,18 +90,20 @@ SWGNoiseFigureSettings::init() {
m_fft_size_isSet = false;
fft_count = 0;
m_fft_count_isSet = false;
frequency_spec = 0;
m_frequency_spec_isSet = false;
start_frequency = 0.0f;
m_start_frequency_isSet = false;
stop_frequency = 0.0f;
m_stop_frequency_isSet = false;
sweep_spec = 0;
m_sweep_spec_isSet = false;
start_value = 0.0f;
m_start_value_isSet = false;
stop_value = 0.0f;
m_stop_value_isSet = false;
steps = 0;
m_steps_isSet = false;
step = 0.0f;
m_step_isSet = false;
frequencies = new QString("");
m_frequencies_isSet = false;
list = new QString("");
m_list_isSet = false;
setting = new QString("");
m_setting_isSet = false;
visa_device = new QString("");
m_visa_device_isSet = false;
power_on_scpi = new QString("");
@ -140,8 +144,11 @@ SWGNoiseFigureSettings::cleanup() {
if(frequencies != nullptr) {
delete frequencies;
if(list != nullptr) {
delete list;
}
if(setting != nullptr) {
delete setting;
}
if(visa_device != nullptr) {
delete visa_device;
@ -190,17 +197,19 @@ SWGNoiseFigureSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&fft_count, pJson["fftCount"], "qint32", "");
::SWGSDRangel::setValue(&frequency_spec, pJson["frequencySpec"], "qint32", "");
::SWGSDRangel::setValue(&sweep_spec, pJson["sweepSpec"], "qint32", "");
::SWGSDRangel::setValue(&start_frequency, pJson["startFrequency"], "float", "");
::SWGSDRangel::setValue(&start_value, pJson["startValue"], "float", "");
::SWGSDRangel::setValue(&stop_frequency, pJson["stopFrequency"], "float", "");
::SWGSDRangel::setValue(&stop_value, pJson["stopValue"], "float", "");
::SWGSDRangel::setValue(&steps, pJson["steps"], "qint32", "");
::SWGSDRangel::setValue(&step, pJson["step"], "float", "");
::SWGSDRangel::setValue(&frequencies, pJson["frequencies"], "QString", "QString");
::SWGSDRangel::setValue(&list, pJson["list"], "QString", "QString");
::SWGSDRangel::setValue(&setting, pJson["setting"], "QString", "QString");
::SWGSDRangel::setValue(&visa_device, pJson["visaDevice"], "QString", "QString");
@ -255,14 +264,14 @@ SWGNoiseFigureSettings::asJsonObject() {
if(m_fft_count_isSet){
obj->insert("fftCount", QJsonValue(fft_count));
}
if(m_frequency_spec_isSet){
obj->insert("frequencySpec", QJsonValue(frequency_spec));
if(m_sweep_spec_isSet){
obj->insert("sweepSpec", QJsonValue(sweep_spec));
}
if(m_start_frequency_isSet){
obj->insert("startFrequency", QJsonValue(start_frequency));
if(m_start_value_isSet){
obj->insert("startValue", QJsonValue(start_value));
}
if(m_stop_frequency_isSet){
obj->insert("stopFrequency", QJsonValue(stop_frequency));
if(m_stop_value_isSet){
obj->insert("stopValue", QJsonValue(stop_value));
}
if(m_steps_isSet){
obj->insert("steps", QJsonValue(steps));
@ -270,8 +279,11 @@ SWGNoiseFigureSettings::asJsonObject() {
if(m_step_isSet){
obj->insert("step", QJsonValue(step));
}
if(frequencies != nullptr && *frequencies != QString("")){
toJsonValue(QString("frequencies"), frequencies, obj, QString("QString"));
if(list != nullptr && *list != QString("")){
toJsonValue(QString("list"), list, obj, QString("QString"));
}
if(setting != nullptr && *setting != QString("")){
toJsonValue(QString("setting"), setting, obj, QString("QString"));
}
if(visa_device != nullptr && *visa_device != QString("")){
toJsonValue(QString("visaDevice"), visa_device, obj, QString("QString"));
@ -350,33 +362,33 @@ SWGNoiseFigureSettings::setFftCount(qint32 fft_count) {
}
qint32
SWGNoiseFigureSettings::getFrequencySpec() {
return frequency_spec;
SWGNoiseFigureSettings::getSweepSpec() {
return sweep_spec;
}
void
SWGNoiseFigureSettings::setFrequencySpec(qint32 frequency_spec) {
this->frequency_spec = frequency_spec;
this->m_frequency_spec_isSet = true;
SWGNoiseFigureSettings::setSweepSpec(qint32 sweep_spec) {
this->sweep_spec = sweep_spec;
this->m_sweep_spec_isSet = true;
}
float
SWGNoiseFigureSettings::getStartFrequency() {
return start_frequency;
SWGNoiseFigureSettings::getStartValue() {
return start_value;
}
void
SWGNoiseFigureSettings::setStartFrequency(float start_frequency) {
this->start_frequency = start_frequency;
this->m_start_frequency_isSet = true;
SWGNoiseFigureSettings::setStartValue(float start_value) {
this->start_value = start_value;
this->m_start_value_isSet = true;
}
float
SWGNoiseFigureSettings::getStopFrequency() {
return stop_frequency;
SWGNoiseFigureSettings::getStopValue() {
return stop_value;
}
void
SWGNoiseFigureSettings::setStopFrequency(float stop_frequency) {
this->stop_frequency = stop_frequency;
this->m_stop_frequency_isSet = true;
SWGNoiseFigureSettings::setStopValue(float stop_value) {
this->stop_value = stop_value;
this->m_stop_value_isSet = true;
}
qint32
@ -400,13 +412,23 @@ SWGNoiseFigureSettings::setStep(float step) {
}
QString*
SWGNoiseFigureSettings::getFrequencies() {
return frequencies;
SWGNoiseFigureSettings::getList() {
return list;
}
void
SWGNoiseFigureSettings::setFrequencies(QString* frequencies) {
this->frequencies = frequencies;
this->m_frequencies_isSet = true;
SWGNoiseFigureSettings::setList(QString* list) {
this->list = list;
this->m_list_isSet = true;
}
QString*
SWGNoiseFigureSettings::getSetting() {
return setting;
}
void
SWGNoiseFigureSettings::setSetting(QString* setting) {
this->setting = setting;
this->m_setting_isSet = true;
}
QString*
@ -563,13 +585,13 @@ SWGNoiseFigureSettings::isSet(){
if(m_fft_count_isSet){
isObjectUpdated = true; break;
}
if(m_frequency_spec_isSet){
if(m_sweep_spec_isSet){
isObjectUpdated = true; break;
}
if(m_start_frequency_isSet){
if(m_start_value_isSet){
isObjectUpdated = true; break;
}
if(m_stop_frequency_isSet){
if(m_stop_value_isSet){
isObjectUpdated = true; break;
}
if(m_steps_isSet){
@ -578,7 +600,10 @@ SWGNoiseFigureSettings::isSet(){
if(m_step_isSet){
isObjectUpdated = true; break;
}
if(frequencies && *frequencies != QString("")){
if(list && *list != QString("")){
isObjectUpdated = true; break;
}
if(setting && *setting != QString("")){
isObjectUpdated = true; break;
}
if(visa_device && *visa_device != QString("")){

Wyświetl plik

@ -51,14 +51,14 @@ public:
qint32 getFftCount();
void setFftCount(qint32 fft_count);
qint32 getFrequencySpec();
void setFrequencySpec(qint32 frequency_spec);
qint32 getSweepSpec();
void setSweepSpec(qint32 sweep_spec);
float getStartFrequency();
void setStartFrequency(float start_frequency);
float getStartValue();
void setStartValue(float start_value);
float getStopFrequency();
void setStopFrequency(float stop_frequency);
float getStopValue();
void setStopValue(float stop_value);
qint32 getSteps();
void setSteps(qint32 steps);
@ -66,8 +66,11 @@ public:
float getStep();
void setStep(float step);
QString* getFrequencies();
void setFrequencies(QString* frequencies);
QString* getList();
void setList(QString* list);
QString* getSetting();
void setSetting(QString* setting);
QString* getVisaDevice();
void setVisaDevice(QString* visa_device);
@ -124,14 +127,14 @@ private:
qint32 fft_count;
bool m_fft_count_isSet;
qint32 frequency_spec;
bool m_frequency_spec_isSet;
qint32 sweep_spec;
bool m_sweep_spec_isSet;
float start_frequency;
bool m_start_frequency_isSet;
float start_value;
bool m_start_value_isSet;
float stop_frequency;
bool m_stop_frequency_isSet;
float stop_value;
bool m_stop_value_isSet;
qint32 steps;
bool m_steps_isSet;
@ -139,8 +142,11 @@ private:
float step;
bool m_step_isSet;
QString* frequencies;
bool m_frequencies_isSet;
QString* list;
bool m_list_isSet;
QString* setting;
bool m_setting_isSet;
QString* visa_device;
bool m_visa_device_isSet;