From bf24ce2e3b0804e5547cf1e3e04ac25343d22821 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Mon, 26 Sep 2022 12:46:52 +0100 Subject: [PATCH] Radio Astronomy: Add filtered power series --- .../radioastronomy/radioastronomygui.cpp | 196 +++++++++++++----- .../radioastronomy/radioastronomygui.h | 14 ++ .../radioastronomy/radioastronomygui.ui | 154 +++++++++++++- .../radioastronomy/radioastronomysettings.cpp | 12 ++ .../radioastronomy/radioastronomysettings.h | 8 + plugins/channelrx/radioastronomy/readme.md | 64 ++++-- 6 files changed, 363 insertions(+), 85 deletions(-) diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.cpp b/plugins/channelrx/radioastronomy/radioastronomygui.cpp index 77070dd1a7..582c1714bf 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomygui.cpp @@ -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 @@ class TimeDeltaDelegate : public QStyledItemDelegate { }; -// 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 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() diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.h b/plugins/channelrx/radioastronomy/radioastronomygui.h index b4a736ade0..434fd87b96 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.h +++ b/plugins/channelrx/radioastronomy/radioastronomygui.h @@ -244,6 +244,7 @@ public slots: 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 @@ public slots: bool m_downloadingLAB; QList 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); diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.ui b/plugins/channelrx/radioastronomy/radioastronomygui.ui index d95f34841a..9c15e2fd81 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.ui +++ b/plugins/channelrx/radioastronomy/radioastronomygui.ui @@ -7,7 +7,7 @@ 0 0 740 - 1688 + 1713 @@ -3407,7 +3407,7 @@ This should be close to the expected difference in power between hot and cold ca 0 990 731 - 481 + 521 @@ -3425,7 +3425,7 @@ This should be close to the expected difference in power between hot and cold ca Radiometer - + 2 @@ -3613,6 +3613,46 @@ This should be close to the expected difference in power between hot and cold ca + + + + Plot filtered measurement + + + + + + + :/carrier.png:/carrier.png + + + true + + + true + + + + + + + Plot measurement + + + + + + + :/carrier.png:/carrier.png + + + true + + + true + + + @@ -4141,6 +4181,102 @@ This should be close to the expected difference in power between hot and cold ca + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Median + + + + + Moving average + + + + + + + + n + + + + + + + Filter window size (samples) + + + 1 + + + 50 + + + 10 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + @@ -4746,7 +4882,7 @@ This should be close to the expected difference in power between hot and cold ca 10 - 1490 + 1520 721 171 @@ -5009,6 +5145,11 @@ This should be close to the expected difference in power between hot and cold ca + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
RollupContents QWidget @@ -5021,11 +5162,6 @@ This should be close to the expected difference in power between hot and cold ca
gui/valuedialz.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
QChartView QGraphicsView diff --git a/plugins/channelrx/radioastronomy/radioastronomysettings.cpp b/plugins/channelrx/radioastronomy/radioastronomysettings.cpp index 66473becdf..dfb924fd10 100644 --- a/plugins/channelrx/radioastronomy/radioastronomysettings.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomysettings.cpp @@ -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); diff --git a/plugins/channelrx/radioastronomy/radioastronomysettings.h b/plugins/channelrx/radioastronomy/radioastronomysettings.h index f10ab2bd69..1c14905d12 100644 --- a/plugins/channelrx/radioastronomy/radioastronomysettings.h +++ b/plugins/channelrx/radioastronomy/radioastronomysettings.h @@ -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, diff --git a/plugins/channelrx/radioastronomy/readme.md b/plugins/channelrx/radioastronomy/readme.md index a63583f957..ec66408540 100644 --- a/plugins/channelrx/radioastronomy/readme.md +++ b/plugins/channelrx/radioastronomy/readme.md @@ -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. -

4.8: Display Statistics

+

4.8: Plot Filtered Measurement

+ +Plot a filtered version of the measurement. The filter can either be a moving average or a median filter, with a configurable window size. + +

4.9: Plot Measurement

+ +Plot measured data on the chart. + +

4.10: Display Statistics

Displays statistics calculated across all measurements (not just those visible on the chart), including the mean, RMS and standard deviation. -

4.9: Display Gaussian Fitting Tools

+

4.11: Display Gaussian Fitting Tools

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. -

4.10: Display Markers

+

4.12: Display Markers

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. -

4.11: Display Peaks

+

4.13: Display Peaks

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. -

4.12: Save Chart to an Image File

+

4.14: Save Chart to an Image File

Click to save the current chart to an image file. -

4.14: Save Data to a .csv File

+

4.15: Save Data to a .csv File

Click to save data from the Radiometer Data table to a .csv file. -

4.15: Autoscale

+

4.16: Autoscale

When checked, continuously automatically scales both X and Y axis so all data is visible. When unchecked, the axis scales can be set manually. -

4.16: Autoscale X

+

4.17: Autoscale X

When clicked, automatically scales the X axis so all data is visible. -

4.17: Autoscale Y

+

4.18: Autoscale Y

When clicked, automatically scales the Y axis so all data is visible. -

4.18: Ref

+

4.19: Ref

Sets the reference level (maximum value) of the Y axis. -

4.19: Range

+

4.20: Range

Sets the range of the Y axis. -

4.20: Start

+

4.21: Start

Sets the start time of the X axis. -

4.21: End

+

4.22: End

Sets the end time of the X axis. -

4.22: Sel

+

4.23: Sel

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 -

4.23: Center

+

4.24: Center

Specifies the date and time of the center of the Gaussian. -

4.24: a

+

4.25: a

Specifies the amplitude of the Gaussian. Units correspond to the Y axis units. -

4.25: f

+

4.26: f

Specifies the floor (minimum value of the Gaussian). Units correspond to the Y axis units. -

4.26: Delta t FHWM

+

4.27: Delta t FHWM

Specifies the full-width at half maximum of the Gaussian in seconds. -

4.27: HPBW

+

4.28: HPBW

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) -

4.28: Marker Table

+

4.29: Filter

+ +Specifies the type of filter to use for the filtered measurement series. This can either be a moving average or a median filter. + +

4.30: Filter Window Size

+ +Specifies the window size for the filter. + +

4.31: Marker Table

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. +

Frequency Accuracy

+ +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. +

API

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: