1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 17:28:50 -05:00

Merge pull request #1450 from srcejon/radio_astronomy_filter

Radio Astronomy: Add filtered power series
This commit is contained in:
Edouard Griffiths 2022-09-26 20:58:56 +02:00 committed by GitHub
commit f4afc599b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 363 additions and 85 deletions

View File

@ -49,6 +49,8 @@
#include "gui/devicestreamselectiondialog.h"
#include "dsp/dspengine.h"
#include "gui/crightclickenabler.h"
#include "gui/timedelegate.h"
#include "gui/decimaldelegate.h"
#include "channel/channelwebapiutils.h"
#include "maincore.h"
#include "feature/featurewebapiutils.h"
@ -65,30 +67,6 @@
#include "SWGStarTrackerDisplaySettings.h"
#include "SWGStarTrackerDisplayLoSSettings.h"
// Delegate for table to display time
class TimeDelegate : public QStyledItemDelegate {
public:
TimeDelegate(QString format = "hh:mm:ss") :
m_format(format)
{
}
virtual QString displayText(const QVariant &value, const QLocale &locale) const override
{
(void) locale;
if (value.toString() == "") {
return "";
} else {
return value.toTime().toString(m_format);
}
}
private:
QString m_format;
};
// Time value is in milliseconds - Displays hh:mm:ss or d hh:mm:ss
class TimeDeltaDelegate : public QStyledItemDelegate {
@ -120,32 +98,6 @@ private:
};
// Delegate for table to control precision used to display floating point values - also supports strings
class DecimalDelegate : public QStyledItemDelegate {
public:
DecimalDelegate(int precision = 2) :
m_precision(precision)
{
}
virtual QString displayText(const QVariant &value, const QLocale &locale) const override
{
(void) locale;
bool ok;
double d = value.toDouble(&ok);
if (ok) {
return QString::number(d, 'f', m_precision);
} else {
return value.toString();
}
}
private:
int m_precision;
};
// Delegate for table to display hours, minutes and seconds
class HMSDelegate : public QStyledItemDelegate {
@ -471,6 +423,7 @@ void RadioAstronomyGUI::addToPowerSeries(FFTMeasurement *fft, bool skipCalcs)
m_powerMax = std::max(power, m_powerMax);
}
m_powerSeries->append(dateTime.toMSecsSinceEpoch(), power);
addToPowerFilter(dateTime.toMSecsSinceEpoch(), power);
if (!skipCalcs)
{
if (m_settings.m_powerAutoscale)
@ -1278,6 +1231,7 @@ void RadioAstronomyGUI::clearData()
m_powerPeakSeries->clear();
m_powerMarkerSeries->clear();
m_powerTsys0Series->clear();
m_powerFilteredSeries->clear();
m_airTemps.clear();
for (int i = 0; i < RADIOASTRONOMY_SENSORS; i++) {
m_sensors[i].clear();
@ -2030,6 +1984,7 @@ RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI
m_powerMarkerSeries(nullptr),
m_powerTsys0Series(nullptr),
m_powerGaussianSeries(nullptr),
m_powerFilteredSeries(nullptr),
m_powerPeakValid(false),
m_2DChart(nullptr),
m_2DXAxis(nullptr),
@ -2071,7 +2026,11 @@ RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI
m_beamWidth(5.6f),
m_lLAB(0.0f),
m_bLAB(0.0f),
m_downloadingLAB(false)
m_downloadingLAB(false),
m_window(nullptr),
m_windowSorted(nullptr),
m_windowIdx(0),
m_windowCount(0)
{
qDebug("RadioAstronomyGUI::RadioAstronomyGUI");
setAttribute(Qt::WA_DeleteOnClose, true);
@ -2326,6 +2285,8 @@ RadioAstronomyGUI::~RadioAstronomyGUI()
qDeleteAll(m_dataLAB);
m_dataLAB.clear();
delete[] m_2DMapIntensity;
delete[] m_window;
delete[] m_windowSorted;
}
void RadioAstronomyGUI::blockApplySettings(bool block)
@ -2487,6 +2448,17 @@ void RadioAstronomyGUI::displaySettings()
ui->powerShowSensor2->setChecked(m_settings.m_sensorVisible[1]);
m_sensors[1].setName(m_settings.m_sensorName[1]);
m_sensors[1].clicked(m_settings.m_sensorVisible[1]);
ui->powerShowFiltered->setChecked(m_settings.m_powerShowFiltered);
if (m_powerFilteredSeries) {
m_powerFilteredSeries->setVisible(m_settings.m_powerShowFiltered);
}
ui->powerFilterWidgets->setVisible(m_settings.m_powerShowFiltered);
ui->powerFilter->setCurrentIndex((int)m_settings.m_powerFilter);
ui->powerFilterN->setValue(m_settings.m_powerFilterN);
ui->powerShowMeasurement->setChecked(m_settings.m_powerShowMeasurement);
if (m_powerSeries) {
m_powerSeries->setVisible(m_settings.m_powerShowMeasurement);
}
ui->power2DLinkSweep->setChecked(m_settings.m_power2DLinkSweep);
ui->power2DSweepType->setCurrentIndex((int)m_settings.m_power2DSweepType);
@ -3486,6 +3458,7 @@ void RadioAstronomyGUI::plotPowerVsTimeChart()
// Create measurement data series
m_powerSeries = new QLineSeries();
m_powerSeries->setVisible(m_settings.m_powerShowMeasurement);
connect(m_powerSeries, &QXYSeries::clicked, this, &RadioAstronomyGUI::powerSeries_clicked);
// Plot peak info
@ -3517,6 +3490,12 @@ void RadioAstronomyGUI::plotPowerVsTimeChart()
m_powerGaussianSeries->setName("Gaussian fit");
m_powerGaussianSeries->setVisible(m_settings.m_powerShowGaussian);
// Filtered measurement
m_powerFilteredSeries = new QLineSeries();
m_powerFilteredSeries->setName("Filtered");
m_powerFilteredSeries->setVisible(m_settings.m_powerShowFiltered);
plotPowerFiltered();
// Sensors
for (int i = 0; i < RADIOASTRONOMY_SENSORS; i++) {
m_sensors[i].init(m_settings.m_sensorName[i], m_settings.m_sensorVisible[i]);
@ -3630,6 +3609,10 @@ void RadioAstronomyGUI::plotPowerVsTimeChart()
m_sensors[i].addToChart(m_powerChart, m_powerXAxis);
}
m_powerChart->addSeries(m_powerFilteredSeries);
m_powerFilteredSeries->attachAxis(m_powerXAxis);
m_powerFilteredSeries->attachAxis(m_powerYAxis);
m_powerChart->addSeries(m_powerPeakSeries);
m_powerPeakSeries->attachAxis(m_powerXAxis);
m_powerPeakSeries->attachAxis(m_powerYAxis);
@ -5113,6 +5096,7 @@ void RadioAstronomyGUI::on_saveSpectrumChartImages_clicked()
for (int i = 0; i < m_fftMeasurements.size(); i++)
{
plotFFTMeasurement(i);
QApplication::processEvents(); // To get chart title to be updated
QImage image(ui->spectrumChart->size(), QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
@ -5366,6 +5350,9 @@ void RadioAstronomyGUI::updateDistanceColumns()
{
ui->spectrumMarkerTable->showColumn(SPECTRUM_MARKER_COL_R);
ui->spectrumMarkerTable->showColumn(SPECTRUM_MARKER_COL_D);
ui->spectrumMarkerTable->showColumn(SPECTRUM_MARKER_COL_PLOT_MAX);
ui->spectrumMarkerTable->showColumn(SPECTRUM_MARKER_COL_R_MIN);
ui->spectrumMarkerTable->showColumn(SPECTRUM_MARKER_COL_V);
showLoSMarker("Max");
showLoSMarker("M1");
showLoSMarker("M2");
@ -5382,6 +5369,9 @@ void RadioAstronomyGUI::updateDistanceColumns()
{
ui->spectrumMarkerTable->hideColumn(SPECTRUM_MARKER_COL_R);
ui->spectrumMarkerTable->hideColumn(SPECTRUM_MARKER_COL_D);
ui->spectrumMarkerTable->hideColumn(SPECTRUM_MARKER_COL_PLOT_MAX);
ui->spectrumMarkerTable->hideColumn(SPECTRUM_MARKER_COL_R_MIN);
ui->spectrumMarkerTable->hideColumn(SPECTRUM_MARKER_COL_V);
clearLoSMarker("Max");
clearLoSMarker("M1");
clearLoSMarker("M2");
@ -5671,6 +5661,7 @@ void RadioAstronomyGUI::on_powerShowGaussian_clicked(bool checked)
m_powerGaussianSeries->setVisible(checked);
updatePowerSelect();
getRollupContents()->arrangeRollups();
update();
}
void RadioAstronomyGUI::plotPowerGaussian()
@ -5748,6 +5739,92 @@ void RadioAstronomyGUI::on_powerGaussianHPBW_valueChanged(double value)
ui->powerGaussianFWHM->blockSignals(false);
}
void RadioAstronomyGUI::addToPowerFilter(qreal x, qreal y)
{
// Add data to circular buffer
m_window[m_windowIdx] = y;
m_windowIdx = (m_windowIdx + 1) % m_settings.m_powerFilterN;
if (m_windowCount < m_settings.m_powerFilterN) {
m_windowCount++;
}
// Filter
if (m_settings.m_powerFilter == RadioAstronomySettings::FILT_MOVING_AVERAGE)
{
// Moving average
qreal sum = 0.0;
for (int i = 0; i < m_windowCount; i++) {
sum += m_window[i];
}
qreal mean = sum / m_windowCount;
y = mean;
}
else
{
// Median
std::partial_sort_copy(m_window, m_window + m_windowCount, m_windowSorted, m_windowSorted + m_windowCount);
qreal median;
if ((m_windowCount & 1) == 1) {
median = m_windowSorted[m_windowCount / 2];
} else {
median = (m_windowSorted[m_windowCount / 2 - 1] + m_windowSorted[m_windowCount / 2]) / 2.0;
}
y = median;
}
// Add to series for chart
m_powerFilteredSeries->append(x, y);
}
void RadioAstronomyGUI::plotPowerFiltered()
{
delete[] m_window;
delete[] m_windowSorted;
m_window = new qreal[m_settings.m_powerFilterN];
m_windowSorted = new qreal[m_settings.m_powerFilterN];
m_windowIdx = 0;
m_windowCount = 0;
m_powerFilteredSeries->clear();
QVector<QPointF> powerSeries = m_powerSeries->pointsVector();
for (int i = 0; i < powerSeries.size(); i++)
{
QPointF point = powerSeries.at(i);
addToPowerFilter(point.x(), point.y());
}
}
void RadioAstronomyGUI::on_powerShowFiltered_clicked(bool checked)
{
m_settings.m_powerShowFiltered = checked;
applySettings();
ui->powerFilterWidgets->setVisible(checked);
m_powerFilteredSeries->setVisible(checked);
getRollupContents()->arrangeRollups();
update();
}
void RadioAstronomyGUI::on_powerFilter_currentIndexChanged(int index)
{
m_settings.m_powerFilter = (RadioAstronomySettings::PowerFilter)index;
applySettings();
plotPowerFiltered();
}
void RadioAstronomyGUI::on_powerFilterN_valueChanged(int value)
{
m_settings.m_powerFilterN = value;
applySettings();
plotPowerFiltered();
}
void RadioAstronomyGUI::on_powerShowMeasurement_clicked(bool checked)
{
m_settings.m_powerShowMeasurement = checked;
applySettings();
m_powerSeries->setVisible(checked);
}
RadioAstronomyGUI::LABData* RadioAstronomyGUI::parseLAB(QFile* file, float l, float b)
{
LABData *data = new LABData();
@ -5786,11 +5863,11 @@ void RadioAstronomyGUI::plotLAB(float l, float b, float beamWidth)
if (!data)
{
// Try to open previously downloaded data
m_filenameLAB = HttpDownloadManager::downloadDir() + "/" + QString("lab_l_%1_b_%2.txt").arg(l).arg(b);
QFile file(m_filenameLAB);
QString filenameLAB = HttpDownloadManager::downloadDir() + "/" + QString("lab_l_%1_b_%2.txt").arg(l).arg(b);
QFile file(filenameLAB);
if (file.open(QIODevice::ReadOnly))
{
qDebug() << "RadioAstronomyGUI::plotLAB: Using cached file: " << m_filenameLAB;
qDebug() << "RadioAstronomyGUI::plotLAB: Using cached file: " << filenameLAB;
data = parseLAB(&file, l, b);
}
else
@ -5801,6 +5878,7 @@ void RadioAstronomyGUI::plotLAB(float l, float b, float beamWidth)
m_downloadingLAB = true;
m_lLAB = l;
m_bLAB = b;
m_filenameLAB = filenameLAB;
// Request data be generated via web server
QNetworkRequest request(QUrl("https://www.astro.uni-bonn.de/hisurvey/euhou/LABprofile/index.php"));
@ -5867,6 +5945,7 @@ void RadioAstronomyGUI::downloadFinished(const QString& filename, bool success)
if (file.open(QIODevice::ReadOnly))
{
LABData *data = parseLAB(&file, m_lLAB, m_bLAB);
file.close();
// Check if the data we've downloaded is for the current FFT being displayed
int index = ui->spectrumIndex->value();
if (index < m_fftMeasurements.size())
@ -5876,19 +5955,26 @@ void RadioAstronomyGUI::downloadFinished(const QString& filename, bool success)
{
data->toSeries(m_fftLABSeries);
spectrumAutoscale();
m_downloadingLAB = false;
}
else
{
// Try ploting for current FFT (as we only allow one download at a time, so may have been skipped)
m_downloadingLAB = false;
plotLAB(fft->m_l, fft->m_b, m_beamWidth);
// Don't clear m_downloadingLAB after this point
}
}
} else {
qDebug() << "RadioAstronomyGUI::downloadFinished: Failed to open downloaded file: " << filename;
m_downloadingLAB = false;
}
}
m_downloadingLAB = false;
else
{
qDebug() << "RadioAstronomyGUI::downloadFinished: Failed to download: " << filename;
m_downloadingLAB = false;
}
}
void RadioAstronomyGUI::displayRunModeSettings()

View File

@ -244,6 +244,7 @@ private:
QScatterSeries *m_powerMarkerSeries;
QLineSeries *m_powerTsys0Series;
QLineSeries *m_powerGaussianSeries;
QLineSeries *m_powerFilteredSeries;
double m_powerMin; // For axis autoscale
double m_powerMax;
bool m_powerPeakValid;
@ -320,6 +321,12 @@ private:
bool m_downloadingLAB;
QList<LABData *> m_dataLAB;
// Circular buffer to filtering power series data
qreal *m_window;
qreal *m_windowSorted;
int m_windowIdx;
int m_windowCount;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
HttpDownloadManager m_dlm;
@ -637,6 +644,13 @@ private slots:
void on_powerGaussianFWHM_valueChanged(double value);
void on_powerGaussianHPBW_valueChanged(double value);
void plotPowerFiltered();
void addToPowerFilter(qreal y, qreal x);
void on_powerShowFiltered_clicked(bool checked=false);
void on_powerFilter_currentIndexChanged(int index);
void on_powerFilterN_valueChanged(int value);
void on_powerShowMeasurement_clicked(bool checked=false);
void on_runMode_currentIndexChanged(int index);
void on_sweepType_currentIndexChanged(int index);
void on_startStop_clicked(bool checked=false);

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>740</width>
<height>1688</height>
<height>1713</height>
</rect>
</property>
<property name="sizePolicy">
@ -3407,7 +3407,7 @@ This should be close to the expected difference in power between hot and cold ca
<x>0</x>
<y>990</y>
<width>731</width>
<height>481</height>
<height>521</height>
</rect>
</property>
<property name="sizePolicy">
@ -3425,7 +3425,7 @@ This should be close to the expected difference in power between hot and cold ca
<property name="windowTitle">
<string>Radiometer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0,0,0,0,0,0,0">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0,0,0,0,0,0,0,0">
<property name="spacing">
<number>2</number>
</property>
@ -3613,6 +3613,46 @@ This should be close to the expected difference in power between hot and cold ca
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="powerShowFiltered">
<property name="toolTip">
<string>Plot filtered measurement</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/carrier.png</normaloff>:/carrier.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="powerShowMeasurement">
<property name="toolTip">
<string>Plot measurement</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/carrier.png</normaloff>:/carrier.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="powerShowAvg">
<property name="toolTip">
@ -4141,6 +4181,102 @@ This should be close to the expected difference in power between hot and cold ca
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="powerFilterWidgets" native="true">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="Line" name="line_41">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="powerFilterWidgetsHor" native="true">
<layout class="QHBoxLayout" name="spectrumScaleLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="powerFilter">
<item>
<property name="text">
<string>Median</string>
</property>
</item>
<item>
<property name="text">
<string>Moving average</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="powerFilterNLabel">
<property name="text">
<string>n</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="powerFilterN">
<property name="toolTip">
<string>Filter window size (samples)</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_21">
<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>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="power2DScaleWidgets" native="true">
<layout class="QGridLayout" name="power2DAxisScaleLayout">
@ -4746,7 +4882,7 @@ This should be close to the expected difference in power between hot and cold ca
<property name="geometry">
<rect>
<x>10</x>
<y>1490</y>
<y>1520</y>
<width>721</width>
<height>171</height>
</rect>
@ -5009,6 +5145,11 @@ This should be close to the expected difference in power between hot and cold ca
</widget>
</widget>
<customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>RollupContents</class>
<extends>QWidget</extends>
@ -5021,11 +5162,6 @@ This should be close to the expected difference in power between hot and cold ca
<header>gui/valuedialz.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>QChartView</class>
<extends>QGraphicsView</extends>

View File

@ -104,6 +104,10 @@ void RadioAstronomySettings::resetToDefaults()
m_powerShowTsys0 = false;
m_powerShowAirTemp = false;
m_powerShowGaussian = false;
m_powerShowFiltered = false;
m_powerFilter = FILT_MEDIAN;
m_powerFilterN = 10;
m_powerShowMeasurement = true;
m_power2DLinkSweep = true;
m_power2DSweepType = SWP_OFFSET;
@ -247,6 +251,10 @@ QByteArray RadioAstronomySettings::serialize() const
s.writeBool(89, m_powerAutoscale);
s.writeS32(90, (int)m_powerYData);
s.writeS32(91, (int)m_powerYUnits);
s.writeBool(92, m_powerShowFiltered);
s.writeS32(93, (int)m_powerFilter);
s.writeS32(94, m_powerFilterN);
s.writeBool(95, m_powerShowMeasurement);
s.writeBool(100, m_power2DLinkSweep);
s.writeS32(102, (int)m_power2DSweepType);
@ -408,6 +416,10 @@ bool RadioAstronomySettings::deserialize(const QByteArray& data)
d.readBool(89, &m_powerAutoscale, true);
d.readS32(90, (int*)&m_powerYData, PY_POWER);
d.readS32(91, (int*)&m_powerYUnits, PY_DBFS);
d.readBool(92, &m_powerShowFiltered, false);
d.readS32(93, (int*)&m_powerFilter, FILT_MEDIAN);
d.readS32(94, &m_powerFilterN, 10);
d.readBool(95, &m_powerShowMeasurement, true);
d.readBool(100, &m_power2DLinkSweep, true);
d.readS32(102, (int*)&m_power2DSweepType, SWP_OFFSET);

View File

@ -143,6 +143,8 @@ struct RadioAstronomySettings
bool m_powerShowTsys0; //!< Plot total noise temperature
bool m_powerShowAirTemp;
bool m_powerShowGaussian;
bool m_powerShowFiltered;
bool m_powerShowMeasurement;
float m_powerReference; //!< In dB
float m_powerRange; //!< In dB
bool m_powerAutoscale;
@ -161,6 +163,12 @@ struct RadioAstronomySettings
PY_SFU,
PY_JANSKY
} m_powerYUnits;
enum PowerFilter {
FILT_MEDIAN,
FILT_MOVING_AVERAGE,
// TODO: FILT_LPF
} m_powerFilter;
int m_powerFilterN;
enum SweepType {
SWP_AZEL,

View File

@ -5,7 +5,7 @@
The Radio Astronomy plugin provides a number of tools to help make radio astronomy measurements. It supports:
- A spectrometer for displaying time averaged spectra.
- A radiometer for displaying time averaged continuum measurements (total power).
- A radiometer for displaying time averaged and optionally filtered continuum measurements (total power).
- Calibration to enable measurements to be displayed as noise temperatures (K), power (dBm/Watts) and spectral flux density (Jy).
- Utilities are included for estimation and calculation of noise temperature components (Tsys, Trx, Tgal, Tatm, Tsky, Tsp) and sensitivity (sigma Tsys and sigma Sv).
- Spectra can be displayed against frequency and velocity (with a configurable reference spectral line), with the velocity adjusted to topocentric, Solar System barycentric or the Local Standard of Rest (LSR) reference frames.
@ -605,59 +605,67 @@ Plot the surface air temperature data received from Star Tracker on the chart.
Plot Tsys0 on the chart.
<h3>4.8: Display Statistics</h3>
<h3>4.8: Plot Filtered Measurement</h3>
Plot a filtered version of the measurement. The filter can either be a moving average or a median filter, with a configurable window size.
<h3>4.9: Plot Measurement</h3>
Plot measured data on the chart.
<h3>4.10: Display Statistics</h3>
Displays statistics calculated across all measurements (not just those visible on the chart), including the mean, RMS and standard deviation.
<h3>4.9: Display Gaussian Fitting Tools</h3>
<h3>4.11: Display Gaussian Fitting Tools</h3>
When checked, the Gaussian fitting tools are displayed. These allow a Gaussian to be fitted to the data, allowing measurement of the HPBW of the antenna.
<h3>4.10: Display Markers</h3>
<h3>4.12: Display Markers</h3>
When checked, the marker table is displayed and the user may place two markers (M1 and M2) on the chart for accurate display of the corresponding values from the measurement series.
<h3>4.11: Display Peaks</h3>
<h3>4.13: Display Peaks</h3>
When checked, the marker table is displayed and the peak Max and Min markers are displayed at the maximum and minimum values on the measurement series.
<h3>4.12: Save Chart to an Image File</h3>
<h3>4.14: Save Chart to an Image File</h3>
Click to save the current chart to an image file.
<h3>4.14: Save Data to a .csv File</h3>
<h3>4.15: Save Data to a .csv File</h3>
Click to save data from the Radiometer Data table to a .csv file.
<h3>4.15: Autoscale</h3>
<h3>4.16: Autoscale</h3>
When checked, continuously automatically scales both X and Y axis so all data is visible. When unchecked, the axis scales can be set manually.
<h3>4.16: Autoscale X</h3>
<h3>4.17: Autoscale X</h3>
When clicked, automatically scales the X axis so all data is visible.
<h3>4.17: Autoscale Y</h3>
<h3>4.18: Autoscale Y</h3>
When clicked, automatically scales the Y axis so all data is visible.
<h3>4.18: Ref</h3>
<h3>4.19: Ref</h3>
Sets the reference level (maximum value) of the Y axis.
<h3>4.19: Range</h3>
<h3>4.20: Range</h3>
Sets the range of the Y axis.
<h3>4.20: Start</h3>
<h3>4.21: Start</h3>
Sets the start time of the X axis.
<h3>4.21: End</h3>
<h3>4.22: End</h3>
Sets the end time of the X axis.
<h3>4.22: Sel</h3>
<h3>4.23: Sel</h3>
Selects what is selected when clicking on the chart:
@ -666,29 +674,37 @@ Selects what is selected when clicking on the chart:
- M2 sets position of marker 2
- Gaussian sets peak of Gaussian
<h3>4.23: Center</h3>
<h3>4.24: Center</h3>
Specifies the date and time of the center of the Gaussian.
<h3>4.24: a</h3>
<h3>4.25: a</h3>
Specifies the amplitude of the Gaussian. Units correspond to the Y axis units.
<h3>4.25: f</h3>
<h3>4.26: f</h3>
Specifies the floor (minimum value of the Gaussian). Units correspond to the Y axis units.
<h3>4.26: Delta t FHWM</h3>
<h3>4.27: Delta t FHWM</h3>
Specifies the full-width at half maximum of the Gaussian in seconds.
<h3>4.27: HPBW</h3>
<h3>4.28: HPBW</h3>
An estimate of the HPBW in degrees of an antenna whose main lobe corresponds to the Gaussian profile of a drift scan of the Sun, using a linear scale (E.g. Y axis must not be in not dB).
![Radiometer Gaussian Fit](../../../doc/img/RadioAstronomy_RadiometerGaussian.png)
<h3>4.28: Marker Table</h3>
<h3>4.29: Filter</h3>
Specifies the type of filter to use for the filtered measurement series. This can either be a moving average or a median filter.
<h3>4.30: Filter Window Size</h3>
Specifies the window size for the filter.
<h3>4.31: Marker Table</h3>
The marker table displays corresponding values for markers that are placed on the chart.
@ -845,6 +861,12 @@ Starts a measurement that will be used as the cold calibration data.
When checked, results of a new calibration will be applied to all existing measurements. When unchecked, the calibration will only apply to new measurements.
<h2>Frequency Accuracy</h2>
When measuring Doppler shifts in order to estimate velocity, it is important to use an accurate clock source for the SDR.
For example, a 5ppm XO at 1420MHz could have a frequency error of 7.1kHz, resulting in an velocity error of 1.5km/s.
A GPSDO can be 1000x more accurate, at less than 1ppb.
<h2>API</h2>
Full details of the API can be found in the Swagger documentation. Here is a quick example of how to start a measurement from the command line: