1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 16:08:39 -05:00

Merge pull request #910 from srcejon/star_tracker_drift_scan

Star tracker updates
This commit is contained in:
Edouard Griffiths 2021-05-25 17:34:01 +02:00 committed by GitHub
commit 8d09a82f4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 845 additions and 381 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -4,6 +4,7 @@
The Star Tracker feature plugin is for use in radio astronomy and EME (Earth-Moon-Earth) communication.
It calculates the azimuth and elevation of celestial objects and can send them to the Rotator Controller or other plugins to point an antenna at that object.
It can plot drift scan paths in both equatorial and galactic charts.
The overhead position of the Sun, Moon and selected star can be displayed on the Map Feature.
It can display local Sidereal time, solar flux density and sky temperature.
The plugin can communicate with Stellarium, allowing Stellarium to control SDRangel as though it was a telescope and for the direction the antenna is pointing to be displayed in Stellarium.
@ -72,8 +73,8 @@ Displays the Solar flux density. The observatory where the data is sourced from,
<h3>11: Target</h3>
Select a target object to track from the list.
To manually enter RA (right ascension) and Dec (declination) of an unlisted target, select Custom.
To allow Stellarium to set the RA and Dec, select Custom, and ensure the Stellarium Server option is checked in the Star Tracker Settings dialog.
To manually enter RA (right ascension) and Dec (declination) of an unlisted target, select Custom RA/Dec.
To allow Stellarium to set the RA and Dec, select Custom RA/Dec, and ensure the Stellarium Server option is checked in the Star Tracker Settings dialog.
| Target | Type | Details | Flux density (Jy) |
|------------------|-------------------|------------------------------------------------|---------------------------------------------
@ -86,7 +87,8 @@ To allow Stellarium to set the RA and Dec, select Custom, and ensure the Stellar
| Cygnus A | Galaxy | First radio galaxy | 22k (50MHz), 11k (150MHz), 1579 (1.4GHz) |
| Taurus A (M1) | Supernova/Pulsar | Crab Nebular | 2008 (50MHz), 1368 (150MHz), 829 (1.4GHz) |
| Virgo A (M87) | Galaxy | | 2635 (50MHz), 1209 (150MHz), 212 (1.4GHz) |
| Custom | | Manually enter RA and Dec | |
| Custom RA/Dec | | Manually enter RA and Dec | |
| Custom Az/El | | Manually enter azimuth and elevation | |
References:
@ -104,31 +106,40 @@ Enter the half power (-3dB) beamwidth of your antenna. This value is used for sk
<h3>14: Right Ascension</h3>
When target is set to Custom, you can specify the right ascension in hours of the target object. This can be specified as a decimal (E.g. 12.23, from 0 to 24) or in hours, minutes and seconds (E.g. 12h05m10.2s or 12 05 10.2). Whether the epoch is J2000 or JNOW can be set in the Star Tracker Settings dialog.
When target is set to Custom RA/Dec, you can specify the right ascension in hours of the target object. This can be specified as a decimal (E.g. 12.23, from 0 to 24) or in hours, minutes and seconds (E.g. 12h05m10.2s or 12 05 10.2). Whether the epoch is J2000 or JNOW can be set in the Star Tracker Settings dialog.
When target is set to Custom Az/El, this will display the corresponding right ascension.
<h3>15: Declination</h3>
When target is set to Custom, you can specify the declination in degrees of the target object. This can be specified as a decimal (E.g. 34.6, from -90.0 to 90.0) or in degrees, minutes and seconds (E.g. 34d12m5.6s, 34d12'5.6" 34 12 5.6). Whether the epoch is J2000 or JNOW can be set in the Star Tracker Settings dialog.
When target is set to Custom RA/Dec, you can specify the declination in degrees of the target object. This can be specified as a decimal (E.g. 34.6, from -90.0 to 90.0) or in degrees, minutes and seconds (E.g. 34d12m5.6s, 34d12'5.6" 34 12 5.6). Whether the epoch is J2000 or JNOW can be set in the Star Tracker Settings dialog.
When target is set to Custom Az/El, this will display the corresponding declination.
<h3>16: Azimuth</h3>
Displays the calculated azimuth (angle in degrees, clockwise from North) to the object.
When target is set to Custom Az/El, you specify the azimuth in degrees of the target object. The corresponding RA/Dec will be calculated and displayed.
For all other target settings, this displays the calculated azimuth (angle in degrees, clockwise from North) to the object.
<h3>17: Elevation</h3>
Displays the calculated elevation (angle in degrees - 0 to horizon and 90 to zenith) to the object.
When target is set to Custom Az/El, you specify the elevation in degrees of the target object. The corresponding RA/Dec will be calculated and displayed.
For all other target settings, this displays the calculated elevation (angle in degrees - 0 to horizon and 90 to zenith) to the object.
<h2>Plots</h2>
<h3>Light or dark theme</h3>
click on this icon ![Star Tracker Chart theme](../../../doc/img/StarTracker_chart_theme.png) to switch between light and dark themes for the charts.
Click on this icon ![Star Tracker Chart theme](../../../doc/img/StarTracker_chart_theme.png) to switch between light and dark themes for the charts.
<h3>Elevation vs time</h3>
![Star Tracker Elevation vs Time](../../../doc/img/StarTracker_elevationvstime.png)
![Star Tracker Elevation vs Time](../../../doc/img/StarTracker_elevationvstime.png) ![Star Tracker Elevation vs Time Polar](../../../doc/img/StarTracker_elevationvstime_polar.png)
In order to assist in determining whether and when observations of the target object may be possible, an elevation vs time plot is drawn for the 24 hours encompassing the selected date and time.
This can be plotted on Cartesian or polar axis.
Some objects may not be visible from a particular latitude for the specified time, in which case, the graph title will indicate the object is not visible on that particular date.
<h3>Solar flux vs frequency</h3>
@ -148,6 +159,17 @@ This temperature is therefore valid for a beamwidth of less than 1 degree.
The Star Tracker plugin can also estimate a sky temperature based on the user entered observation frequency and beamwidth.
To see this figure, which will be typically lower than the above, select one of the last two temperature maps from the right hand combo box.
<h3>Drift scan path</h3>
When the target (11) is set to Custom Az/El and the Sky temperature plot is displayed, a curve showing the drift scan path over a 24 hour period will be displayed.
This assumes the azimuth and elevation will be held constant and the path shows the part of the sky the antenna will point to as the Earth rotates.
![Drift scan path](../../../doc/img/StarTracker_driftscan.png)
To setup a drift scan through a particular target object, first set the target (11) to that object. This will set the azimuth and elevation to point at the object.
You may want to set the Time (8) to Custom and a few hours in the future, so that the elevation is at a maximum when pointing at the target.
Then switch the target to Custom Az/El and Time back to Now, and the drift scan path that sweeps through the object will displayed.
<h2>Map</h2>
The Star Tracker feature can send the overhead position of the Sun, Moon and target Star to the Map. These can be enabled individually in the settings dialog. The Moon should be displayed with an approximate phase. Stars (or galaxies) are displayed as an image of a pulsar.
@ -160,7 +182,7 @@ When using the Find feature in the Map GUI, you can search for "Sun", "Moon" or
In Star Tracker:
* Set target to Custom
* Set target to Custom RA/Dec
* Press Show settings dialog and ensure Stellarium server is checked
* Press Start
@ -186,7 +208,7 @@ Then select the SDRangel telescope reticle and press Ocular view.
<h2>Attribution</h2>
Solar radio flux measurement at 10.7cm/2800MHz is from National Research Council Canada and Natural Resources Canada: https://www.spaceweather.gc.ca/solarflux/sx-4-en.php
Solar radio flux measurement at 10.7cm/2800MHz is from National Research Council Canada and Natural Resources Canada: https://www.spaceweather.gc.ca/forecast-prevision/solar-solaire/solarflux/sx-4-en.php
Solar radio flux measurements at 245, 410, 610, 1415, 2695, 4995, 8800 and 15400MHz from the Learmonth Observatory: http://www.sws.bom.gov.au/World_Data_Centre/1/10

View File

@ -141,6 +141,8 @@ void StarTracker::applySettings(const StarTrackerSettings& settings, bool force)
<< " m_target: " << settings.m_target
<< " m_ra: " << settings.m_ra
<< " m_dec: " << settings.m_dec
<< " m_az: " << settings.m_az
<< " m_el: " << settings.m_el
<< " m_latitude: " << settings.m_latitude
<< " m_longitude: " << settings.m_longitude
<< " m_serverPort: " << settings.m_serverPort

View File

@ -32,6 +32,7 @@
#include "feature/featureuiset.h"
#include "feature/featurewebapiutils.h"
#include "gui/basicfeaturesettingsdialog.h"
#include "gui/dmsspinbox.h"
#include "mainwindow.h"
#include "device/deviceuiset.h"
#include "util/units.h"
@ -93,18 +94,6 @@ bool StarTrackerGUI::deserialize(const QByteArray& data)
}
}
QString StarTrackerGUI::convertDegreesToText(double degrees)
{
if (m_settings.m_azElUnits == StarTrackerSettings::DMS)
return Units::decimalDegreesToDegreeMinutesAndSeconds(degrees);
else if (m_settings.m_azElUnits == StarTrackerSettings::DM)
return Units::decimalDegreesToDegreesAndMinutes(degrees);
else if (m_settings.m_azElUnits == StarTrackerSettings::D)
return Units::decimalDegreesToDegrees(degrees);
else
return QString("%1").arg(degrees, 0, 'f', 2);
}
bool StarTrackerGUI::handleMessage(const Message& message)
{
if (StarTracker::MsgConfigureStarTracker::match(message))
@ -121,8 +110,10 @@ bool StarTrackerGUI::handleMessage(const Message& message)
else if (StarTrackerReport::MsgReportAzAl::match(message))
{
StarTrackerReport::MsgReportAzAl& azAl = (StarTrackerReport::MsgReportAzAl&) message;
ui->azimuth->setText(convertDegreesToText(azAl.getAzimuth()));
ui->elevation->setText(convertDegreesToText(azAl.getElevation()));
blockApplySettings(true);
ui->azimuth->setValue(azAl.getAzimuth());
ui->elevation->setValue(azAl.getElevation());
blockApplySettings(false);
return true;
}
else if (StarTrackerReport::MsgReportRADec::match(message))
@ -197,6 +188,10 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(1000);
connect(ui->azimuth, SIGNAL(valueChanged(double)), this, SLOT(on_azimuth_valueChanged(double)));
ui->azimuth->setRange(0, 360.0);
ui->elevation->setRange(-90.0, 90.0);
// Intialise chart
m_chart.legend()->hide();
ui->chart->setChart(&m_chart);
@ -310,11 +305,18 @@ void StarTrackerGUI::displaySettings()
ui->latitude->setValue(m_settings.m_latitude);
ui->longitude->setValue(m_settings.m_longitude);
ui->target->setCurrentIndex(ui->target->findText(m_settings.m_target));
if (m_settings.m_target == "Custom")
ui->azimuth->setUnits((DMSSpinBox::DisplayUnits)m_settings.m_azElUnits);
ui->elevation->setUnits((DMSSpinBox::DisplayUnits)m_settings.m_azElUnits);
if (m_settings.m_target == "Custom RA/Dec")
{
ui->rightAscension->setText(m_settings.m_ra);
ui->declination->setText(m_settings.m_dec);
}
else if (m_settings.m_target == "Custom Az/El")
{
ui->azimuth->setValue(m_settings.m_az);
ui->elevation->setValue(m_settings.m_el);
}
if (m_settings.m_dateTime == "")
{
ui->dateTimeSelect->setCurrentIndex(0);
@ -413,6 +415,20 @@ void StarTrackerGUI::on_declination_editingFinished()
plotChart();
}
void StarTrackerGUI::on_azimuth_valueChanged(double value)
{
m_settings.m_az = value;
applySettings();
plotChart();
}
void StarTrackerGUI::on_elevation_valueChanged(double value)
{
m_settings.m_el = value;
applySettings();
plotChart();
}
void StarTrackerGUI::updateForTarget()
{
if (m_settings.m_target == "Sun")
@ -429,7 +445,7 @@ void StarTrackerGUI::updateForTarget()
ui->rightAscension->setText("");
ui->declination->setText("");
}
else if (m_settings.m_target == "Custom")
else if (m_settings.m_target == "Custom RA/Dec")
{
ui->rightAscension->setReadOnly(false);
ui->declination->setReadOnly(false);
@ -476,9 +492,21 @@ void StarTrackerGUI::updateForTarget()
on_rightAscension_editingFinished();
on_declination_editingFinished();
}
// Clear as no longer valid when target has changed
ui->azimuth->setText("");
ui->elevation->setText("");
if (m_settings.m_target != "Custom Az/El")
{
ui->azimuth->setReadOnly(true);
ui->elevation->setReadOnly(true);
// Clear as no longer valid when target has changed
ui->azimuth->setText("");
ui->elevation->setText("");
}
else
{
ui->rightAscension->setReadOnly(true);
ui->declination->setReadOnly(true);
ui->azimuth->setReadOnly(false);
ui->elevation->setReadOnly(false);
}
}
void StarTrackerGUI::on_target_currentTextChanged(const QString &text)
@ -572,6 +600,8 @@ void StarTrackerGUI::on_displaySettings_clicked()
if (dialog.exec() == QDialog::Accepted)
{
applySettings();
ui->elevation->setUnits((DMSSpinBox::DisplayUnits)m_settings.m_azElUnits);
ui->azimuth->setUnits((DMSSpinBox::DisplayUnits)m_settings.m_azElUnits);
displaySolarFlux();
if (ui->chartSelect->currentIndex() == 1)
plotChart();
@ -691,6 +721,116 @@ void StarTrackerGUI::plotSolarFluxChart()
// disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
}
QList<QLineSeries*> StarTrackerGUI::createDriftScan(bool galactic)
{
QList<QLineSeries *>list;
QLineSeries *series = new QLineSeries();
list.append(series);
QDateTime dt;
// Get date and time to calculate position at
if (m_settings.m_dateTime == "") {
dt = QDateTime::currentDateTime();
} else {
dt = QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs);
}
// Create a list of RA/Dec points of drift scan path
AzAlt aa;
aa.alt = m_settings.m_el;
aa.az = m_settings.m_az;
double prevX, prevY;
// Plot every 30min over a day
for (int i = 0; i <= 24*2; i++)
{
dt = dt.addSecs(30*60);
RADec rd = Astronomy::azAltToRaDec(aa, m_settings.m_latitude, m_settings.m_longitude, dt);
double x, y;
mapRaDec(rd.ra, rd.dec, galactic, x, y);
if (i == 0)
{
series->append(x, y);
}
else
{
// Check for crossing edge of chart
if (galactic)
{
if (((prevX < 90.0) && (x > 270.0)) || ((prevX > 270.0) && (x < 90.0)))
{
// Start new series, so we don't have lines crossing across the chart
series = new QLineSeries();
list.append(series);
}
}
series->append(x, y);
}
prevX = x;
prevY = y;
}
return list;
}
void StarTrackerGUI::mapRaDec(double ra, double dec, bool galactic, double& x, double& y)
{
if (galactic)
{
// Convert to category coordinates
double l, b;
Astronomy::equatorialToGalactic(ra, dec, l, b);
// Map to linear axis
double lAxis;
if (l < 180.0) {
lAxis = 180.0 - l;
} else {
lAxis = 360.0 - l + 180.0;
}
x = lAxis;
y = b;
}
else
{
// Map to category axis
double raAxis;
if (ra <= 12.0) {
raAxis = 12.0 - ra;
} else {
raAxis = 24 - ra + 12;
}
x = raAxis;
y = dec;
}
}
// Is there a way to get this from the theme? Got these values from the source
QColor StarTrackerGUI::getSeriesColor(int series)
{
if (m_settings.m_chartsDarkTheme)
{
if (series == 0) {
return QColor(0x38ad6b);
} else if (series == 1) {
return QColor(0x3c84a7);
} else {
return QColor(0xeb8817);
}
}
else
{
if (series == 0) {
return QColor(0x209fdf);
} else if (series == 1) {
return QColor(0x99ca53);
} else {
return QColor(0xf6a625);
}
}
}
void StarTrackerGUI::plotSkyTemperatureChart()
{
bool galactic = (ui->chartSubSelect->currentIndex() & 1) == 1;
@ -698,6 +838,16 @@ void StarTrackerGUI::plotSkyTemperatureChart()
m_chart.removeAllSeries();
removeAllAxes();
// Plot drift scan path
QList<QLineSeries*> lineSeries;
if (m_settings.m_target == "Custom Az/El") {
lineSeries = createDriftScan(galactic);
QPen pen(getSeriesColor(1), 2, Qt::SolidLine);
for (int i = 0; i < lineSeries.length(); i++) {
lineSeries[i]->setPen(pen);
}
}
QScatterSeries *series = new QScatterSeries();
float ra = Astronomy::raToDecimal(m_settings.m_ra);
float dec = Astronomy::decToDecimal(m_settings.m_dec);
@ -709,30 +859,9 @@ void StarTrackerGUI::plotSkyTemperatureChart()
double degPerPixel = std::min(degPerPixelW, degPerPixelH);
double markerSize;
if (galactic)
{
// Convert to category coordinates
double l, b;
Astronomy::equatorialToGalactic(ra, dec, l, b);
// Map to linear axis
double lAxis;
if (l < 180.0)
lAxis = 180.0 - l;
else
lAxis = 360.0 - l + 180.0;
series->append(lAxis, b);
}
else
{
// Map to category axis
double raAxis;
if (ra <= 12.0)
raAxis = 12.0 - ra;
else
raAxis = 24 - ra + 12;
series->append(raAxis, dec);
}
double x, y;
mapRaDec(ra, dec, galactic, x, y);
series->append(x, y);
// Get temperature
int idx = ui->chartSubSelect->currentIndex();
@ -757,10 +886,12 @@ void StarTrackerGUI::plotSkyTemperatureChart()
double degreesPerPixelV = abs(fits->degreesPerPixelV());
int numberOfCoeffsH = ceil(beamwidth/degreesPerPixelH);
int numberOfCoeffsV = ceil(beamwidth/degreesPerPixelV);
if ((numberOfCoeffsH & 1) == 0)
if ((numberOfCoeffsH & 1) == 0) {
numberOfCoeffsH++;
if ((numberOfCoeffsV & 1) == 0)
}
if ((numberOfCoeffsV & 1) == 0) {
numberOfCoeffsV++;
}
double *beam = new double[numberOfCoeffsH*numberOfCoeffsV];
double sum = 0.0;
int y0 = numberOfCoeffsV/2;
@ -780,16 +911,19 @@ void StarTrackerGUI::plotSkyTemperatureChart()
nonZeroCount++;
}
else
{
beam[y*numberOfCoeffsH+x] = 0.0;
}
}
}
// Get centre pixel coordinates
double centreX;
if (ra <= 12.0)
if (ra <= 12.0) {
centreX = (12.0 - ra) / 24.0;
else
} else {
centreX = (24 - ra + 12) / 24.0;
}
double centreY = (90.0-dec) / 180.0;
int imgX = centreX * fits->width();
int imgY = centreY * fits->height();
@ -831,12 +965,13 @@ void StarTrackerGUI::plotSkyTemperatureChart()
else
{
// See https://arxiv.org/abs/1812.10084 fig 2
if (m_settings.m_frequency < 200e6)
if (m_settings.m_frequency < 200e6) {
spectralIndex = 2.55;
else if (m_settings.m_frequency < 20e9)
} else if (m_settings.m_frequency < 20e9) {
spectralIndex = 2.695;
else
} else {
spectralIndex = 3.1;
}
}
double galactic480 = temp408 - cmbT - iso408;
double galacticT = galactic480 * pow(408e6/m_settings.m_frequency, spectralIndex); // Scale galactic contribution by frequency
@ -860,16 +995,19 @@ void StarTrackerGUI::plotSkyTemperatureChart()
QImage *img = &m_images[idx];
FITS *fits = &m_temps[idx/2];
double x;
if (ra <= 12.0)
if (ra <= 12.0) {
x = (12.0 - ra) / 24.0;
else
} else {
x = (24 - ra + 12) / 24.0;
int imgX = x * img->width();
if (imgX >= img->width())
imgX = img->width();
int imgY = (90.0-dec)/180.0 * img->height();
if (imgY >= img->height())
imgY = img->height();
}
int imgX = x * (img->width() - 1);
if (imgX >= img->width()) {
imgX = img->width() - 1;
}
int imgY = (90.0-dec)/180.0 * (img->height() - 1);
if (imgY >= img->height()) {
imgY = img->height() - 1;
}
if (fits->valid())
{
@ -883,8 +1021,13 @@ void StarTrackerGUI::plotSkyTemperatureChart()
markerSize = 5;
}
series->setMarkerSize(markerSize);
series->setColor(getSeriesColor(0));
m_chart.setTitle("");
// We want scatter to be on top of line, but same color even when no drift line
for (int i = 0; i < lineSeries.length(); i++) {
m_chart.addSeries(lineSeries[i]);
}
m_chart.addSeries(series);
if (galactic)
{
@ -894,6 +1037,12 @@ void StarTrackerGUI::plotSkyTemperatureChart()
m_skyTempYAxis.setTitleText(QString("Galactic latitude (%1)").arg(QChar(0xb0)));
m_chart.addAxis(&m_skyTempYAxis, Qt::AlignLeft);
series->attachAxis(&m_skyTempYAxis);
for (int i = 0; i < lineSeries.length(); i++)
{
lineSeries[i]->attachAxis(&m_skyTempGalacticLXAxis);
lineSeries[i]->attachAxis(&m_skyTempYAxis);
}
}
else
{
@ -903,6 +1052,12 @@ void StarTrackerGUI::plotSkyTemperatureChart()
m_skyTempYAxis.setTitleText(QString("Declination (%1)").arg(QChar(0xb0)));
m_chart.addAxis(&m_skyTempYAxis, Qt::AlignLeft);
series->attachAxis(&m_skyTempYAxis);
for (int i = 0; i < lineSeries.length(); i++)
{
lineSeries[i]->attachAxis(&m_skyTempRAXAxis);
lineSeries[i]->attachAxis(&m_skyTempYAxis);
}
}
ui->chart->setChart(&m_chart);
plotAreaChanged(m_chart.plotArea());
@ -965,7 +1120,7 @@ void StarTrackerGUI::plotElevationLineChart()
QList<QLineSeries *> azSeriesList;
QLineSeries *azSeries = new QLineSeries();
azSeriesList.append(azSeries);
QPen pen(QColor(153, 202, 83), 2, Qt::SolidLine);
QPen pen(getSeriesColor(1), 2, Qt::SolidLine);
azSeries->setPen(pen);
QDateTime dt;
@ -1172,7 +1327,7 @@ void StarTrackerGUI::plotElevationPolarChart()
QList<QLineSeries *> series;
series.append(new QLineSeries());
QLineSeries *s = series.first();
QPen pen(QColor(32, 159, 223), 2, Qt::SolidLine);
QPen pen(getSeriesColor(0), 2, Qt::SolidLine);
s->setPen(pen);
qreal prevAz = polarSeries->at(0).x();
@ -1467,7 +1622,7 @@ void StarTrackerGUI::updateSolarFlux(bool all)
}
if ((m_settings.m_solarFluxData == StarTrackerSettings::DRAO_2800) || all)
{
m_networkRequest.setUrl(QUrl("https://www.spaceweather.gc.ca/solarflux/sx-4-en.php"));
m_networkRequest.setUrl(QUrl("https://www.spaceweather.gc.ca/forecast-prevision/solar-solaire/solarflux/sx-4-en.php"));
m_networkManager->get(m_networkRequest);
}
}

