Merge pull request #761 from srcejon/star_tracker_temp
Star tracker updates
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.fits binary
|
BIN
doc/img/StarTracker_elevationvstime.png
Normal file
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 76 KiB |
BIN
doc/img/StarTracker_skytemp.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
doc/img/StarTracker_solarflux.png
Normal file
After Width: | Height: | Size: 15 KiB |
@ -199,7 +199,7 @@ struct Beacon {
|
||||
idx++;
|
||||
}
|
||||
float latitude, longitude;
|
||||
if (callsign && frequency && locator && Maidenhead::fromMaidenhead(locator, latitude, longitude))
|
||||
if (callsign && frequencyString && locator && Maidenhead::fromMaidenhead(locator, latitude, longitude))
|
||||
{
|
||||
Beacon *beacon = new Beacon();
|
||||
beacon->m_callsign = callsign;
|
||||
|
@ -5,9 +5,10 @@
|
||||
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.
|
||||
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.
|
||||
|
||||
<h2>Interface</h2>
|
||||
<h2>Settings</h2>
|
||||
|
||||
![Star Tracker feature plugin GUI](../../../doc/img/StarTracker_plugin.png)
|
||||
|
||||
@ -19,24 +20,28 @@ This button starts or stops the plugin. The plugin will only calculate azimuth a
|
||||
|
||||
Pressing this button centres the Map Feature (if open) on the current target.
|
||||
|
||||
<h3>3: Set latitude and longitude from My Position</h3>
|
||||
<h3>3:Download Solar flux density data</h3>
|
||||
|
||||
Pressing this button downloads the Solar flux density data from the DRAO and Learmonth Observatories.
|
||||
|
||||
<h3>4: Set latitude and longitude from My Position</h3>
|
||||
|
||||
When clicked, it sets the latitude, longitude and height fields to the values from SDRangel's My Position preferences.
|
||||
|
||||
<h3>4: Show settings dialog</h3>
|
||||
<h3>5: Show settings dialog</h3>
|
||||
|
||||
Pressing this button displays a settings dialog, that allows you to set:
|
||||
|
||||
* The epoch used when entering RA and Dec. This can be either J2000 (which is used for most catalogues) or JNOW which is the current date and time.
|
||||
* The units used for the display of the calculated azimuth and elevation. This can be either degrees, minutes and seconds or decimal degrees.
|
||||
* Whether to correct for atmospheric refaction. You can choose either no correction, the Saemundsson algorithm, typically used for optical astronomy or the more accurate Positional Astronomy Library calculation, which can be used for >250MHz radio frequencies or light. Note that there is only a very minor difference between the two.
|
||||
* Whether to correct for atmospheric refraction. You can choose either no correction, the Saemundsson algorithm, typically used for optical astronomy or the more accurate Positional Astronomy Library calculation, which can be used for >250MHz radio frequencies or light. Note that there is only a very minor difference between the two.
|
||||
* Air pressure in millibars for use in refraction correction.
|
||||
* Air temperature in degrees Celsius for use in refraction correction.
|
||||
* Relative humidity in % for use in refraction correction.
|
||||
* Height above sea level in metres for use in refraction correction.
|
||||
* Temperature lapse rate in Kelvin per kilometer for use in refraction correction.
|
||||
* Radio frequency being observed in MHz for use in refraction correction.
|
||||
* The units to display the solar flux in.
|
||||
* Temperature lapse rate in Kelvin per kilometre for use in refraction correction.
|
||||
* What data to display for the Solar flux measurement. Data can be selected from 2800 from DRAO or a number of different frequencies from Learmonth. Also, the Learmonth data can be linearly interpolated to the observation frequency set in the main window.
|
||||
* The units to display the solar flux in, either Solar Flux Units, Jansky or Wm^-2Hz-1. 1 sfu equals 10,000 Jansky or 10^-22 Wm^-2Hz-1.
|
||||
* The update period in seconds, which controls how frequently azimuth and elevation are re-calculated.
|
||||
* The IP port number the Stellarium server listens on.
|
||||
* Whether to start a Stellarium telescope server.
|
||||
@ -44,29 +49,27 @@ Pressing this button displays a settings dialog, that allows you to set:
|
||||
* Whether to draw the Moon on the map.
|
||||
* Whether to draw the target star (or galaxy) on the map.
|
||||
|
||||
<h3>5: Latitude</h3>
|
||||
<h3>6: Latitude</h3>
|
||||
|
||||
Specifies the latitude in decimal degrees of the observation point (antenna location).
|
||||
Specifies the latitude in decimal degrees (North positive) of the observation point (antenna location).
|
||||
|
||||
<h3>6: Longitude</h3>
|
||||
<h3>7: Longitude</h3>
|
||||
|
||||
Specifies the longitude in decimal degrees of the observation point (antenna location).
|
||||
Specifies the longitude in decimal degrees (East positive) of the observation point (antenna location).
|
||||
|
||||
<h3>7: Time</h3>
|
||||
<h3>8: Time</h3>
|
||||
|
||||
Select the date and time at which the position of the target should be calculated. Select either Now, for the current time, or Custom to manually enter a date and time.
|
||||
|
||||
<h3>8: LST - Local Sidereal Time</h3>
|
||||
<h3>9: LST - Local Sidereal Time</h3>
|
||||
|
||||
The LST field displays the local sidereal time at the specified location (5&6) and Solar time (7).
|
||||
The LST field displays the local sidereal time at the specified location (6&7) and Solar time (8).
|
||||
|
||||
<h3>9: Solar Flux</h3>
|
||||
<h3>10: Solar Flux</h3>
|
||||
|
||||
The Canadian Solar Radio Monitoring Program measures the Solar flux at 10.7cm three times a day, and is reported in Solar Flux Units (sfu), where 1 SFU equals 10,000 Jansky or 10^-22 Wm^-2Hz-1.
|
||||
Displays the Solar flux density. The observatory where the data is sourced from, frequency and units can be set in the Settings dialog (5). The field is updated every 24 hours, or can be manually by pressing the download Solar flux density data button (3).
|
||||
|
||||
The Solar flux field displays this flux value, using units that can be set in the settings dialog. The field is updated every 24 hours.
|
||||
|
||||
<h3>10: Target</h3>
|
||||
<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.
|
||||
@ -78,7 +81,7 @@ To allow Stellarium to set the RA and Dec, select Custom, and ensure the Stellar
|
||||
| Moon | Moon | Targets our Moon | 2 (50MHz), 1000 (1.4GHz) |
|
||||
| PSR B0329+54 | Pulsar | Strongest in Northern hemisphere (J0332+5434) | 1.8 (50MHz), 1.5 (400MHz), 0.2 (1.4GHz) |
|
||||
| PSR B0833-45 | Pulsar | Strongest in Southern hemisphere (J0835-4510) | 5.4 (150MHz), 5.0 (400MHz), 1.0 (1.4GHz) |
|
||||
| Sagittarius A | Galatic centre | First detected source of extrasolar radio | ~0.5 (<1GHz) for Sgr A* |
|
||||
| Sagittarius A | Galactic centre | First detected source of extrasolar radio | ~0.5 (<1GHz) for Sgr A* |
|
||||
| Cassiopeia A | Supernova | Brightest extrasolar radio source | 27k (50MHz), 10k (150MHz), 1768 (1.4GHz) |
|
||||
| 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) |
|
||||
@ -91,26 +94,55 @@ References:
|
||||
* Cassiopeia A, Cygnus A, Taurus A, and Virgo A at ultra-low radio frequencies - https://research.chalmers.se/publication/516438/file/516438_Fulltext.pdf
|
||||
* Repeating Jansky - https://www.gb.nrao.edu/~fghigo/JanskyAntenna/RepeatingJansky_memo10.pdf
|
||||
|
||||
<h3>11: Right Ascension</h3>
|
||||
<h3>12: Frequency</h3>
|
||||
|
||||
Enter the frequency of observation in MHz. This value is used for sky temperature and refraction calculations.
|
||||
|
||||
<h3>13: Beamwidth</h3>
|
||||
|
||||
Enter the half power (-3dB) beamwidth of your antenna. This value is used for sky temperature calculation.
|
||||
|
||||
<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.
|
||||
|
||||
<h3>12: Declination</h3>
|
||||
<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.
|
||||
|
||||
<h3>13: Azimuth</h3>
|
||||
<h3>16: Azimuth</h3>
|
||||
|
||||
Displays the calculated azimuth (angle in degrees, clockwise from North) to the object.
|
||||
|
||||
<h3>14: Elevation</h3>
|
||||
<h3>17: Elevation</h3>
|
||||
|
||||
Displays the calculated elevation (angle in degrees - 0 to horizon and 90 to zenith) to the object.
|
||||
|
||||
<h3>13: Elevation vs Time Plot</h3>
|
||||
<h2>Plots</h2>
|
||||
|
||||
In order to assit 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.
|
||||
Some objects may not be visible from a particular latitude for the specified time, in which case, the grahp title will indicate the object is not visible on that particular date.
|
||||
<h3>Elevation vs time</h3>
|
||||
|
||||
![Star Tracker Elevation vs Time](../../../doc/img/StarTracker_elevationvstime.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.
|
||||
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>
|
||||
|
||||
![Star Tracker Solar Flux](../../../doc/img/StarTracker_solarflux.png)
|
||||
|
||||
The Solar flux vs frequency plot, shows the solar flux density data from the Learmonth observatory as a function of frequency. The measurements are made at 245, 410, 610, 1415, 2695, 4995, 8800 and 15400MHz.
|
||||
|
||||
<h3>Sky temperature</h3>
|
||||
|
||||
![Star Tracker sky temperature](../../../doc/img/StarTracker_skytemp.png)
|
||||
|
||||
Background sky temperature maps are available for display at 150MHz, 408MHz and 1420MHz, in both equatorial and galactic coordinates.
|
||||
For these first six temperature maps, the temperature reported, which is in Kelvin, is for the single pixel corresponding to the target coordinates.
|
||||
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.
|
||||
|
||||
<h2>Map</h2>
|
||||
|
||||
@ -134,7 +166,7 @@ Then in Stellarium:
|
||||
* Press the telescope button in the main toolbar
|
||||
* Press "Configure telescopes..."
|
||||
* Press "Add a new telescope"
|
||||
* Set "Telescope controlled by" to "External softare or a remote computer"
|
||||
* Set "Telescope controlled by" to "External software or a remote computer"
|
||||
* Set "Name" to "SDRangel" (Optional)
|
||||
* Set "Coordinate system" to "J2000 (default)"
|
||||
* Press OK
|
||||
@ -150,7 +182,13 @@ Then select the SDRangel telescope reticle and press Ocular view.
|
||||
|
||||
<h2>Attribution</h2>
|
||||
|
||||
Solar radio flux measurement at 10.7cm 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/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
|
||||
|
||||
150MHz (Landecker and Wielebinski) and 1420MHz (Stockert and Villa-Elisa) All Sky images from MPIfR's (Max-Planck-Institut Fur Radioastronomie) Survey Sampler: https://www3.mpifr-bonn.mpg.de/survey.html
|
||||
|
||||
408MHz (Haslam) destriped (Platania) All Sky image and spectral index (Platania) from Strasbourg astronomical Data Center: http://cdsarc.u-strasbg.fr/viz-bin/cat/J/A+A/410/847
|
||||
|
||||
Icons are by Adnen Kadri and Erik Madsen, from the Noun Project Noun Project: https://thenounproject.com/
|
||||
|
||||
@ -169,3 +207,26 @@ Or to a custom RA and declination on a given date and time:
|
||||
To start tracking:
|
||||
|
||||
curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/run"
|
||||
|
||||
<h2>Developer Notes</h2>
|
||||
|
||||
To convert FITS images between projections, use Montage:
|
||||
|
||||
sudo apg-get install montage wcslib-tools
|
||||
|
||||
Create header for desired output image. E.g. For galatic coordinates, 0.3deg per pixel, covering 360/180 degrees:
|
||||
|
||||
mHdr -c ga -p 1200 -h 180.0 "0.0 +0.0" 360 header.hdr
|
||||
|
||||
This uses a gnomonic projection. To change to cylindrical/plate carree, with the centre of the galaxy at the centre of the image, edit header.hdr to have:
|
||||
|
||||
CTYPE1 = 'GLON-CAR'
|
||||
CTYPE2 = 'GLAT-CAR'
|
||||
CRVAL1 = 0
|
||||
CRVAL2 = 0
|
||||
|
||||
Then convert with:
|
||||
|
||||
mProjectQL source.fits dest.fits header.hdr
|
||||
|
||||
FITS files can be scaled (Scale > ZScale) and exported to .png with SAOImageDS9: https://sites.google.com/cfa.harvard.edu/saoimageds9
|
||||
|
@ -13,5 +13,16 @@
|
||||
<file>startracker/moon-young-32.png</file>
|
||||
<file>startracker/pulsar-32.png</file>
|
||||
<file>startracker/sun-40.png</file>
|
||||
<file>startracker/sun-button-24.png</file>
|
||||
<file>startracker/150mhz_ra_dec.png</file>
|
||||
<file>startracker/408mhz_ra_dec.png</file>
|
||||
<file>startracker/1420mhz_ra_dec.png</file>
|
||||
<file>startracker/150mhz_galactic.png</file>
|
||||
<file>startracker/408mhz_galactic.png</file>
|
||||
<file>startracker/1420mhz_galactic.png</file>
|
||||
<file>startracker/150mhz_ra_dec.fits</file>
|
||||
<file>startracker/408mhz_ra_dec.fits</file>
|
||||
<file>startracker/1420mhz_ra_dec.fits</file>
|
||||
<file>startracker/408mhz_ra_dec_spectral_index.fits</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
BIN
plugins/feature/startracker/startracker/1420mhz_galactic.png
Normal file
After Width: | Height: | Size: 641 KiB |
2444
plugins/feature/startracker/startracker/1420mhz_ra_dec.fits
Normal file
BIN
plugins/feature/startracker/startracker/1420mhz_ra_dec.png
Normal file
After Width: | Height: | Size: 682 KiB |
BIN
plugins/feature/startracker/startracker/150mhz_galactic.png
Normal file
After Width: | Height: | Size: 90 KiB |
1322
plugins/feature/startracker/startracker/150mhz_ra_dec.fits
Normal file
BIN
plugins/feature/startracker/startracker/150mhz_ra_dec.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
plugins/feature/startracker/startracker/408mhz_galactic.png
Normal file
After Width: | Height: | Size: 341 KiB |
6492
plugins/feature/startracker/startracker/408mhz_ra_dec.fits
Normal file
BIN
plugins/feature/startracker/startracker/408mhz_ra_dec.png
Normal file
After Width: | Height: | Size: 393 KiB |
BIN
plugins/feature/startracker/startracker/sun-button-24.png
Normal file
After Width: | Height: | Size: 367 B |
@ -17,6 +17,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <QMessageBox>
|
||||
#include <QLineEdit>
|
||||
#include <QRegExp>
|
||||
@ -42,6 +43,7 @@
|
||||
#include "startrackerreport.h"
|
||||
#include "startrackersettingsdialog.h"
|
||||
|
||||
|
||||
StarTrackerGUI* StarTrackerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
|
||||
{
|
||||
StarTrackerGUI* gui = new StarTrackerGUI(pluginAPI, featureUISet, feature);
|
||||
@ -119,6 +121,7 @@ bool StarTrackerGUI::handleMessage(const Message& message)
|
||||
m_settings.m_dec = Units::decimalDegreesToDegreeMinutesAndSeconds(raDec.getDec());
|
||||
ui->rightAscension->setText(m_settings.m_ra);
|
||||
ui->declination->setText(m_settings.m_dec);
|
||||
raDecChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -151,7 +154,19 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
|
||||
m_doApplySettings(true),
|
||||
m_lastFeatureState(0),
|
||||
m_networkManager(nullptr),
|
||||
m_solarFlux(0.0)
|
||||
m_progressDialog(nullptr),
|
||||
m_solarFlux(0.0),
|
||||
m_solarFluxesValid(false),
|
||||
m_images{QImage(":/startracker/startracker/150mhz_ra_dec.png"),
|
||||
QImage(":/startracker/startracker/150mhz_galactic.png"),
|
||||
QImage(":/startracker/startracker/408mhz_ra_dec.png"),
|
||||
QImage(":/startracker/startracker/408mhz_galactic.png"),
|
||||
QImage(":/startracker/startracker/1420mhz_ra_dec.png"),
|
||||
QImage(":/startracker/startracker/1420mhz_galactic.png")},
|
||||
m_temps{FITS(":/startracker/startracker/150mhz_ra_dec.fits"),
|
||||
FITS(":/startracker/startracker/408mhz_ra_dec.fits"),
|
||||
FITS(":/startracker/startracker/1420mhz_ra_dec.fits")},
|
||||
m_spectralIndex(":/startracker/startracker/408mhz_ra_dec_spectral_index.fits")
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
@ -165,15 +180,51 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
|
||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||
|
||||
connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &StarTrackerGUI::downloadFinished);
|
||||
|
||||
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
|
||||
m_statusTimer.start(1000);
|
||||
|
||||
// Intialise chart
|
||||
m_chart.legend()->hide();
|
||||
ui->elevationChart->setChart(&m_chart);
|
||||
ui->elevationChart->setRenderHint(QPainter::Antialiasing);
|
||||
ui->chart->setChart(&m_chart);
|
||||
ui->chart->setRenderHint(QPainter::Antialiasing);
|
||||
m_chart.addAxis(&m_chartXAxis, Qt::AlignBottom);
|
||||
m_chart.addAxis(&m_chartYAxis, Qt::AlignLeft);
|
||||
m_chart.layout()->setContentsMargins(0, 0, 0, 0);
|
||||
m_chart.setMargins(QMargins(1, 1, 1, 1));
|
||||
|
||||
// Create axes that are static
|
||||
|
||||
m_skyTempGalacticLXAxis.setTitleText(QString("Galactic longitude (%1)").arg(QChar(0xb0)));
|
||||
m_skyTempGalacticLXAxis.setMin(0);
|
||||
m_skyTempGalacticLXAxis.setMax(360);
|
||||
m_skyTempGalacticLXAxis.append("180", 0);
|
||||
m_skyTempGalacticLXAxis.append("90", 90);
|
||||
m_skyTempGalacticLXAxis.append("0/360", 180);
|
||||
m_skyTempGalacticLXAxis.append("270", 270);
|
||||
//m_skyTempGalacticLXAxis.append("180", 360); // Note - labels need to be unique, so can't have 180 at start and end
|
||||
m_skyTempGalacticLXAxis.setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
|
||||
m_skyTempGalacticLXAxis.setGridLineVisible(false);
|
||||
|
||||
m_skyTempRAXAxis.setTitleText(QString("Right ascension (hours)"));
|
||||
m_skyTempRAXAxis.setMin(0);
|
||||
m_skyTempRAXAxis.setMax(24);
|
||||
m_skyTempRAXAxis.append("12", 0);
|
||||
m_skyTempRAXAxis.append("9", 3);
|
||||
m_skyTempRAXAxis.append("6", 6);
|
||||
m_skyTempRAXAxis.append("3", 9);
|
||||
m_skyTempRAXAxis.append("0", 12);
|
||||
m_skyTempRAXAxis.append("21", 15);
|
||||
m_skyTempRAXAxis.append("18", 18);
|
||||
m_skyTempRAXAxis.append("15", 21);
|
||||
//m_skyTempRAXAxis.append("12", 24); // Note - labels need to be unique, so can't have 12 at start and end
|
||||
m_skyTempRAXAxis.setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
|
||||
m_skyTempRAXAxis.setGridLineVisible(false);
|
||||
|
||||
m_skyTempYAxis.setGridLineVisible(false);
|
||||
m_skyTempYAxis.setRange(-90.0, 90.0);
|
||||
m_skyTempYAxis.setGridLineVisible(false);
|
||||
|
||||
ui->dateTime->setDateTime(QDateTime::currentDateTime());
|
||||
displaySettings();
|
||||
@ -200,14 +251,15 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
|
||||
7.5e14, m_settings.m_latitude, m_settings.m_heightAboveSeaLevel,
|
||||
m_settings.m_temperatureLapseRate));
|
||||
printf("];\n");
|
||||
*/
|
||||
*/
|
||||
|
||||
m_networkManager = new QNetworkAccessManager();
|
||||
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
|
||||
connect(&m_solarFluxTimer, SIGNAL(timeout()), this, SLOT(updateSolarFlux()));
|
||||
readSolarFlux();
|
||||
connect(&m_solarFluxTimer, SIGNAL(timeout()), this, SLOT(autoUpdateSolarFlux()));
|
||||
m_solarFluxTimer.start(1000*60*60*24); // Update every 24hours
|
||||
updateSolarFlux();
|
||||
autoUpdateSolarFlux();
|
||||
}
|
||||
|
||||
StarTrackerGUI::~StarTrackerGUI()
|
||||
@ -246,6 +298,10 @@ void StarTrackerGUI::displaySettings()
|
||||
ui->dateTime->setVisible(true);
|
||||
ui->dateTimeSelect->setCurrentIndex(1);
|
||||
}
|
||||
if ((m_settings.m_solarFluxData != StarTrackerSettings::DRAO_2800) && !m_solarFluxesValid)
|
||||
autoUpdateSolarFlux();
|
||||
ui->frequency->setValue(m_settings.m_frequency/1000000.0);
|
||||
ui->beamwidth->setValue(m_settings.m_beamwidth);
|
||||
updateForTarget();
|
||||
plotChart();
|
||||
blockApplySettings(false);
|
||||
@ -489,6 +545,8 @@ void StarTrackerGUI::on_displaySettings_clicked()
|
||||
{
|
||||
applySettings();
|
||||
displaySolarFlux();
|
||||
if (ui->chartSelect->currentIndex() == 1)
|
||||
plotChart();
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,10 +577,349 @@ void StarTrackerGUI::on_dateTime_dateTimeChanged(const QDateTime &datetime)
|
||||
}
|
||||
}
|
||||
|
||||
// Plot target elevation angle over the day
|
||||
void StarTrackerGUI::plotChart()
|
||||
{
|
||||
if (ui->chartSelect->currentIndex() == 0)
|
||||
plotElevationChart();
|
||||
else if (ui->chartSelect->currentIndex() == 1)
|
||||
plotSolarFluxChart();
|
||||
else if (ui->chartSelect->currentIndex() == 2)
|
||||
plotSkyTemperatureChart();
|
||||
}
|
||||
|
||||
void StarTrackerGUI::raDecChanged()
|
||||
{
|
||||
if (ui->chartSelect->currentIndex() == 2)
|
||||
plotSkyTemperatureChart();
|
||||
}
|
||||
|
||||
void StarTrackerGUI::on_frequency_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_frequency = value*1000000.0;
|
||||
applySettings();
|
||||
if (ui->chartSelect->currentIndex() != 0)
|
||||
{
|
||||
updateChartSubSelect();
|
||||
plotChart();
|
||||
}
|
||||
displaySolarFlux();
|
||||
}
|
||||
|
||||
void StarTrackerGUI::on_beamwidth_valueChanged(double value)
|
||||
{
|
||||
m_settings.m_beamwidth = value;
|
||||
applySettings();
|
||||
updateChartSubSelect();
|
||||
if (ui->chartSelect->currentIndex() == 2)
|
||||
plotChart();
|
||||
}
|
||||
|
||||
void StarTrackerGUI::plotSolarFluxChart()
|
||||
{
|
||||
m_chart.removeAllSeries();
|
||||
removeAllAxes();
|
||||
if (m_solarFluxesValid)
|
||||
{
|
||||
double maxValue = -std::numeric_limits<double>::infinity();
|
||||
double minValue = std::numeric_limits<double>::infinity();
|
||||
QLineSeries *series = new QLineSeries();
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
double value = convertSolarFluxUnits(m_solarFluxes[i]);
|
||||
series->append(m_solarFluxFrequencies[i], value);
|
||||
maxValue = std::max(value, maxValue);
|
||||
minValue = std::min(value, minValue);
|
||||
}
|
||||
series->setPointLabelsVisible(true);
|
||||
series->setPointLabelsFormat("@yPoint");
|
||||
series->setPointLabelsClipping(false);
|
||||
m_chart.setTitle("");
|
||||
m_chart.addAxis(&m_chartSolarFluxXAxis, Qt::AlignBottom);
|
||||
m_chart.addAxis(&m_chartYAxis, Qt::AlignLeft);
|
||||
m_chart.addSeries(series);
|
||||
series->attachAxis(&m_chartSolarFluxXAxis);
|
||||
series->attachAxis(&m_chartYAxis);
|
||||
m_chartSolarFluxXAxis.setTitleText(QString("Frequency (MHz)"));
|
||||
m_chartSolarFluxXAxis.setMinorTickCount(-1);
|
||||
if (m_settings.m_solarFluxUnits == StarTrackerSettings::SFU)
|
||||
{
|
||||
m_chartYAxis.setLabelFormat("%d");
|
||||
m_chartYAxis.setRange(0.0, ((((int)maxValue)+99)/100)*100);
|
||||
}
|
||||
else if (m_settings.m_solarFluxUnits == StarTrackerSettings::JANSKY)
|
||||
{
|
||||
m_chartYAxis.setLabelFormat("%.2g");
|
||||
m_chartYAxis.setRange(0, ((((int)maxValue)+999999)/100000)*100000);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_chartYAxis.setLabelFormat("%.2g");
|
||||
m_chartYAxis.setRange(minValue, maxValue);
|
||||
}
|
||||
m_chartYAxis.setTitleText(QString("Solar flux density (%1)").arg(solarFluxUnit()));
|
||||
}
|
||||
else
|
||||
m_chart.setTitle("Press download Solar flux density data to view");
|
||||
m_chart.setPlotAreaBackgroundVisible(false);
|
||||
disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
|
||||
}
|
||||
|
||||
void StarTrackerGUI::plotSkyTemperatureChart()
|
||||
{
|
||||
bool galactic = (ui->chartSubSelect->currentIndex() & 1) == 1;
|
||||
|
||||
m_chart.removeAllSeries();
|
||||
removeAllAxes();
|
||||
|
||||
QScatterSeries *series = new QScatterSeries();
|
||||
float ra = Astronomy::raToDecimal(m_settings.m_ra);
|
||||
float dec = Astronomy::decToDecimal(m_settings.m_dec);
|
||||
|
||||
double beamWidth = m_settings.m_beamwidth;
|
||||
// Ellipse not supported, so draw circle on shorter axis
|
||||
double degPerPixelW = 360.0/m_chart.plotArea().width();
|
||||
double degPerPixelH = 180.0/m_chart.plotArea().height();
|
||||
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);
|
||||
}
|
||||
|
||||
// Get temperature
|
||||
int idx = ui->chartSubSelect->currentIndex();
|
||||
if ((idx == 6) || (idx == 7))
|
||||
{
|
||||
// Adjust temperature from 408MHz FITS file, taking in to account
|
||||
// observation frequency and beamwidth
|
||||
FITS *fits = &m_temps[1];
|
||||
if (fits->valid())
|
||||
{
|
||||
const double beamwidth = m_settings.m_beamwidth;
|
||||
const double halfBeamwidth = beamwidth/2.0;
|
||||
// Use cos^p(x) for approximation of radiation pattern
|
||||
// (Essentially the same as Gaussian of exp(-4*ln(theta^2/beamwidth^2))
|
||||
// (See a2 in https://arxiv.org/pdf/1812.10084.pdf for Elliptical equivalent))
|
||||
// We have gain of 0dB (1) at 0 degrees, and -3dB (~0.5) at half-beamwidth degrees
|
||||
// Find exponent that correponds to -3dB at that angle
|
||||
double minus3dBLinear = pow(10.0, -3.0/10.0);
|
||||
double p = log(minus3dBLinear)/log(cos(Units::degreesToRadians(halfBeamwidth)));
|
||||
// Create an matrix with gain as a function of angle
|
||||
double degreesPerPixelH = abs(fits->degreesPerPixelH());
|
||||
double degreesPerPixelV = abs(fits->degreesPerPixelV());
|
||||
int numberOfCoeffsH = ceil(beamwidth/degreesPerPixelH);
|
||||
int numberOfCoeffsV = ceil(beamwidth/degreesPerPixelV);
|
||||
if ((numberOfCoeffsH & 1) == 0)
|
||||
numberOfCoeffsH++;
|
||||
if ((numberOfCoeffsV & 1) == 0)
|
||||
numberOfCoeffsV++;
|
||||
double *beam = new double[numberOfCoeffsH*numberOfCoeffsV];
|
||||
double sum = 0.0;
|
||||
int y0 = numberOfCoeffsV/2;
|
||||
int x0 = numberOfCoeffsH/2;
|
||||
int nonZeroCount = 0;
|
||||
for (int y = 0; y < numberOfCoeffsV; y++)
|
||||
{
|
||||
for (int x = 0; x < numberOfCoeffsH; x++)
|
||||
{
|
||||
double xp = (x - x0) * degreesPerPixelH;
|
||||
double yp = (y - y0) * degreesPerPixelV;
|
||||
double r = sqrt(xp*xp+yp*yp);
|
||||
if (r < halfBeamwidth)
|
||||
{
|
||||
beam[y*numberOfCoeffsH+x] = pow(cos(Units::degreesToRadians(r)), p);
|
||||
sum += beam[y*numberOfCoeffsH+x];
|
||||
nonZeroCount++;
|
||||
}
|
||||
else
|
||||
beam[y*numberOfCoeffsH+x] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Get centre pixel coordinates
|
||||
double centreX;
|
||||
if (ra <= 12.0)
|
||||
centreX = (12.0 - ra) / 24.0;
|
||||
else
|
||||
centreX = (24 - ra + 12) / 24.0;
|
||||
double centreY = (90.0-dec) / 180.0;
|
||||
int imgX = centreX * fits->width();
|
||||
int imgY = centreY * fits->height();
|
||||
|
||||
// Apply weighting to temperature data
|
||||
double weightedSum = 0.0;
|
||||
for (int y = 0; y < numberOfCoeffsV; y++)
|
||||
{
|
||||
for (int x = 0; x < numberOfCoeffsH; x++)
|
||||
{
|
||||
weightedSum += beam[y*numberOfCoeffsH+x] * fits->scaledWrappedValue(imgX + (x-x0), imgY + (y-y0));
|
||||
}
|
||||
}
|
||||
// From: https://www.cv.nrao.edu/~sransom/web/Ch3.html
|
||||
// The antenna temperature equals the source brightness temperature multiplied by the fraction of the beam solid angle filled by the source
|
||||
// So we scale the sum by the total number of non-zero pixels (i.e. beam area)
|
||||
// If we compare to some maps with different beamwidths here: https://www.cv.nrao.edu/~demerson/radiosky/sky_jun96.pdf
|
||||
// The values we've computed are a bit higher..
|
||||
double temp408 = weightedSum/nonZeroCount;
|
||||
|
||||
// Scale according to frequency - CMB contribution constant
|
||||
// Power law at low frequencies, with slight variation in spectral index
|
||||
// See:
|
||||
// Global Sky Model: https://ascl.net/1011.010
|
||||
// An improved Model of Diffuse Galactic Radio Emission: https://arxiv.org/pdf/1605.04920.pdf
|
||||
// A high-resolution self-consistent whole sky foreground model: https://arxiv.org/abs/1812.10084
|
||||
// (De-striping:) Full sky study of diffuse Galactic emission at decimeter wavelength https://www.aanda.org/articles/aa/pdf/2003/42/aah4363.pdf
|
||||
// Data here: http://cdsarc.u-strasbg.fr/viz-bin/cat/J/A+A/410/847
|
||||
// LFmap: https://www.faculty.ece.vt.edu/swe/lwa/memo/lwa0111.pdf
|
||||
double iso408 = 50 * pow(150e6/408e6, 2.75); // Extra-galactic isotropic in reference map at 408MHz
|
||||
double isoT = 50 * pow(150e6/m_settings.m_frequency, 2.75); // Extra-galactic isotropic at target frequency
|
||||
double cmbT = 2.725; // Cosmic microwave backgroud;
|
||||
double spectralIndex;
|
||||
if (m_spectralIndex.valid())
|
||||
{
|
||||
// See https://www.aanda.org/articles/aa/pdf/2003/42/aah4363.pdf
|
||||
spectralIndex = m_spectralIndex.scaledValue(imgX, imgY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// See https://arxiv.org/abs/1812.10084 fig 2
|
||||
if (m_settings.m_frequency < 200e6)
|
||||
spectralIndex = 2.55;
|
||||
else if (m_settings.m_frequency < 20e9)
|
||||
spectralIndex = 2.695;
|
||||
else
|
||||
spectralIndex = 3.1;
|
||||
}
|
||||
double galactic480 = temp408 - cmbT - iso408;
|
||||
double galacticT = galactic480 * pow(408e6/m_settings.m_frequency, spectralIndex); // Scale galactic contribution by frequency
|
||||
double temp = galacticT + cmbT + isoT; // Final temperature
|
||||
|
||||
series->setPointLabelsVisible(true);
|
||||
series->setPointLabelsColor(Qt::red);
|
||||
series->setPointLabelsFormat(QString("%1 K").arg(std::round(temp)));
|
||||
|
||||
// Scale marker size by beamwidth
|
||||
markerSize = std::max((int)round(beamWidth * degPerPixel), 5);
|
||||
}
|
||||
else
|
||||
qDebug() << "StarTrackerGUI::plotSkyTemperatureChart: FITS temperature file not valid";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read temperature from selected FITS file at target RA/Dec
|
||||
QImage *img = &m_images[idx];
|
||||
FITS *fits = &m_temps[idx/2];
|
||||
double x;
|
||||
if (ra <= 12.0)
|
||||
x = (12.0 - ra) / 24.0;
|
||||
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();
|
||||
|
||||
if (fits->valid())
|
||||
{
|
||||
double temp = fits->scaledValue(imgX, imgY);
|
||||
series->setPointLabelsVisible(true);
|
||||
series->setPointLabelsColor(Qt::red);
|
||||
series->setPointLabelsFormat(QString("%1 K").arg(std::round(temp)));
|
||||
}
|
||||
|
||||
// Temperature from just one pixel, but need to make marker visbile
|
||||
markerSize = 5;
|
||||
}
|
||||
series->setMarkerSize(markerSize);
|
||||
|
||||
m_chart.setTitle("");
|
||||
m_chart.addSeries(series);
|
||||
if (galactic)
|
||||
{
|
||||
m_chart.addAxis(&m_skyTempGalacticLXAxis, Qt::AlignBottom);
|
||||
series->attachAxis(&m_skyTempGalacticLXAxis);
|
||||
|
||||
m_skyTempYAxis.setTitleText(QString("Galactic latitude (%1)").arg(QChar(0xb0)));
|
||||
m_chart.addAxis(&m_skyTempYAxis, Qt::AlignLeft);
|
||||
series->attachAxis(&m_skyTempYAxis);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_chart.addAxis(&m_skyTempRAXAxis, Qt::AlignBottom);
|
||||
series->attachAxis(&m_skyTempRAXAxis);
|
||||
|
||||
m_skyTempYAxis.setTitleText(QString("Declination (%1)").arg(QChar(0xb0)));
|
||||
m_chart.addAxis(&m_skyTempYAxis, Qt::AlignLeft);
|
||||
series->attachAxis(&m_skyTempYAxis);
|
||||
}
|
||||
|
||||
plotAreaChanged(m_chart.plotArea());
|
||||
connect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
|
||||
}
|
||||
|
||||
void StarTrackerGUI::plotAreaChanged(const QRectF &plotArea)
|
||||
{
|
||||
int width = static_cast<int>(plotArea.width());
|
||||
int height = static_cast<int>(plotArea.height());
|
||||
int viewW = static_cast<int>(ui->chart->width());
|
||||
int viewH = static_cast<int>(ui->chart->height());
|
||||
|
||||
// Scale the image to fit plot area
|
||||
int imageIdx = ui->chartSubSelect->currentIndex();
|
||||
if (imageIdx == 6)
|
||||
imageIdx = 2;
|
||||
else if (imageIdx == 7)
|
||||
imageIdx = 3;
|
||||
QImage image = m_images[imageIdx].scaled(QSize(width, height), Qt::IgnoreAspectRatio);
|
||||
QImage translated(viewW, viewH, QImage::Format_ARGB32);
|
||||
translated.fill(Qt::white);
|
||||
QPainter painter(&translated);
|
||||
painter.drawImage(plotArea.topLeft(), image);
|
||||
|
||||
m_chart.setPlotAreaBackgroundBrush(translated);
|
||||
m_chart.setPlotAreaBackgroundVisible(true);
|
||||
}
|
||||
|
||||
void StarTrackerGUI::removeAllAxes()
|
||||
{
|
||||
QList<QAbstractAxis *> axes;
|
||||
axes = m_chart.axes(Qt::Horizontal);
|
||||
for (QAbstractAxis *axis : axes)
|
||||
m_chart.removeAxis(axis);
|
||||
axes = m_chart.axes(Qt::Vertical);
|
||||
for (QAbstractAxis *axis : axes)
|
||||
m_chart.removeAxis(axis);
|
||||
}
|
||||
|
||||
// Plot target elevation angle over the day
|
||||
void StarTrackerGUI::plotElevationChart()
|
||||
{
|
||||
m_chart.removeAllSeries();
|
||||
removeAllAxes();
|
||||
|
||||
double maxElevation = -90.0;
|
||||
|
||||
QLineSeries *series = new QLineSeries();
|
||||
@ -579,6 +976,8 @@ void StarTrackerGUI::plotChart()
|
||||
m_chart.setTitle("Not visible from this latitude");
|
||||
else
|
||||
m_chart.setTitle("");
|
||||
m_chart.addAxis(&m_chartXAxis, Qt::AlignBottom);
|
||||
m_chart.addAxis(&m_chartYAxis, Qt::AlignLeft);
|
||||
m_chart.addSeries(series);
|
||||
series->attachAxis(&m_chartXAxis);
|
||||
series->attachAxis(&m_chartYAxis);
|
||||
@ -588,6 +987,8 @@ void StarTrackerGUI::plotChart()
|
||||
m_chartXAxis.setRange(startTime, endTime);
|
||||
m_chartYAxis.setRange(0.0, 90.0);
|
||||
m_chartYAxis.setTitleText(QString("Elevation (%1)").arg(QChar(0xb0)));
|
||||
m_chart.setPlotAreaBackgroundVisible(false);
|
||||
disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
|
||||
}
|
||||
|
||||
// Find target on the Map
|
||||
@ -597,35 +998,174 @@ void StarTrackerGUI::on_viewOnMap_clicked()
|
||||
FeatureWebAPIUtils::mapFind(target);
|
||||
}
|
||||
|
||||
void StarTrackerGUI::updateSolarFlux()
|
||||
void StarTrackerGUI::updateChartSubSelect()
|
||||
{
|
||||
qDebug() << "StarTrackerGUI: Updating flux";
|
||||
m_networkRequest.setUrl(QUrl("https://www.spaceweather.gc.ca/solarflux/sx-4-en.php"));
|
||||
m_networkManager->get(m_networkRequest);
|
||||
if (ui->chartSelect->currentIndex() == 2)
|
||||
{
|
||||
ui->chartSubSelect->setItemText(6, QString("%1 MHz %2%3 Equatorial")
|
||||
.arg((int)std::round(m_settings.m_frequency/1e6))
|
||||
.arg((int)std::round(m_settings.m_beamwidth))
|
||||
.arg(QChar(0xb0)));
|
||||
ui->chartSubSelect->setItemText(7, QString("%1 MHz %2%3 Galactic")
|
||||
.arg((int)std::round(m_settings.m_frequency/1e6))
|
||||
.arg((int)std::round(m_settings.m_beamwidth))
|
||||
.arg(QChar(0xb0)));
|
||||
}
|
||||
}
|
||||
|
||||
void StarTrackerGUI::on_chartSelect_currentIndexChanged(int index)
|
||||
{
|
||||
bool oldState = ui->chartSubSelect->blockSignals(true);
|
||||
ui->chartSubSelect->clear();
|
||||
if (index == 2)
|
||||
{
|
||||
ui->chartSubSelect->addItem(QString("150 MHz 5%1 Equatorial").arg(QChar(0xb0)));
|
||||
ui->chartSubSelect->addItem(QString("150 MHz 5%1 Galactic").arg(QChar(0xb0)));
|
||||
ui->chartSubSelect->addItem("408 MHz 51' Equatorial");
|
||||
ui->chartSubSelect->addItem("408 MHz 51' Galactic");
|
||||
ui->chartSubSelect->addItem("1420 MHz 35' Equatorial");
|
||||
ui->chartSubSelect->addItem("1420 MHz 35' Galactic");
|
||||
ui->chartSubSelect->addItem("Custom Equatorial");
|
||||
ui->chartSubSelect->addItem("Custom Galactic");
|
||||
ui->chartSubSelect->setCurrentIndex(2);
|
||||
updateChartSubSelect();
|
||||
}
|
||||
ui->chartSubSelect->blockSignals(oldState);
|
||||
plotChart();
|
||||
}
|
||||
|
||||
void StarTrackerGUI::on_chartSubSelect_currentIndexChanged(int index)
|
||||
{
|
||||
(void) index;
|
||||
plotChart();
|
||||
}
|
||||
|
||||
double StarTrackerGUI::convertSolarFluxUnits(double sfu)
|
||||
{
|
||||
switch (m_settings.m_solarFluxUnits)
|
||||
{
|
||||
case StarTrackerSettings::SFU:
|
||||
return sfu;
|
||||
case StarTrackerSettings::JANSKY:
|
||||
return Units::solarFluxUnitsToJansky(sfu);
|
||||
case StarTrackerSettings::WATTS_M_HZ:
|
||||
return Units::solarFluxUnitsToWattsPerMetrePerHertz(sfu);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
QString StarTrackerGUI::solarFluxUnit()
|
||||
{
|
||||
switch (m_settings.m_solarFluxUnits)
|
||||
{
|
||||
case StarTrackerSettings::SFU:
|
||||
return "sfu";
|
||||
case StarTrackerSettings::JANSKY:
|
||||
return "Jy";
|
||||
case StarTrackerSettings::WATTS_M_HZ:
|
||||
return "Wm^-2Hz^-1";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Linear extrapolation
|
||||
static double extrapolate(double x0, double y0, double x1, double y1, double x)
|
||||
{
|
||||
return y0 + ((x-x0)/(x1-x0)) * (y1-y0);
|
||||
}
|
||||
|
||||
// Linear interpolation
|
||||
static double interpolate(double x0, double y0, double x1, double y1, double x)
|
||||
{
|
||||
return (y0*(x1-x) + y1*(x-x0)) / (x1-x0);
|
||||
}
|
||||
|
||||
void StarTrackerGUI::displaySolarFlux()
|
||||
{
|
||||
if (m_solarFlux <= 0.0)
|
||||
if (((m_settings.m_solarFluxData == StarTrackerSettings::DRAO_2800) && (m_solarFlux == 0.0))
|
||||
|| ((m_settings.m_solarFluxData != StarTrackerSettings::DRAO_2800) && !m_solarFluxesValid))
|
||||
ui->solarFlux->setText("");
|
||||
else
|
||||
{
|
||||
switch (m_settings.m_solarFluxUnits)
|
||||
double solarFlux;
|
||||
if (m_settings.m_solarFluxData == StarTrackerSettings::DRAO_2800)
|
||||
{
|
||||
case StarTrackerSettings::SFU:
|
||||
ui->solarFlux->setText(QString("%1 sfu").arg(m_solarFlux));
|
||||
break;
|
||||
case StarTrackerSettings::JANSKY:
|
||||
ui->solarFlux->setText(QString("%1 Jy").arg(Units::solarFluxUnitsToJansky(m_solarFlux)));
|
||||
break;
|
||||
case StarTrackerSettings::WATTS_M_HZ:
|
||||
ui->solarFlux->setText(QString("%1 Wm^-2Hz^-1").arg(Units::solarFluxUnitsToWattsPerMetrePerHertz(m_solarFlux)));
|
||||
break;
|
||||
solarFlux = m_solarFlux;
|
||||
ui->solarFlux->setToolTip(QString("Solar flux density at 2800 MHz"));
|
||||
}
|
||||
else if (m_settings.m_solarFluxData == StarTrackerSettings::TARGET_FREQ)
|
||||
{
|
||||
double freqMhz = m_settings.m_frequency/1000000.0;
|
||||
const int fluxes = sizeof(m_solarFluxFrequencies)/sizeof(*m_solarFluxFrequencies);
|
||||
int i;
|
||||
for (i = 0; i < fluxes; i++)
|
||||
{
|
||||
if (freqMhz < m_solarFluxFrequencies[i])
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
solarFlux = extrapolate(m_solarFluxFrequencies[0], m_solarFluxes[0],
|
||||
m_solarFluxFrequencies[1], m_solarFluxes[1],
|
||||
freqMhz
|
||||
);
|
||||
}
|
||||
else if (i == fluxes)
|
||||
{
|
||||
solarFlux = extrapolate(m_solarFluxFrequencies[fluxes-2], m_solarFluxes[fluxes-2],
|
||||
m_solarFluxFrequencies[fluxes-1], m_solarFluxes[fluxes-1],
|
||||
freqMhz
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
solarFlux = interpolate(m_solarFluxFrequencies[i-1], m_solarFluxes[i-1],
|
||||
m_solarFluxFrequencies[i], m_solarFluxes[i],
|
||||
freqMhz
|
||||
);
|
||||
}
|
||||
ui->solarFlux->setToolTip(QString("Solar flux density interpolated to %1 MHz").arg(freqMhz));
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = m_settings.m_solarFluxData-StarTrackerSettings::L_245;
|
||||
solarFlux = m_solarFluxes[idx];
|
||||
ui->solarFlux->setToolTip(QString("Solar flux density at %1 MHz").arg(m_solarFluxFrequencies[idx]));
|
||||
}
|
||||
ui->solarFlux->setText(QString("%1 %2").arg(convertSolarFluxUnits(solarFlux)).arg(solarFluxUnit()));
|
||||
ui->solarFlux->setCursorPosition(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool StarTrackerGUI::readSolarFlux()
|
||||
{
|
||||
QFile file(getSolarFluxFilename());
|
||||
QDateTime lastModified = file.fileTime(QFileDevice::FileModificationTime);
|
||||
if (QDateTime::currentDateTime().secsTo(lastModified) >= -(60*60*24))
|
||||
{
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QByteArray bytes = file.readLine();
|
||||
QString string(bytes);
|
||||
// HHMMSS 245 410 610 1415 2695 4995 8800 15400 Mhz
|
||||
// 000000 000019 000027 000037 000056 000073 000116 000202 000514 sfu
|
||||
QRegExp re("([0-9]{2})([0-9]{2})([0-9]{2}) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)");
|
||||
if (re.indexIn(string) != -1)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
m_solarFluxes[i] = re.capturedTexts()[i+4].toInt();
|
||||
m_solarFluxesValid = true;
|
||||
displaySolarFlux();
|
||||
plotChart();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
qDebug() << "StarTrackerGUI::readSolarFlux: Solar flux data is more than 1 day old";
|
||||
return false;
|
||||
}
|
||||
|
||||
void StarTrackerGUI::networkManagerFinished(QNetworkReply *reply)
|
||||
{
|
||||
ui->solarFlux->setText(""); // Don't show obsolete data
|
||||
@ -648,8 +1188,51 @@ void StarTrackerGUI::networkManagerFinished(QNetworkReply *reply)
|
||||
displaySolarFlux();
|
||||
}
|
||||
else
|
||||
qDebug() << "No Solar flux found: " << answer;
|
||||
qDebug() << "StarTrackerGUI::networkManagerFinished - No Solar flux found: " << answer;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
QString StarTrackerGUI::getSolarFluxFilename()
|
||||
{
|
||||
return HttpDownloadManager::downloadDir() + "/solar_flux.srd";
|
||||
}
|
||||
|
||||
void StarTrackerGUI::updateSolarFlux(bool all)
|
||||
{
|
||||
qDebug() << "StarTrackerGUI: Updating Solar flux data";
|
||||
if ((m_settings.m_solarFluxData != StarTrackerSettings::DRAO_2800) || all)
|
||||
{
|
||||
QDate today = QDateTime::currentDateTimeUtc().date();
|
||||
QString solarFluxFile = getSolarFluxFilename();
|
||||
if (m_dlm.confirmDownload(solarFluxFile))
|
||||
{
|
||||
QString urlString = QString("http://www.sws.bom.gov.au/Category/World Data Centre/Data Display and Download/Solar Radio/station/learmonth/SRD/%1/L%2.SRD")
|
||||
.arg(today.year()).arg(today.toString("yyMMdd"));
|
||||
m_dlm.download(QUrl(urlString), solarFluxFile, this);
|
||||
}
|
||||
}
|
||||
if ((m_settings.m_solarFluxData == StarTrackerSettings::DRAO_2800) || all)
|
||||
{
|
||||
m_networkRequest.setUrl(QUrl("https://www.spaceweather.gc.ca/solarflux/sx-4-en.php"));
|
||||
m_networkManager->get(m_networkRequest);
|
||||
}
|
||||
}
|
||||
|
||||
void StarTrackerGUI::autoUpdateSolarFlux()
|
||||
{
|
||||
updateSolarFlux(false);
|
||||
}
|
||||
|
||||
void StarTrackerGUI::on_downloadSolarFlux_clicked()
|
||||
{
|
||||
updateSolarFlux(true);
|
||||
}
|
||||
|
||||
void StarTrackerGUI::downloadFinished(const QString& filename, bool success)
|
||||
{
|
||||
(void) filename;
|
||||
if (success)
|
||||
readSolarFlux();
|
||||
}
|
||||
|
@ -22,9 +22,13 @@
|
||||
#include <QTimer>
|
||||
#include <QtCharts>
|
||||
#include <QNetworkRequest>
|
||||
#include <QImage>
|
||||
#include <QProgressDialog>
|
||||
|
||||
#include "feature/featuregui.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "util/fits.h"
|
||||
#include "gui/httpdownloadmanagergui.h"
|
||||
#include "startrackersettings.h"
|
||||
|
||||
class PluginAPI;
|
||||
@ -67,9 +71,25 @@ private:
|
||||
QDateTimeAxis m_chartXAxis;
|
||||
QValueAxis m_chartYAxis;
|
||||
|
||||
QCategoryAxis m_skyTempGalacticLXAxis;
|
||||
QCategoryAxis m_skyTempRAXAxis;
|
||||
QValueAxis m_skyTempYAxis;
|
||||
|
||||
QLogValueAxis m_chartSolarFluxXAxis;
|
||||
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
double m_solarFlux;
|
||||
HttpDownloadManagerGUI m_dlm;
|
||||
QProgressDialog *m_progressDialog;
|
||||
|
||||
double m_solarFlux; // 10.7cm/2800MHz
|
||||
bool m_solarFluxesValid;
|
||||
int m_solarFluxes[8]; // Frequency (MHz), flux density (sfu)
|
||||
const int m_solarFluxFrequencies[8] = {245, 410, 610, 1415, 2695, 4995, 8800, 15400};
|
||||
|
||||
QList<QImage> m_images;
|
||||
QList<FITS> m_temps;
|
||||
FITS m_spectralIndex;
|
||||
|
||||
explicit StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
|
||||
virtual ~StarTrackerGUI();
|
||||
@ -81,8 +101,19 @@ private:
|
||||
QString convertDegreesToText(double degrees);
|
||||
bool handleMessage(const Message& message);
|
||||
void updateLST();
|
||||
void plotElevationChart();
|
||||
void plotSkyTemperatureChart();
|
||||
void plotSolarFluxChart();
|
||||
void plotChart();
|
||||
void removeAllAxes();
|
||||
double convertSolarFluxUnits(double sfu);
|
||||
QString solarFluxUnit();
|
||||
void displaySolarFlux();
|
||||
QString getSolarFluxFilename();
|
||||
bool readSolarFlux();
|
||||
void raDecChanged();
|
||||
void updateChartSubSelect();
|
||||
void updateSolarFlux(bool all);
|
||||
|
||||
void leaveEvent(QEvent*);
|
||||
void enterEvent(QEvent*);
|
||||
@ -97,14 +128,21 @@ private slots:
|
||||
void on_longitude_valueChanged(double value);
|
||||
void on_rightAscension_editingFinished();
|
||||
void on_declination_editingFinished();
|
||||
void on_frequency_valueChanged(int value);
|
||||
void on_beamwidth_valueChanged(double value);
|
||||
void on_target_currentTextChanged(const QString &text);
|
||||
void on_displaySettings_clicked();
|
||||
void on_dateTimeSelect_currentTextChanged(const QString &text);
|
||||
void on_dateTime_dateTimeChanged(const QDateTime &datetime);
|
||||
void updateStatus();
|
||||
void on_viewOnMap_clicked();
|
||||
void updateSolarFlux();
|
||||
void on_chartSelect_currentIndexChanged(int index);
|
||||
void on_chartSubSelect_currentIndexChanged(int index);
|
||||
void plotAreaChanged(const QRectF &plotArea);
|
||||
void autoUpdateSolarFlux();
|
||||
void on_downloadSolarFlux_clicked();
|
||||
void networkManagerFinished(QNetworkReply *reply);
|
||||
void downloadFinished(const QString& filename, bool success);
|
||||
};
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>337</width>
|
||||
<width>339</width>
|
||||
<height>568</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -42,7 +42,7 @@
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>301</width>
|
||||
<width>321</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -67,73 +67,44 @@
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="latitude">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="lst">
|
||||
<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="6" 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="7" 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>
|
||||
<string>Local sidereal time for selected date, time and longitude</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="timeLabel">
|
||||
<item row="7" column="2">
|
||||
<widget class="QLabel" name="declinationLabel">
|
||||
<property name="text">
|
||||
<string>Time</string>
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="3">
|
||||
<widget class="QLineEdit" name="declination">
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="dateTimeSelect">
|
||||
<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" 34 12 10.2)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-90d59'59.59"</string>
|
||||
<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="5" column="0">
|
||||
<widget class="QLabel" name="targetLabel">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="frequencyLabel">
|
||||
<property name="text">
|
||||
<string>Target</string>
|
||||
<string>Frequency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -150,114 +121,109 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="latitudeLabel">
|
||||
<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" 34 12 10.2)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Latitude</string>
|
||||
<string>-90d59'59.59"</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="dateTimeSelect">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Now</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Custom</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QLabel" name="elevationLabel">
|
||||
<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>Elevation</string>
|
||||
<string>23h59m59.59s</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="rightAscensionLabel">
|
||||
<property name="text">
|
||||
<string>RA</string>
|
||||
<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="0" column="0" colspan="4">
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="startStop">
|
||||
<property name="toolTip">
|
||||
<string>start/stop acquisition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/play.png</normaloff>
|
||||
<normalon>:/stop.png</normalon>:/play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewOnMap">
|
||||
<property name="toolTip">
|
||||
<string>Find target on the map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/gridpolar.png</normaloff>:/gridpolar.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="useMyPosition">
|
||||
<property name="toolTip">
|
||||
<string>Set latitude, longitude and height from My Position in SDRangel preferences</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/import.png</normaloff>:/import.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="displaySettings">
|
||||
<property name="toolTip">
|
||||
<string>Show settings dialog</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/listing.png</normaloff>:/listing.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="frequency">
|
||||
<property name="toolTip">
|
||||
<string>Observation frequency (MHz)</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</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">
|
||||
<string>Azimuth</string>
|
||||
</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="5" column="1" colspan="3">
|
||||
<layout class="QHBoxLayout" name="targetLayout">
|
||||
@ -269,6 +235,9 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Target object</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -339,47 +308,142 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QDoubleSpinBox" name="longitude">
|
||||
<item row="0" column="0" colspan="4">
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="startStop">
|
||||
<property name="toolTip">
|
||||
<string>start/stop acquisition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/play.png</normaloff>
|
||||
<normalon>:/stop.png</normalon>:/play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewOnMap">
|
||||
<property name="toolTip">
|
||||
<string>Find target on the map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/gridpolar.png</normaloff>:/gridpolar.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="downloadSolarFlux">
|
||||
<property name="toolTip">
|
||||
<string>Download Solar flux density data</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="startracker.qrc">
|
||||
<normaloff>:/startracker/startracker/sun-button-24.png</normaloff>:/startracker/startracker/sun-button-24.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="useMyPosition">
|
||||
<property name="toolTip">
|
||||
<string>Set latitude, longitude and height from My Position in SDRangel preferences</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/import.png</normaloff>:/import.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="displaySettings">
|
||||
<property name="toolTip">
|
||||
<string>Show settings dialog</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/listing.png</normaloff>:/listing.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="latitude">
|
||||
<property name="toolTip">
|
||||
<string>Longitude in decimal degress (East positive) of observation point / antenna location</string>
|
||||
<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>-180.000000000000000</double>
|
||||
<double>-90.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>-180.000000000000000</double>
|
||||
<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="declinationLabel">
|
||||
<widget class="QLabel" name="beamwidthLabel">
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="longitudeLabel">
|
||||
<property name="text">
|
||||
<string>Longitude</string>
|
||||
<string>Beamwidth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="azimuthtLabel">
|
||||
<widget class="QLabel" name="rightAscensionLabel">
|
||||
<property name="text">
|
||||
<string>Azimuth</string>
|
||||
<string>RA</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="3">
|
||||
<item row="8" column="3">
|
||||
<widget class="QLineEdit" name="elevation">
|
||||
<property name="toolTip">
|
||||
<string>Computed elevation in degrees to the target from the observation point</string>
|
||||
@ -392,40 +456,42 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lstLabel">
|
||||
<property name="text">
|
||||
<string>LST</string>
|
||||
</property>
|
||||
</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="2">
|
||||
<widget class="QLabel" name="solarFluxLabel">
|
||||
<property name="text">
|
||||
<string>Solar Flux</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLineEdit" name="solarFlux">
|
||||
<property name="toolTip">
|
||||
<string>Displays the solar flux at 10.7cm</string>
|
||||
<string>Solar flux density</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>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="3">
|
||||
<widget class="QDoubleSpinBox" name="beamwidth">
|
||||
<property name="toolTip">
|
||||
<string>Antenna half power (-3dB) beamwidth (degrees)</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>25.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@ -452,9 +518,9 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Elevation vs Time</string>
|
||||
<string>Plots</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
@ -471,7 +537,36 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QChartView" name="elevationChart">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="chartSelect">
|
||||
<property name="toolTip">
|
||||
<string>Select chart to view</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Elevation vs time</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Solar flux vs frequency</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Sky temperature</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="chartSubSelect"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QChartView" name="chart">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
@ -517,10 +612,11 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon
|
||||
<tabstop>declination</tabstop>
|
||||
<tabstop>azimuth</tabstop>
|
||||
<tabstop>elevation</tabstop>
|
||||
<tabstop>elevationChart</tabstop>
|
||||
<tabstop>chart</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
<include location="startracker.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -42,10 +42,12 @@ void StarTrackerSettings::resetToDefaults()
|
||||
m_humidity = 80.0;
|
||||
m_heightAboveSeaLevel = 0.0;
|
||||
m_temperatureLapseRate = 6.49;
|
||||
m_frequency = 435000000;
|
||||
m_frequency = 432000000;
|
||||
m_beamwidth = 25.0;
|
||||
m_enableServer = true;
|
||||
m_serverPort = 10001;
|
||||
m_azElUnits = DM;
|
||||
m_solarFluxData = DRAO_2800;
|
||||
m_solarFluxUnits = SFU;
|
||||
m_updatePeriod = 1.0;
|
||||
m_jnow = false;
|
||||
@ -94,6 +96,8 @@ QByteArray StarTrackerSettings::serialize() const
|
||||
s.writeU32(27, m_reverseAPIFeatureSetIndex);
|
||||
s.writeU32(28, m_reverseAPIFeatureIndex);
|
||||
s.writeU32(29, m_solarFluxUnits);
|
||||
s.writeDouble(30, m_beamwidth);
|
||||
s.writeU32(31, m_solarFluxData);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -159,6 +163,8 @@ bool StarTrackerSettings::deserialize(const QByteArray& data)
|
||||
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
|
||||
|
||||
d.readU32(29, (quint32 *)&m_solarFluxUnits, SFU);
|
||||
d.readDouble(30, &m_beamwidth, 25.0);
|
||||
d.readU32(31, (quint32 *)&m_solarFluxData, DRAO_2800);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -41,9 +41,11 @@ struct StarTrackerSettings
|
||||
double m_heightAboveSeaLevel; // In metres
|
||||
double m_temperatureLapseRate; // In K/km
|
||||
double m_frequency; // Observation frequency in Hz
|
||||
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 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;
|
||||
bool m_jnow; // Use JNOW epoch rather than J2000
|
||||
|
@ -36,7 +36,7 @@ StarTrackerSettingsDialog::StarTrackerSettingsDialog(StarTrackerSettings *settin
|
||||
ui->humidity->setValue(settings->m_humidity);
|
||||
ui->height->setValue(settings->m_heightAboveSeaLevel);
|
||||
ui->temperatureLapseRate->setValue(settings->m_temperatureLapseRate);
|
||||
ui->frequency->setValue(settings->m_frequency/1000000.0);
|
||||
ui->solarFluxData->setCurrentIndex((int)settings->m_solarFluxData);
|
||||
ui->solarFluxUnits->setCurrentIndex((int)settings->m_solarFluxUnits);
|
||||
ui->drawSunOnMap->setChecked(settings->m_drawSunOnMap);
|
||||
ui->drawMoonOnMap->setChecked(settings->m_drawMoonOnMap);
|
||||
@ -61,7 +61,7 @@ void StarTrackerSettingsDialog::accept()
|
||||
m_settings->m_humidity = ui->humidity->value();
|
||||
m_settings->m_heightAboveSeaLevel = ui->height->value();
|
||||
m_settings->m_temperatureLapseRate = ui->temperatureLapseRate->value();
|
||||
m_settings->m_frequency = ui->frequency->value() * 1000000.0;
|
||||
m_settings->m_solarFluxData = (StarTrackerSettings::SolarFluxData)ui->solarFluxData->currentIndex();
|
||||
m_settings->m_solarFluxUnits = (StarTrackerSettings::SolarFluxUnits)ui->solarFluxUnits->currentIndex();
|
||||
m_settings->m_drawSunOnMap = ui->drawSunOnMap->isChecked();
|
||||
m_settings->m_drawMoonOnMap = ui->drawMoonOnMap->isChecked();
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>393</width>
|
||||
<height>485</height>
|
||||
<width>496</width>
|
||||
<height>491</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -23,17 +23,29 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="updatePeriodLabel">
|
||||
<property name="text">
|
||||
<string>Update period (s)</string>
|
||||
<item row="10" column="1">
|
||||
<widget class="QDoubleSpinBox" name="updatePeriod">
|
||||
<property name="toolTip">
|
||||
<string>Enter the time in seconds between each calculation of the target's position</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="pressureLabel">
|
||||
<property name="text">
|
||||
<string>Air pressure (mb)</string>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="temperature">
|
||||
<property name="toolTip">
|
||||
<string>Air temperature in degrees Celsius, for use in atmospheric refraction correction</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -44,52 +56,69 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="refractionLabel">
|
||||
<item row="16" column="0">
|
||||
<widget class="QCheckBox" name="drawStarOnMap">
|
||||
<property name="text">
|
||||
<string>Refraction correction</string>
|
||||
<string>Draw target star on map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="frequencyLabel">
|
||||
<property name="text">
|
||||
<string>Frequency (MHz)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="refraction">
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="pressure">
|
||||
<property name="toolTip">
|
||||
<string>Atmospheric refraction correction</string>
|
||||
<string>Air pressure in millibars, for use in atmospheric refraction correction</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<property name="maximum">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1010.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="heightLabel">
|
||||
<property name="text">
|
||||
<string>Height above sea level (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QCheckBox" name="drawMoonOnMap">
|
||||
<property name="text">
|
||||
<string>Draw Moon on map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="solarFluxUnits">
|
||||
<property name="toolTip">
|
||||
<string>Units to use for the display of the Solar flux density</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
<string>Solar flux units (sfu)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Saemundsson</string>
|
||||
<string>Jansky (Jy)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Positional Astronomy Library</string>
|
||||
<string>Watts per square metre per hertz (W m^-2 Hz-1)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QCheckBox" name="enableServer">
|
||||
<property name="toolTip">
|
||||
<string>Enable Stellarium server which allows RA and Dec to be sent to and from Stellarium</string>
|
||||
</property>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="updatePeriodLabel">
|
||||
<property name="text">
|
||||
<string>Stellarium server</string>
|
||||
<string>Update period (s)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -106,16 +135,66 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QSpinBox" name="frequency">
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="humidity">
|
||||
<property name="toolTip">
|
||||
<string>Radio frequency being observed</string>
|
||||
<string>Relative humidity in %</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>435</number>
|
||||
<number>80</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="solarFluxUnitsLabel">
|
||||
<property name="text">
|
||||
<string>Solar flux density units</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QCheckBox" name="drawSunOnMap">
|
||||
<property name="text">
|
||||
<string>Draw Sun on map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QSpinBox" name="serverPort">
|
||||
<property name="toolTip">
|
||||
<string>Stellarium telescope server IP port number</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10001</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="serverPortLabel">
|
||||
<property name="text">
|
||||
<string>Stellarium server port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -126,6 +205,63 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="temperatureLapseRateLabel">
|
||||
<property name="toolTip">
|
||||
<string>Temperature lapse rate (K/m)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Temperature lapse rate (K/km)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="pressureLabel">
|
||||
<property name="text">
|
||||
<string>Air pressure (mb)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QCheckBox" name="enableServer">
|
||||
<property name="toolTip">
|
||||
<string>Enable Stellarium server which allows RA and Dec to be sent to and from Stellarium</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stellarium server</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="epoch">
|
||||
<property name="toolTip">
|
||||
<string>Epoch for custom right ascension and declination</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>J2000</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>JNOW</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="temperatureLapseRate">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>6.490000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="temperatureLabel">
|
||||
<property name="text">
|
||||
@ -133,6 +269,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="humidityLabel">
|
||||
<property name="text">
|
||||
<string>Humidity (%)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="azElUnits">
|
||||
<property name="toolTip">
|
||||
@ -163,197 +306,98 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QCheckBox" name="drawSunOnMap">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="refractionLabel">
|
||||
<property name="text">
|
||||
<string>Draw Sun on map</string>
|
||||
<string>Refraction correction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="heightLabel">
|
||||
<property name="text">
|
||||
<string>Height above sea level (m)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="epoch">
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="refraction">
|
||||
<property name="toolTip">
|
||||
<string>Epoch for custom right ascension and declination</string>
|
||||
<string>Atmospheric refraction correction</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>J2000</string>
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>JNOW</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="humidityLabel">
|
||||
<property name="text">
|
||||
<string>Humidity (%)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QDoubleSpinBox" name="temperatureLapseRate">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>6.490000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<widget class="QCheckBox" name="drawMoonOnMap">
|
||||
<property name="text">
|
||||
<string>Draw Moon on map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="pressure">
|
||||
<property name="toolTip">
|
||||
<string>Air pressure in millibars, for use in atmospheric refraction correction</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1010.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="temperatureLapseRateLabel">
|
||||
<property name="toolTip">
|
||||
<string>Temperature lapse rate (K/m)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Temperature lapse rate (K/km)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="humidity">
|
||||
<property name="toolTip">
|
||||
<string>Relative humidity in %</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>80</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QSpinBox" name="serverPort">
|
||||
<property name="toolTip">
|
||||
<string>Stellarium telescope server IP port number</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10001</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="temperature">
|
||||
<property name="toolTip">
|
||||
<string>Air temperature in degrees Celsius, for use in atmospheric refraction correction</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QDoubleSpinBox" name="updatePeriod">
|
||||
<property name="toolTip">
|
||||
<string>Enter the time in seconds between each calculation of the target's position</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="serverPortLabel">
|
||||
<property name="text">
|
||||
<string>Stellarium server port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<widget class="QCheckBox" name="drawStarOnMap">
|
||||
<property name="text">
|
||||
<string>Draw target star on map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="solarFluxUnitsLabel">
|
||||
<property name="text">
|
||||
<string>Solar flux units</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="solarFluxUnits">
|
||||
<property name="toolTip">
|
||||
<string>Units to use for the display of the Solar flux</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Solar flux units (sfu)</string>
|
||||
<string>Saemundsson</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Jansky (Jy)</string>
|
||||
<string>Positional Astronomy Library</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="solarFluxDataLabel">
|
||||
<property name="text">
|
||||
<string>Solar flux density data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QComboBox" name="solarFluxData">
|
||||
<property name="toolTip">
|
||||
<string>Select frequency at which to display Solar flux density data for</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DRAO (2800MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Watts per square metre per hertz (W m^-2 Hz-1)</string>
|
||||
<string>Learmonth (245MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (410MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (610MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (1415MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (2695MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (4995MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (8800MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Learmonth (15400MHz)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Observation frequency</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@ -382,7 +426,6 @@
|
||||
<tabstop>humidity</tabstop>
|
||||
<tabstop>height</tabstop>
|
||||
<tabstop>temperatureLapseRate</tabstop>
|
||||
<tabstop>frequency</tabstop>
|
||||
<tabstop>solarFluxUnits</tabstop>
|
||||
<tabstop>updatePeriod</tabstop>
|
||||
<tabstop>serverPort</tabstop>
|
||||
|
@ -184,6 +184,7 @@ set(sdrbase_SOURCES
|
||||
util/csv.cpp
|
||||
util/db.cpp
|
||||
util/fixedtraits.cpp
|
||||
util/fits.cpp
|
||||
util/httpdownloadmanager.cpp
|
||||
util/lfsr.cpp
|
||||
util/maidenhead.cpp
|
||||
@ -377,6 +378,7 @@ set(sdrbase_HEADERS
|
||||
util/doublebuffer.h
|
||||
util/doublebufferfifo.h
|
||||
util/fixedtraits.h
|
||||
util/fits.h
|
||||
util/httpdownloadmanager.h
|
||||
util/incrementalarray.h
|
||||
util/incrementalvector.h
|
||||
|
@ -492,6 +492,61 @@ double Astronomy::lstAndRAToLongitude(double lst, double raHours)
|
||||
return -longitude; // East positive
|
||||
}
|
||||
|
||||
// Return right ascension and declination of North Galactic Pole in J2000 Epoch
|
||||
void Astronomy::northGalacticPoleJ2000(double& ra, double& dec)
|
||||
{
|
||||
ra = 12 + 51.4 / 60.0;
|
||||
dec = 27.13;
|
||||
}
|
||||
|
||||
// Convert from equatorial to Galactic coordinates, J2000 Epoch
|
||||
void Astronomy::equatorialToGalactic(double ra, double dec, double& l, double& b)
|
||||
{
|
||||
const double raRad = Units::degreesToRadians(ra * 15.0);
|
||||
const double decRad = Units::degreesToRadians(dec);
|
||||
|
||||
// Calculate RA and dec for North Galactic pole, J2000
|
||||
double ngpRa, ngpDec;
|
||||
northGalacticPoleJ2000(ngpRa, ngpDec);
|
||||
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);
|
||||
|
||||
// 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;
|
||||
|
||||
// Convert to degrees in range -90,90 and 0,360
|
||||
b = Units::radiansToDegrees(bRad);
|
||||
l = Units::radiansToDegrees(lRad);
|
||||
if (l < 0.0)
|
||||
l += 360.0;
|
||||
if (l > 360.0)
|
||||
l -= 360.0;
|
||||
}
|
||||
|
||||
// The following functions are from Starlink Positional Astronomy Library
|
||||
// https://github.com/Starlink/pal
|
||||
|
||||
|
@ -61,6 +61,9 @@ public:
|
||||
|
||||
static double lstAndRAToLongitude(double lst, double raHours);
|
||||
|
||||
static void equatorialToGalactic(double ra, double dec, double& l, double& b);
|
||||
static void northGalacticPoleJ2000(double& ra, double& dec);
|
||||
|
||||
protected:
|
||||
static double modulo(double a, double b);
|
||||
};
|
||||
|
164
sdrbase/util/fits.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QRegExp>
|
||||
#include <QDebug>
|
||||
#include <QResource>
|
||||
|
||||
#include "fits.h"
|
||||
|
||||
FITS::FITS(QString resourceName) :
|
||||
m_valid(false)
|
||||
{
|
||||
QResource m_res(resourceName);
|
||||
int m_headerSize = 2880;
|
||||
qint64 m_fileSize;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
m_data = m_res.uncompressedData();
|
||||
m_fileSize = m_res.uncompressedSize();
|
||||
#else
|
||||
m_data = QByteArray::fromRawData((const char *)m_res.data(), m_res.size());
|
||||
m_fileSize = m_res.size();
|
||||
#endif
|
||||
int hLen = std::min((qint64)m_headerSize * 3, m_fileSize); // Could possibly be bigger
|
||||
QByteArray headerBytes = m_data.left(hLen);
|
||||
QString header = QString::fromLatin1(headerBytes);
|
||||
QRegExp widthRE("NAXIS1 *= *([0-9]+)");
|
||||
QRegExp heightRE("NAXIS2 *= *([0-9]+)");
|
||||
QRegExp bitsPerPixelRE("BITPIX *= *(-?[0-9]+)");
|
||||
QRegExp bzeroRE("BZERO *= *([0-9]+)");
|
||||
QRegExp bscaleRE("BSCALE *= *(-?[0-9]+(.[0-9]+)?)");
|
||||
QRegExp buintRE("BUNIT *= *\\'([A-Z ]+)\\'");
|
||||
QRegExp cdelt1RE("CDELT1 *= *(-?[0-9]+(.[0-9]+)?)");
|
||||
QRegExp cdelt2RE("CDELT2 *= *(-?[0-9]+(.[0-9]+)?)");
|
||||
QRegExp endRE("END {77}");
|
||||
|
||||
if (widthRE.indexIn(header) != -1)
|
||||
m_width = widthRE.capturedTexts()[1].toInt();
|
||||
else
|
||||
{
|
||||
qWarning() << "FITS: NAXIS1 missing";
|
||||
return;
|
||||
}
|
||||
if (heightRE.indexIn(header) != -1)
|
||||
m_height = heightRE.capturedTexts()[1].toInt();
|
||||
else
|
||||
{
|
||||
qWarning() << "FITS: NAXIS2 missing";
|
||||
return;
|
||||
}
|
||||
if (bitsPerPixelRE.indexIn(header) != -1)
|
||||
m_bitsPerPixel = bitsPerPixelRE.capturedTexts()[1].toInt();
|
||||
else
|
||||
{
|
||||
qWarning() << "FITS: BITPIX missing";
|
||||
return;
|
||||
}
|
||||
m_bytesPerPixel = abs(m_bitsPerPixel)/8;
|
||||
if (bzeroRE.indexIn(header) != -1)
|
||||
m_bzero = bzeroRE.capturedTexts()[1].toInt();
|
||||
else
|
||||
m_bzero = 0;
|
||||
if (bscaleRE.indexIn(header) != -1)
|
||||
m_bscale = bscaleRE.capturedTexts()[1].toDouble();
|
||||
else
|
||||
m_bscale = 1.0;
|
||||
|
||||
if (cdelt1RE.indexIn(header) != -1)
|
||||
m_cdelta1 = cdelt1RE.capturedTexts()[1].toDouble();
|
||||
else
|
||||
m_cdelta1 = 0.0;
|
||||
if (cdelt2RE.indexIn(header) != -1)
|
||||
m_cdelta2 = cdelt2RE.capturedTexts()[1].toDouble();
|
||||
else
|
||||
m_cdelta2 = 0.0;
|
||||
|
||||
if (buintRE.indexIn(header) != -1)
|
||||
{
|
||||
m_buint = buintRE.capturedTexts()[1].trimmed();
|
||||
if (m_buint.contains("MILLI"))
|
||||
m_uintScale = 0.001f;
|
||||
else
|
||||
m_uintScale = 1.0f;
|
||||
}
|
||||
else
|
||||
m_uintScale = 1.0f;
|
||||
int endIdx = endRE.indexIn(header);
|
||||
if (endIdx == -1)
|
||||
{
|
||||
qWarning() << "FITS: END missing";
|
||||
return;
|
||||
}
|
||||
m_dataStart = ((endIdx + m_headerSize) / m_headerSize) * m_headerSize;
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
float FITS::value(int x, int y)
|
||||
{
|
||||
int offset = m_dataStart + (m_height-1-y) * m_width * m_bytesPerPixel + x * m_bytesPerPixel;
|
||||
const uchar *data = (const uchar *)m_data.data();
|
||||
// Big-endian
|
||||
int v = 0;
|
||||
for (int i = m_bytesPerPixel - 1; i >= 0; i--)
|
||||
v += data[offset++] << (i*8);
|
||||
if (m_bitsPerPixel > 0)
|
||||
{
|
||||
// Sign-extend
|
||||
switch (m_bytesPerPixel)
|
||||
{
|
||||
case 1:
|
||||
v = (char)v;
|
||||
break;
|
||||
case 2:
|
||||
v = (qint16)v;
|
||||
break;
|
||||
case 3:
|
||||
v = (qint32)v;
|
||||
break;
|
||||
}
|
||||
return v * m_bscale + m_bzero;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Type-punning via unions apparently undefined behaviour in C++
|
||||
uint32_t i = (uint32_t)v;
|
||||
float f;
|
||||
memcpy(&f, &i, sizeof(f));
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
float FITS::scaledValue(int x, int y)
|
||||
{
|
||||
float v = value(x, y);
|
||||
return v * m_uintScale;
|
||||
}
|
||||
|
||||
int FITS::mod(int a, int b)
|
||||
{
|
||||
return a - b * floor(a/(double)b);
|
||||
}
|
||||
|
||||
float FITS::scaledWrappedValue(int x, int y)
|
||||
{
|
||||
float v = value(mod(x, m_width), mod(y, m_height));
|
||||
return v * m_uintScale;
|
||||
}
|
66
sdrbase/util/fits.h
Normal file
@ -0,0 +1,66 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 INCLUDE_UTIL_FITS_H
|
||||
#define INCLUDE_UTIL_FITS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
// Flexible Image Transport System
|
||||
// Specification: https://fits.gsfc.nasa.gov/standard40/fits_standard40aa-le.pdf
|
||||
// This just implements the minimum functionality used by the files
|
||||
// used by the StarTracker plugin
|
||||
class SDRBASE_API FITS {
|
||||
|
||||
bool m_valid;
|
||||
int m_width; // In pixels
|
||||
int m_height; // In pixels
|
||||
int m_bitsPerPixel; // BITPIX=-32 means single precision floating point
|
||||
int m_bytesPerPixel;
|
||||
int m_bzero;
|
||||
double m_bscale;
|
||||
QString m_buint; // "K TB" "MILLIK TB" "K"
|
||||
float m_uintScale;
|
||||
double m_cdelta1; // How many degrees RA per horizontal pixel
|
||||
double m_cdelta2; // How many degrees Declination per vertical pixel
|
||||
|
||||
int m_dataStart;
|
||||
QByteArray m_data;
|
||||
|
||||
public:
|
||||
|
||||
FITS(QString resourceName);
|
||||
|
||||
float value(int x, int y);
|
||||
float scaledValue(int x, int y);
|
||||
float scaledWrappedValue(int x, int y);
|
||||
|
||||
double degreesPerPixelH() { return m_cdelta1; }
|
||||
double degreesPerPixelV() { return m_cdelta2; }
|
||||
int width() { return m_width; }
|
||||
int height() { return m_height; }
|
||||
bool valid() { return m_valid; }
|
||||
|
||||
protected:
|
||||
|
||||
int mod(int a, int b);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_UTIL_FITS_H
|
@ -18,6 +18,8 @@
|
||||
#include "httpdownloadmanager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
|
||||
HttpDownloadManager::HttpDownloadManager()
|
||||
{
|
||||
@ -34,10 +36,32 @@ QNetworkReply *HttpDownloadManager::download(const QUrl &url, const QString &fil
|
||||
qDebug() << "HttpDownloadManager: Downloading from " << url << " to " << filename;
|
||||
downloads.append(reply);
|
||||
filenames.append(filename);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
qint64 HttpDownloadManager::fileAgeInDays(const QString& filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (file.exists())
|
||||
{
|
||||
QDateTime modified = file.fileTime(QFileDevice::FileModificationTime);
|
||||
if (modified.isValid())
|
||||
return modified.daysTo(QDateTime::currentDateTime());
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get default directory to write downloads to
|
||||
QString HttpDownloadManager::downloadDir()
|
||||
{
|
||||
// Get directory to store app data in
|
||||
QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
|
||||
// First dir is writable
|
||||
return locations[0];
|
||||
}
|
||||
|
||||
void HttpDownloadManager::sslErrors(const QList<QSslError> &sslErrors)
|
||||
{
|
||||
for (const QSslError &error : sslErrors)
|
||||
|
@ -33,6 +33,11 @@ public:
|
||||
HttpDownloadManager();
|
||||
QNetworkReply *download(const QUrl &url, const QString &filename);
|
||||
|
||||
static QString downloadDir();
|
||||
|
||||
protected:
|
||||
static qint64 fileAgeInDays(const QString& filename);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager manager;
|
||||
QVector<QNetworkReply *> downloads;
|
||||
|
@ -71,14 +71,16 @@ public:
|
||||
return (int)std::round(feetPerMinToMetresPerSecond(fpm));
|
||||
}
|
||||
|
||||
static float degreesToRadians(float degrees)
|
||||
template <class T>
|
||||
static T degreesToRadians(T degrees)
|
||||
{
|
||||
return degrees * ((float)M_PI) / 180.0f;
|
||||
return degrees * ((T)M_PI) / 180.0f;
|
||||
}
|
||||
|
||||
static float radiansToDegrees(float radians)
|
||||
template <class T>
|
||||
static T radiansToDegrees(T radians)
|
||||
{
|
||||
return radians * 180.0f / ((float)M_PI);
|
||||
return radians * 180.0f / ((T)M_PI);
|
||||
}
|
||||
|
||||
static float fahrenheitToCelsius(float fahrenheit)
|
||||
@ -218,7 +220,8 @@ public:
|
||||
return sfu * 10000.0f;
|
||||
}
|
||||
|
||||
static float solarFluxUnitsToWattsPerMetrePerHertz(float sfu)
|
||||
template <class T>
|
||||
static T solarFluxUnitsToWattsPerMetrePerHertz(T sfu)
|
||||
{
|
||||
return sfu * 1e-22f;
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ set(sdrgui_SOURCES
|
||||
gui/glshadertvarray.cpp
|
||||
gui/glspectrum.cpp
|
||||
gui/glspectrumgui.cpp
|
||||
gui/httpdownloadmanagergui.cpp
|
||||
gui/indicator.cpp
|
||||
gui/levelmeter.cpp
|
||||
gui/loggingdialog.cpp
|
||||
@ -128,6 +129,7 @@ set(sdrgui_HEADERS
|
||||
gui/glshadertextured.h
|
||||
gui/glspectrum.h
|
||||
gui/glspectrumgui.h
|
||||
gui/httpdownloadmanagergui.h
|
||||
gui/indicator.h
|
||||
gui/levelmeter.h
|
||||
gui/loggingdialog.h
|
||||
|
80
sdrgui/gui/httpdownloadmanagergui.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 "httpdownloadmanagergui.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QProgressDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
HttpDownloadManagerGUI::HttpDownloadManagerGUI()
|
||||
{
|
||||
connect(this, &HttpDownloadManager::downloadComplete, this, &HttpDownloadManagerGUI::downloadCompleteGUI);
|
||||
}
|
||||
|
||||
QNetworkReply *HttpDownloadManagerGUI::download(const QUrl &url, const QString &filename, QWidget *parent)
|
||||
{
|
||||
QNetworkReply *reply = HttpDownloadManager::download(url, filename);
|
||||
if (parent != nullptr)
|
||||
{
|
||||
QProgressDialog *progressDialog = new QProgressDialog(parent);
|
||||
progressDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
progressDialog->setCancelButton(nullptr);
|
||||
progressDialog->setMinimumDuration(500);
|
||||
progressDialog->setLabelText(QString("Downloading %1.").arg(url.toString()));
|
||||
m_progressDialogs.append(progressDialog);
|
||||
connect(reply, &QNetworkReply::downloadProgress, this, [progressDialog](qint64 bytesRead, qint64 totalBytes) {
|
||||
progressDialog->setMaximum(totalBytes);
|
||||
progressDialog->setValue(bytesRead);
|
||||
});
|
||||
}
|
||||
else
|
||||
m_progressDialogs.append(nullptr);
|
||||
return reply;
|
||||
}
|
||||
|
||||
// Confirm if user wants to re-download an existing file
|
||||
bool HttpDownloadManagerGUI::confirmDownload(const QString& filename, QWidget *parent, int maxAge)
|
||||
{
|
||||
qint64 age = HttpDownloadManager::fileAgeInDays(filename);
|
||||
if ((age == -1) || (age > maxAge))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
QMessageBox::StandardButton reply;
|
||||
if (age == 0)
|
||||
reply = QMessageBox::question(parent, "Confirm download", "This file was last downloaded today. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No);
|
||||
else if (age == 1)
|
||||
reply = QMessageBox::question(parent, "Confirm download", "This file was last downloaded yesterday. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No);
|
||||
else
|
||||
reply = QMessageBox::question(parent, "Confirm download", QString("This file was last downloaded %1 days ago. Are you sure you wish to redownload this file?").arg(age), QMessageBox::Yes|QMessageBox::No);
|
||||
return reply == QMessageBox::Yes;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpDownloadManagerGUI::downloadCompleteGUI(const QString& filename, bool success)
|
||||
{
|
||||
int idx = m_filenames.indexOf(filename);
|
||||
if (idx >= 0)
|
||||
{
|
||||
QProgressDialog *progressDialog = m_progressDialogs[idx];
|
||||
if (progressDialog != nullptr)
|
||||
progressDialog->close();
|
||||
m_filenames.remove(idx);
|
||||
m_progressDialogs.remove(idx);
|
||||
}
|
||||
}
|
45
sdrgui/gui/httpdownloadmanagergui.h
Normal file
@ -0,0 +1,45 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 INCLUDE_HTTPDOWNLOADMANAGERGUI_H
|
||||
#define INCLUDE_HTTPDOWNLOADMANAGERGUI_H
|
||||
|
||||
#include "util/httpdownloadmanager.h"
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class QWidget;
|
||||
class QProgressDialog;
|
||||
|
||||
// Class to download files via http and write them to disk with progress dialog
|
||||
class SDRGUI_API HttpDownloadManagerGUI : public HttpDownloadManager
|
||||
{
|
||||
public:
|
||||
HttpDownloadManagerGUI();
|
||||
QNetworkReply *download(const QUrl &url, const QString &filename, QWidget *parent = nullptr);
|
||||
|
||||
static bool confirmDownload(const QString& filename, QWidget *parent = nullptr, int maxAge = 100);
|
||||
|
||||
private:
|
||||
QVector<QString> m_filenames;
|
||||
QVector<QProgressDialog *> m_progressDialogs;
|
||||
|
||||
public slots:
|
||||
void downloadCompleteGUI(const QString &filename, bool success);
|
||||
};
|
||||
|
||||
#endif /* INCLUDE_HTTPDOWNLOADMANAGERGUI_H */
|