View File

@ -102,9 +102,11 @@ private:
void applySettings(bool force = false);
void displaySettings();
void updateForTarget();
QString convertDegreesToText(double degrees);
bool handleMessage(const Message& message);
void updateLST();
void mapRaDec(double ra, double dec, bool galactic, double& x, double& y);
QList<QLineSeries*> createDriftScan(bool galactic);
QColor getSeriesColor(int series);
void plotElevationLineChart();
void plotElevationPolarChart();
void plotSkyTemperatureChart();
@ -133,6 +135,8 @@ private slots:
void on_longitude_valueChanged(double value);
void on_rightAscension_editingFinished();
void on_declination_editingFinished();
void on_azimuth_valueChanged(double value);
void on_elevation_valueChanged(double value);
void on_frequency_valueChanged(int value);
void on_beamwidth_valueChanged(double value);
void on_target_currentTextChanged(const QString &text);

View File

@ -67,13 +67,17 @@
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="1">
<widget class="QLineEdit" name="lst">
<property name="toolTip">
<string>Local sidereal time for selected date, time and longitude</string>
<item row="6" column="2">
<widget class="QLabel" name="beamwidthLabel">
<property name="text">
<string>Beamwidth</string>
</property>
<property name="readOnly">
<bool>true</bool>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
@ -84,86 +88,6 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="dateTimeSelect">
<property name="toolTip">
<string>Select time to calculate target's position at</string>
</property>
<item>
<property name="text">
<string>Now</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="frequencyLabel">
<property name="text">
<string>Frequency</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="WrappingDateTimeEdit" name="dateTime">
<property name="toolTip">
<string>Date and time to use when calculating target's position</string>
</property>
<property name="displayFormat">
<string>dd/MM/yyyy HH:mm:ss</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QLineEdit" name="declination">
<property name="toolTip">
<string>Declination of the target object
This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and seconds (E.g. 34d12m10.2s, 34d12'10.2&quot; 34 12 10.2)</string>
</property>
<property name="text">
<string>-90d59'59.59&quot;</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="rightAscension">
<property name="toolTip">
<string>Right Ascension of the target object.
This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds (E.g. 12h05m10.2s or 12 05 10.2)</string>
</property>
<property name="text">
<string>23h59m59.59s</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QDoubleSpinBox" name="longitude">
<property name="toolTip">
<string>Longitude in decimal degress (East positive) of observation point / antenna location</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
<property name="value">
<double>-180.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="frequency">
<property name="toolTip">
@ -177,40 +101,6 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lstLabel">
<property name="text">
<string>LST</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="longitudeLabel">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="targetLabel">
<property name="text">
<string>Target</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="azimuth">
<property name="toolTip">
<string>Computed azimuth in degrees to the target from the observation point</string>
</property>
<property name="text">
<string>360</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="azimuthtLabel">
<property name="text">
@ -218,95 +108,26 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="solarFluxLabel">
<item row="7" column="0">
<widget class="QLabel" name="rightAscensionLabel">
<property name="text">
<string>Solar Flux</string>
<string>RA</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="3">
<layout class="QHBoxLayout" name="targetLayout">
<item>
<widget class="QComboBox" name="target">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Target object</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Sun</string>
</property>
</item>
<item>
<property name="text">
<string>Moon</string>
</property>
</item>
<item>
<property name="text">
<string>PSR B0329+54</string>
</property>
</item>
<item>
<property name="text">
<string>PSR B0833-45</string>
</property>
</item>
<item>
<property name="text">
<string>Sagittarius A</string>
</property>
</item>
<item>
<property name="text">
<string>Cassiopeia A</string>
</property>
</item>
<item>
<property name="text">
<string>Cygnus A</string>
</property>
</item>
<item>
<property name="text">
<string>Taurus A (M1)</string>
</property>
</item>
<item>
<property name="text">
<string>Virgo A (M87)</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<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 row="4" column="0">
<widget class="QLabel" name="lstLabel">
<property name="text">
<string>LST</string>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QLabel" name="elevationLabel">
<property name="text">
<string>Elevation</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<layout class="QHBoxLayout" name="buttonLayout">
@ -396,80 +217,32 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="latitude">
<property name="toolTip">
<string>Latitude in decimal degrees (North positive) of observation point / antenna location</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-90.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
<property name="value">
<double>-90.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QLabel" name="elevationLabel">
<property name="text">
<string>Elevation</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="beamwidthLabel">
<property name="text">
<string>Beamwidth</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="rightAscensionLabel">
<property name="text">
<string>RA</string>
</property>
</widget>
</item>
<item row="8" column="3">
<widget class="QLineEdit" name="elevation">
<widget class="DMSSpinBox" name="elevation" native="true">
<property name="toolTip">
<string>Computed elevation in degrees to the target from the observation point</string>
<string>Elevation in degrees to the target from the observation point</string>
</property>
<property name="text">
<string>90</string>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lst">
<property name="toolTip">
<string>Local sidereal time for selected date, time and longitude</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLineEdit" name="solarFlux">
<item row="7" column="3">
<widget class="QLineEdit" name="declination">
<property name="toolTip">
<string>Solar flux density</string>
<string>Declination of the target object
This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and seconds (E.g. 34d12m10.2s, 34d12'10.2&quot; 34 12 10.2)</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="latitudeLabel">
<property name="text">
<string>Latitude</string>
<string>-90d59'59.59&quot;</string>
</property>
</widget>
</item>
@ -492,6 +265,226 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
</property>
</widget>
</item>
<item row="5" column="1" colspan="3">
<layout class="QHBoxLayout" name="targetLayout">
<item>
<widget class="QComboBox" name="target">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Target object</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Sun</string>
</property>
</item>
<item>
<property name="text">
<string>Moon</string>
</property>
</item>
<item>
<property name="text">
<string>PSR B0329+54</string>
</property>
</item>
<item>
<property name="text">
<string>PSR B0833-45</string>
</property>
</item>
<item>
<property name="text">
<string>Sagittarius A</string>
</property>
</item>
<item>
<property name="text">
<string>Cassiopeia A</string>
</property>
</item>
<item>
<property name="text">
<string>Cygnus A</string>
</property>
</item>
<item>
<property name="text">
<string>Taurus A (M1)</string>
</property>
</item>
<item>
<property name="text">
<string>Virgo A (M87)</string>
</property>
</item>
<item>
<property name="text">
<string>Custom RA/Dec</string>
</property>
</item>
<item>
<property name="text">
<string>Custom Az/El</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<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 row="3" column="1">
<widget class="QComboBox" name="dateTimeSelect">
<property name="toolTip">
<string>Select time to calculate target's position at</string>
</property>
<item>
<property name="text">
<string>Now</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="latitudeLabel">
<property name="text">
<string>Latitude</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="frequencyLabel">
<property name="text">
<string>Frequency</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="WrappingDateTimeEdit" name="dateTime">
<property name="toolTip">
<string>Date and time to use when calculating target's position</string>
</property>
<property name="displayFormat">
<string>dd/MM/yyyy HH:mm:ss</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLineEdit" name="solarFlux">
<property name="toolTip">
<string>Solar flux density</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="targetLabel">
<property name="text">
<string>Target</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="rightAscension">
<property name="toolTip">
<string>Right Ascension of the target object.
This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds (E.g. 12h05m10.2s or 12 05 10.2)</string>
</property>
<property name="text">
<string>23h59m59.59s</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="longitudeLabel">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QDoubleSpinBox" name="longitude">
<property name="toolTip">
<string>Longitude in decimal degress (East positive) of observation point / antenna location</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
<property name="value">
<double>-180.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="solarFluxLabel">
<property name="text">
<string>Solar Flux</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="latitude">
<property name="toolTip">
<string>Latitude in decimal degrees (North positive) of observation point / antenna location</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-90.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
<property name="value">
<double>-90.000000000000000</double>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="DMSSpinBox" name="azimuth" native="true">
<property name="toolTip">
<string>Azimuth in degrees to the target from the observation point</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -619,6 +612,11 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
<header>gui/wrappingdatetimeedit.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DMSSpinBox</class>
<extends>QWidget</extends>
<header>gui/dmsspinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>startStop</tabstop>
@ -637,10 +635,9 @@ This can be specified as a decimal (E.g. 12.23) or in hours, minutes and seconds
<tabstop>beamwidth</tabstop>
<tabstop>rightAscension</tabstop>
<tabstop>declination</tabstop>
<tabstop>azimuth</tabstop>
<tabstop>elevation</tabstop>
<tabstop>chartSelect</tabstop>
<tabstop>chartSubSelect</tabstop>
<tabstop>darkTheme</tabstop>
<tabstop>chart</tabstop>
</tabstops>
<resources>

View File

@ -20,8 +20,10 @@
#define INCLUDE_FEATURE_STARTRACKERREPORT_H_
#include <QObject>
#include <QList>
#include "util/message.h"
#include "util/astronomy.h"
class StarTrackerReport : public QObject
{

View File

@ -62,6 +62,8 @@ void StarTrackerSettings::resetToDefaults()
m_reverseAPIPort = 8888;
m_reverseAPIFeatureSetIndex = 0;
m_reverseAPIFeatureIndex = 0;
m_az = 0.0;
m_el = 0.0;
}
QByteArray StarTrackerSettings::serialize() const
@ -100,6 +102,8 @@ QByteArray StarTrackerSettings::serialize() const
s.writeDouble(30, m_beamwidth);
s.writeU32(31, m_solarFluxData);
s.writeBool(32, m_chartsDarkTheme);
s.writeDouble(33, m_az);
s.writeDouble(34, m_el);
return s.final();
}
@ -169,6 +173,9 @@ bool StarTrackerSettings::deserialize(const QByteArray& data)
d.readU32(31, (quint32 *)&m_solarFluxData, DRAO_2800);
d.readBool(32, &m_chartsDarkTheme, true);
d.readDouble(33, &m_az, 0.0);
d.readDouble(34, &m_el, 0.0);
return true;
}
else

View File

@ -44,7 +44,7 @@ struct StarTrackerSettings
double m_beamwidth; // Beamwidth in degrees
uint16_t m_serverPort;
bool m_enableServer; // Enable Stellarium server
enum AzElUnits {DMS, DM, D, Decimal} m_azElUnits;
enum AzElUnits {DMS, DM, D, Decimal} m_azElUnits; // This needs to match DMSSpinBox::DisplayUnits
enum SolarFluxData {DRAO_2800, L_245, L_410, L_610, L_1415, L2695, L_4995, L_8800, L_15400, TARGET_FREQ} m_solarFluxData; // What Solar flux density data to display
enum SolarFluxUnits {SFU, JANSKY, WATTS_M_HZ} m_solarFluxUnits;
float m_updatePeriod;
@ -53,7 +53,6 @@ struct StarTrackerSettings
bool m_drawMoonOnMap;
bool m_drawStarOnMap;
bool m_chartsDarkTheme; // Dark theme for charts
QString m_title;
quint32 m_rgbColor;
bool m_useReverseAPI;
@ -61,6 +60,8 @@ struct StarTrackerSettings
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIFeatureSetIndex;
uint16_t m_reverseAPIFeatureIndex;
double m_az; // Azimuth for Custom Az/El
double m_el; // Elevation for Custom Az/El
StarTrackerSettings();
void resetToDefaults();

View File

@ -463,6 +463,13 @@ void StarTrackerWorker::update()
rd = moonRD;
aa = moonAA;
}
else if (m_settings.m_target == "Custom Az/El")
{
// Convert Alt/Az to RA/Dec
aa.alt = m_settings.m_el;
aa.az = m_settings.m_az;
rd = Astronomy::azAltToRaDec(aa, m_settings.m_latitude, m_settings.m_longitude, dt);
}
else
{
// Convert RA/Dec to Alt/Az
@ -491,8 +498,11 @@ void StarTrackerWorker::update()
// Send to GUI
if (getMessageQueueToGUI())
{
StarTrackerReport::MsgReportAzAl *msg = StarTrackerReport::MsgReportAzAl::create(aa.az, aa.alt);
getMessageQueueToGUI()->push(msg);
if (m_settings.m_target == "Custom Az/El") {
getMessageQueueToGUI()->push(StarTrackerReport::MsgReportRADec::create(rd.ra, rd.dec));
} else {
getMessageQueueToGUI()->push(StarTrackerReport::MsgReportAzAl::create(aa.az, aa.alt));
}
}
// Send Az/El to Rotator Controllers
@ -542,7 +552,7 @@ void StarTrackerWorker::update()
{
double starLongitude = Astronomy::lstAndRAToLongitude(lst, rd.ra);
double starLatitude = rd.dec;
QString text = m_settings.m_target == "Custom" ? "Star" : m_settings.m_target;
QString text = m_settings.m_target.startsWith("Custom") ? "Star" : m_settings.m_target;
sendToMap(mapMessageQueues, "Star", "qrc:///startracker/startracker/pulsar-32.png", text, starLatitude, starLongitude);
}
}

View File

@ -216,6 +216,47 @@ AzAlt Astronomy::raDecToAzAlt(RADec rd, double latitude, double longitude, QDate
return aa;
}
// Convert from altitude and azimuth, for location (decimal degrees) and time, to Jnow right ascension (decimal hours) and declination (decimal degrees)
// See: http://jonvoisey.net/blog/2018/07/data-converting-alt-az-to-ra-dec-example/
RADec Astronomy::azAltToRaDec(AzAlt aa, double latitude, double longitude, QDateTime dt)
{
RADec rd;
double lst_deg; // Local sidereal time
double ha_rad, ha_deg; // Hour angle
double alt_rad, az_rad, lat_rad, dec_rad; // Corresponding variables as radians
// Calculate local mean sidereal time (LMST) in degrees (see raDecToAzAlt)
lst_deg = Astronomy::localSiderealTime(dt, longitude);
// Convert degrees to radians
alt_rad = Units::degreesToRadians(aa.alt);
az_rad = Units::degreesToRadians(aa.az);
lat_rad = Units::degreesToRadians(latitude);
// Calculate declination
dec_rad = asin(sin(lat_rad)*sin(alt_rad)+cos(lat_rad)*cos(alt_rad)*cos(az_rad));
// Calculate hour angle
double quotient = (sin(alt_rad)-sin(lat_rad)*sin(dec_rad))/(cos(lat_rad)*cos(dec_rad));
// At extreme altitudes, we seem to get small numerical errors that causes values to be out of range, so clip to [-1,1]
if (quotient < -1.0) {
ha_rad = acos(-1.0);
} else if (quotient > 1.0) {
ha_rad = acos(1.0);
} else {
ha_rad = acos(quotient);
}
// Convert radians to degrees
rd.dec = Units::radiansToDegrees(dec_rad);
ha_deg = Units::radiansToDegrees(ha_rad);
// Calculate right ascension in decimal hours
rd.ra = modulo((lst_deg - ha_deg) / (360.0/24.0), 24.0);
return rd;
}
// Needs to work for negative a
double Astronomy::modulo(double a, double b)
{
@ -493,10 +534,11 @@ double Astronomy::lstAndRAToLongitude(double lst, double raHours)
}
// Return right ascension and declination of North Galactic Pole in J2000 Epoch
// http://www.lsc-group.phys.uwm.edu/lal/lsd/node1777.html
void Astronomy::northGalacticPoleJ2000(double& ra, double& dec)
{
ra = 12 + 51.4 / 60.0;
dec = 27.13;
ra = 192.8594813/15.0;
dec = 27.1282511;
}
// Convert from equatorial to Galactic coordinates, J2000 Epoch
@ -511,40 +553,24 @@ void Astronomy::equatorialToGalactic(double ra, double dec, double& l, double& b
const double ngpRaRad = Units::degreesToRadians(ngpRa * 15.0);
const double ngpDecRad = Units::degreesToRadians(ngpDec);
// Calculate galactic latitude for North Celestial pole, J2000
const double ncpLRad = Units::degreesToRadians(122.93192);
// Calculate galactic longitude in radians
double bRad = asin(sin(ngpDecRad)*sin(decRad)+cos(ngpDecRad)*cos(decRad)*cos(raRad - ngpRaRad));
// Find the two possible solutions for galactic longitude in radians
double rhs1 = cos(decRad)*sin(raRad-ngpRaRad)/cos(bRad);
double rhs2 = (-cos(decRad)*sin(ngpDecRad)*cos(raRad-ngpRaRad)+sin(decRad)*cos(ngpDecRad))/cos(bRad);
double l1 = ncpLRad - asin(rhs1);
double l2 = ncpLRad - acos(rhs2);
// Calculate galactic latitiude in radians
double lRad = atan2(sin(decRad)-sin(bRad)*sin(ngpDecRad), cos(decRad)*cos(ngpDecRad)*sin(raRad - ngpRaRad));
// Plug them back in and select solution which is valid for both equations
// (Error should be 0, but we have to allow for small numerical differences)
// There's probably a better way to solve this.
double l1lhs1 = sin(ncpLRad - l1);
double l1lhs2 = cos(ncpLRad - l1);
double l2lhs1 = sin(ncpLRad - l2);
double l2lhs2 = cos(ncpLRad - l2);
double l1Diff = abs(l1lhs1 - rhs1) + abs(l1lhs2 - rhs2);
double l2Diff = abs(l2lhs1 - rhs1) + abs(l2lhs2 - rhs2);
double lRad;
if (l1Diff < l2Diff)
lRad = l1;
else
lRad = l2;
// Ascending node of the galactic plane in degrees
double lAscend = 33.0;
// Convert to degrees in range -90,90 and 0,360
b = Units::radiansToDegrees(bRad);
l = Units::radiansToDegrees(lRad);
if (l < 0.0)
l = Units::radiansToDegrees(lRad) + lAscend;
if (l < 0.0) {
l += 360.0;
if (l > 360.0)
}
if (l > 360.0) {
l -= 360.0;
}
}
// The following functions are from Starlink Positional Astronomy Library

View File

@ -46,6 +46,7 @@ public:
static RADec precess(RADec rd_in, double jd_from, double jd_to);
static AzAlt raDecToAzAlt(RADec rd, double latitude, double longitude, QDateTime dt, bool j2000=true);
static RADec azAltToRaDec(AzAlt aa, double latitude, double longitude, QDateTime dt);
static double localSiderealTime(QDateTime dateTime, double longitude);

View File

@ -142,9 +142,50 @@ public:
return hours + minutes * 1.0f/60.0f + seconds * 1.0f/(60.0f*60.0f);
}
// Also supports decimal degrees
static bool degreeMinuteAndSecondsToDecimalDegrees(const QString& string, float& degrees)
{
QRegExp decimal("(-?[0-9]+(\\.[0-9]+)?)");
if (decimal.exactMatch(string))
{
degrees = decimal.capturedTexts()[1].toFloat();
return true;
}
QRegExp dms(QString("(-)?([0-9]+)[%1d](([0-9]+)['m](([0-9]+(\\.[0-9]+)?)[\"s])?)?").arg(QChar(0xb0)));
if (dms.exactMatch(string))
{
float d = 0.0f;
bool neg = false;
for (int i = 0; i < dms.captureCount(); i++) {
qDebug() << dms.capturedTexts()[i];
}
if (dms.captureCount() >= 1) {
neg = dms.capturedTexts()[1] == "-";
}
if (dms.captureCount() >= 3) {
d = dms.capturedTexts()[2].toFloat();
}
float m = 0.0f;
if (dms.captureCount() >= 5) {
m = dms.capturedTexts()[4].toFloat();
}
float s = 0.0f;
if (dms.captureCount() >= 7) {
s = dms.capturedTexts()[6].toFloat();
}
qDebug() << neg << d << m << s;
degrees = d + m/60.0 + s/(60.0*60.0);
if (neg) {
degrees = -degrees;
}
return true;
}
return false;
}
static QString decimalDegreesToDegreeMinutesAndSeconds(float decimal, int secondsFieldWidth=5)
{
float v, d, m, s;
double v, d, m, s;
int neg;
v = decimal;
@ -162,7 +203,7 @@ public:
static QString decimalDegreesToDegreesAndMinutes(float decimal)
{
float v, d, m;
double v, d, m;
int neg;
v = decimal;
@ -172,12 +213,21 @@ public:
v -= d;
v *= 60.0;
m = round(v);
if (m == 60)
{
if (neg) {
d--;
} else {
d++;
}
m = 0;
}
return QString("%1%2%3%4'").arg(neg ? "-" : "").arg((int)d).arg(QChar(0xb0)).arg((int)m, 2, 10, QChar('0'));
}
static QString decimalDegreesToDegrees(float decimal)
{
float v, d;
double v, d;
int neg;
v = decimal;
@ -189,7 +239,7 @@ public:
static QString decimalHoursToHoursMinutesAndSeconds(float decimal, int precision=2)
{
float v, h, m, s;
double v, h, m, s;
v = decimal;
v = fabs(v);
@ -218,7 +268,6 @@ public:
QRegExp dms(QString("([0-9]+)[%1d]([0-9]+)['m]([0-9]+(\\.[0-9]+)?)[\"s]([NS]) *,? *([0-9]+)[%1d]([0-9]+)['m]([0-9]+(\\.[0-9]+)?)[\"s]([EW])").arg(QChar(0xb0)));
if (dms.exactMatch(string))
{
qDebug() << "Captured: " << dms.capturedTexts();
float latD = dms.capturedTexts()[1].toFloat();
float latM = dms.capturedTexts()[2].toFloat();
float latS = dms.capturedTexts()[3].toFloat();
@ -233,8 +282,6 @@ public:
longitude = lonD + lonM/60.0 + lonS/(60.0*60.0);
if (!east)
longitude = -longitude;
qDebug() << "Lat " << latitude;
qDebug() << "Long " << longitude;
return true;
}
return false;

View File

@ -28,6 +28,7 @@ set(sdrgui_SOURCES
gui/cwkeyergui.cpp
gui/devicestreamselectiondialog.cpp
gui/deviceuserargsdialog.cpp
gui/dmsspinbox.cpp
gui/editcommanddialog.cpp
gui/externalclockbutton.cpp
gui/externalclockdialog.cpp
@ -114,6 +115,7 @@ set(sdrgui_HEADERS
gui/cwkeyergui.h
gui/devicestreamselectiondialog.h
gui/deviceuserargsdialog.h
gui/dmsspinbox.h
gui/doublevalidator.h
gui/editcommanddialog.h
gui/externalclockbutton.h

126
sdrgui/gui/dmsspinbox.cpp Normal file
View File

@ -0,0 +1,126 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QLineEdit>
#include "util/units.h"
#include "dmsspinbox.h"
DMSSpinBox::DMSSpinBox(QWidget *parent) :
QAbstractSpinBox(parent),
m_value(0.0),
m_minimum(0.0),
m_maximum(360.0),
m_units(DM)
{
setButtonSymbols(QAbstractSpinBox::UpDownArrows);
connect(lineEdit(), SIGNAL(editingFinished()), this, SLOT(on_lineEdit_editingFinished()));
}
bool DMSSpinBox::hasValue() const
{
return m_text.isNull();
}
double DMSSpinBox::value() const
{
return m_value;
}
void DMSSpinBox::setValue(double degrees)
{
if (m_value != degrees)
{
m_value = degrees;
if (m_value < m_minimum) {
m_value = m_minimum;
}
if (m_value > m_maximum) {
m_value = m_maximum;
}
m_text = QString();
emit valueChanged(m_value);
}
lineEdit()->setText(convertDegreesToText(m_value));
}
void DMSSpinBox::setRange(double minimum, double maximum)
{
m_minimum = minimum;
m_maximum = maximum;
}
void DMSSpinBox::setUnits(DisplayUnits units)
{
m_units = units;
if (hasValue()) {
lineEdit()->setText(convertDegreesToText(m_value));
}
}
void DMSSpinBox::setText(QString text)
{
m_text = text;
lineEdit()->setText(m_text);
}
void DMSSpinBox::stepBy(int steps)
{
if (hasValue()) {
setValue(m_value + (double)steps);
}
}
QAbstractSpinBox::StepEnabled DMSSpinBox::stepEnabled() const
{
QAbstractSpinBox::StepEnabled enabled = QAbstractSpinBox::StepNone;
if (hasValue() && (m_value < m_maximum)) {
enabled |= QAbstractSpinBox::StepUpEnabled;
}
if (hasValue() && (m_value > m_minimum)) {
enabled |= QAbstractSpinBox::StepDownEnabled;
}
return enabled;
}
QString DMSSpinBox::convertDegreesToText(double degrees)
{
if (m_units == DMS) {
return Units::decimalDegreesToDegreeMinutesAndSeconds(degrees);
} else if (m_units == DM) {
return Units::decimalDegreesToDegreesAndMinutes(degrees);
} else if (m_units == D) {
return Units::decimalDegreesToDegrees(degrees);
} else {
return QString("%1").arg(degrees, 0, 'f', 2);
}
}
void DMSSpinBox::on_lineEdit_editingFinished()
{
QString text = lineEdit()->text().trimmed();
float decimal;
if (Units::degreeMinuteAndSecondsToDecimalDegrees(text, decimal)) {
setValue(decimal);
} else {
qDebug() << "DMSSpinBox::on_lineEdit_editingFinished: Invalid format: " << text;
}
}

62
sdrgui/gui/dmsspinbox.h Normal file
View File

@ -0,0 +1,62 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRGUI_GUI_DMSSPINBOX_H
#define SDRGUI_GUI_DMSSPINBOX_H
#include <QAbstractSpinBox>
#include "export.h"
// Spin box for displaying degrees in decimal or degrees, minutes and seconds format
// Can also be assigned a text string
class SDRGUI_API DMSSpinBox : public QAbstractSpinBox {
Q_OBJECT
public:
enum DisplayUnits {DMS, DM, D, Decimal};
explicit DMSSpinBox(QWidget *parent = nullptr);
bool hasValue() const;
double value() const;
void setValue(double degrees);
void setRange(double minimum, double maximum);
void setUnits(DisplayUnits units);
void setText(QString text);
virtual void stepBy(int steps) override;
protected:
virtual QAbstractSpinBox::StepEnabled stepEnabled() const override;
QString convertDegreesToText(double degrees);
private:
QString m_text;
double m_value;
double m_minimum;
double m_maximum;
DisplayUnits m_units;
signals:
void valueChanged(double newValue);
private slots:
void on_lineEdit_editingFinished();
};
#endif // SDRGUI_GUI_DMSSPINBOX_H