SVN r8568
This commit is contained in:
@@ -1,522 +0,0 @@
|
||||
#include "widegraph.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <QApplication>
|
||||
#include <QSettings>
|
||||
#include "ui_widegraph.h"
|
||||
#include "commons.h"
|
||||
#include "Configuration.hpp"
|
||||
#include "MessageBox.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "moc_widegraph.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
auto user_defined = QObject::tr ("User Defined");
|
||||
float swide[MAX_SCREENSIZE];
|
||||
}
|
||||
|
||||
WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::WideGraph),
|
||||
m_settings (settings),
|
||||
m_palettes_path {":/Palettes"},
|
||||
m_ntr0 {0},
|
||||
m_lockTxFreq {false},
|
||||
m_bHaveTransmitted {false},
|
||||
m_n {0}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Wide Graph"));
|
||||
setWindowFlags (Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
|
||||
setMaximumWidth (MAX_SCREENSIZE);
|
||||
setMaximumHeight (880);
|
||||
|
||||
ui->widePlot->setCursor(Qt::CrossCursor);
|
||||
ui->widePlot->setMaximumHeight(800);
|
||||
ui->widePlot->setCurrent(false);
|
||||
|
||||
connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this,
|
||||
SLOT(wideFreezeDecode(int)));
|
||||
|
||||
connect(ui->widePlot, SIGNAL(setFreq1(int,int)),this,
|
||||
SLOT(setFreq2(int,int)));
|
||||
|
||||
{
|
||||
//Restore user's settings
|
||||
SettingsGroup g {m_settings, "WideGraph"};
|
||||
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
|
||||
ui->widePlot->setPlotZero(m_settings->value("PlotZero", 0).toInt());
|
||||
ui->widePlot->setPlotGain(m_settings->value("PlotGain", 0).toInt());
|
||||
ui->widePlot->setPlot2dGain(m_settings->value("Plot2dGain", 0).toInt());
|
||||
ui->widePlot->setPlot2dZero(m_settings->value("Plot2dZero", 0).toInt());
|
||||
ui->zeroSlider->setValue(ui->widePlot->plotZero());
|
||||
ui->gainSlider->setValue(ui->widePlot->plotGain());
|
||||
ui->gain2dSlider->setValue(ui->widePlot->plot2dGain());
|
||||
ui->zero2dSlider->setValue(ui->widePlot->plot2dZero());
|
||||
int n = m_settings->value("BinsPerPixel",2).toInt();
|
||||
m_bFlatten=m_settings->value("Flatten",true).toBool();
|
||||
m_bRef=m_settings->value("UseRef",false).toBool();
|
||||
ui->cbFlatten->setChecked(m_bFlatten);
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
ui->cbRef->setChecked(m_bRef);
|
||||
ui->widePlot->setBreadth(m_settings->value("PlotWidth",1000).toInt());
|
||||
ui->bppSpinBox->setValue(n);
|
||||
m_nsmo=m_settings->value("SmoothYellow",1).toInt();
|
||||
ui->smoSpinBox->setValue(m_nsmo);
|
||||
m_Percent2DScreen=m_settings->value("Percent2D",30).toInt();
|
||||
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
|
||||
m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt();
|
||||
ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
|
||||
ui->widePlot->setWaterfallAvg(m_waterfallAvg);
|
||||
ui->widePlot->setCurrent(m_settings->value("Current",false).toBool());
|
||||
ui->widePlot->setCumulative(m_settings->value("Cumulative",true).toBool());
|
||||
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
|
||||
ui->widePlot->setReference(m_settings->value("Reference",false).toBool());
|
||||
if(ui->widePlot->current()) ui->spec2dComboBox->setCurrentIndex(0);
|
||||
if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1);
|
||||
if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2);
|
||||
if(ui->widePlot->Reference()) ui->spec2dComboBox->setCurrentIndex(3);
|
||||
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
|
||||
ui->widePlot->setBinsPerPixel(nbpp);
|
||||
ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt());
|
||||
ui->fStartSpinBox->setValue(ui->widePlot->startFreq());
|
||||
m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString();
|
||||
m_userPalette = WFPalette {m_settings->value("UserPalette").value<WFPalette::Colours> ()};
|
||||
int m_fMin = m_settings->value ("Fmin", 2500).toInt ();
|
||||
ui->fSplitSpinBox->setValue (m_fMin);
|
||||
setRxRange ();
|
||||
ui->controls_widget->setVisible(!m_settings->value("HideControls", false).toBool ());
|
||||
}
|
||||
|
||||
saveSettings (); // update config with defaults
|
||||
|
||||
int index=0;
|
||||
for (QString const& file:
|
||||
m_palettes_path.entryList(QDir::NoDotAndDotDot |
|
||||
QDir::System | QDir::Hidden |
|
||||
QDir::AllDirs | QDir::Files,
|
||||
QDir::DirsFirst)) {
|
||||
QString t=file.mid(0,file.length()-4);
|
||||
ui->paletteComboBox->addItem(t);
|
||||
if(t==m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
|
||||
index++;
|
||||
}
|
||||
ui->paletteComboBox->addItem (user_defined);
|
||||
if (user_defined == m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
|
||||
readPalette ();
|
||||
}
|
||||
|
||||
WideGraph::~WideGraph ()
|
||||
{
|
||||
}
|
||||
|
||||
void WideGraph::closeEvent (QCloseEvent * e)
|
||||
{
|
||||
saveSettings ();
|
||||
QDialog::closeEvent (e);
|
||||
}
|
||||
|
||||
void WideGraph::saveSettings() //saveSettings
|
||||
{
|
||||
SettingsGroup g {m_settings, "WideGraph"};
|
||||
m_settings->setValue ("geometry", saveGeometry ());
|
||||
m_settings->setValue ("PlotZero", ui->widePlot->plotZero());
|
||||
m_settings->setValue ("PlotGain", ui->widePlot->plotGain());
|
||||
m_settings->setValue ("Plot2dGain", ui->widePlot->plot2dGain());
|
||||
m_settings->setValue ("Plot2dZero", ui->widePlot->plot2dZero());
|
||||
m_settings->setValue ("PlotWidth", ui->widePlot->plotWidth ());
|
||||
m_settings->setValue ("BinsPerPixel", ui->bppSpinBox->value ());
|
||||
m_settings->setValue ("SmoothYellow", ui->smoSpinBox->value ());
|
||||
m_settings->setValue ("Percent2D",m_Percent2DScreen);
|
||||
m_settings->setValue ("WaterfallAvg", ui->waterfallAvgSpinBox->value ());
|
||||
m_settings->setValue ("Current", ui->widePlot->current());
|
||||
m_settings->setValue ("Cumulative", ui->widePlot->cumulative());
|
||||
m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg());
|
||||
m_settings->setValue ("Reference", ui->widePlot->Reference());
|
||||
m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ());
|
||||
m_settings->setValue ("StartFreq", ui->widePlot->startFreq ());
|
||||
m_settings->setValue ("WaterfallPalette", m_waterfallPalette);
|
||||
m_settings->setValue ("UserPalette", QVariant::fromValue (m_userPalette.colours ()));
|
||||
m_settings->setValue("Flatten",m_bFlatten);
|
||||
m_settings->setValue("UseRef",m_bRef);
|
||||
m_settings->setValue ("HideControls", ui->controls_widget->isHidden ());
|
||||
}
|
||||
|
||||
void WideGraph::drawRed(int ia, int ib)
|
||||
{
|
||||
ui->widePlot->drawRed(ia,ib,swide);
|
||||
}
|
||||
|
||||
void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dataSink2
|
||||
{
|
||||
static float splot[NSMAX];
|
||||
int nbpp = ui->widePlot->binsPerPixel();
|
||||
|
||||
//Average spectra over specified number, m_waterfallAvg
|
||||
if (m_n==0) {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i]=s[i];
|
||||
} else {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i] += s[i];
|
||||
}
|
||||
m_n++;
|
||||
|
||||
if (m_n>=m_waterfallAvg) {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i] /= m_n; //Normalize the average
|
||||
m_n=0;
|
||||
int i=int(ui->widePlot->startFreq()/df3 + 0.5);
|
||||
int jz=5000.0/(nbpp*df3);
|
||||
if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE;
|
||||
for (int j=0; j<jz; j++) {
|
||||
float ss=0;
|
||||
for (int k=0; k<nbpp; k++) {
|
||||
if(splot[i]>ss) ss=splot[i];
|
||||
i++;
|
||||
}
|
||||
swide[j]=nbpp*ss;
|
||||
}
|
||||
|
||||
// Time according to this computer
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
int ntr = (ms/1000) % m_TRperiod;
|
||||
if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) {
|
||||
float flagValue=1.0e30;
|
||||
if(m_bHaveTransmitted) flagValue=2.0e30;
|
||||
for (int i=0; i<2048; i++) {
|
||||
swide[i] = flagValue;
|
||||
}
|
||||
m_bHaveTransmitted=false;
|
||||
}
|
||||
m_ntr0=ntr;
|
||||
ui->widePlot->draw(swide,true,false);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_bppSpinBox_valueChanged(int n) //bpp
|
||||
{
|
||||
ui->widePlot->setBinsPerPixel(n);
|
||||
}
|
||||
|
||||
void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) //Navg
|
||||
{
|
||||
m_waterfallAvg = n;
|
||||
ui->widePlot->setWaterfallAvg(n);
|
||||
}
|
||||
|
||||
void WideGraph::keyPressEvent(QKeyEvent *e) //F11, F12
|
||||
{
|
||||
switch(e->key())
|
||||
{
|
||||
int n;
|
||||
case Qt::Key_F11:
|
||||
n=11;
|
||||
if(e->modifiers() & Qt::ControlModifier) n+=100;
|
||||
emit f11f12(n);
|
||||
break;
|
||||
case Qt::Key_F12:
|
||||
n=12;
|
||||
if(e->modifiers() & Qt::ControlModifier) n+=100;
|
||||
emit f11f12(n);
|
||||
break;
|
||||
case Qt::Key_M:
|
||||
if(e->modifiers() & Qt::ControlModifier) {
|
||||
ui->controls_widget->setVisible(!ui->controls_widget->isVisible());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QDialog::keyPressEvent (e);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::setRxFreq(int n) //setRxFreq
|
||||
{
|
||||
ui->widePlot->setRxFreq(n);
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_lockTxFreq) setTxFreq(n);
|
||||
}
|
||||
|
||||
int WideGraph::rxFreq() //rxFreq
|
||||
{
|
||||
return ui->widePlot->rxFreq();
|
||||
}
|
||||
|
||||
int WideGraph::nStartFreq() //nStartFreq
|
||||
{
|
||||
return ui->widePlot->startFreq();
|
||||
}
|
||||
|
||||
void WideGraph::wideFreezeDecode(int n) //wideFreezeDecode
|
||||
{
|
||||
emit freezeDecode2(n);
|
||||
}
|
||||
|
||||
void WideGraph::setRxRange ()
|
||||
{
|
||||
ui->widePlot->setRxRange (Fmin ());
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
int WideGraph::Fmin() //Fmin
|
||||
{
|
||||
return "60m" == m_rxBand ? 0 : m_fMin;
|
||||
}
|
||||
|
||||
int WideGraph::Fmax() //Fmax
|
||||
{
|
||||
return std::min(5000,ui->widePlot->Fmax());
|
||||
}
|
||||
|
||||
int WideGraph::fSpan()
|
||||
{
|
||||
return ui->widePlot->fSpan ();
|
||||
}
|
||||
|
||||
void WideGraph::setPeriod(int ntrperiod, int nsps) //SetPeriod
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
ui->widePlot->setNsps(ntrperiod, nsps);
|
||||
}
|
||||
|
||||
void WideGraph::setTxFreq(int n) //setTxFreq
|
||||
{
|
||||
emit setXIT2(n);
|
||||
ui->widePlot->setTxFreq(n);
|
||||
}
|
||||
|
||||
void WideGraph::setMode(QString mode) //setMode
|
||||
{
|
||||
m_mode=mode;
|
||||
ui->fSplitSpinBox->setEnabled(m_mode=="JT9+JT65");
|
||||
ui->widePlot->setMode(mode);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
void WideGraph::setSubMode(int n) //setSubMode
|
||||
{
|
||||
m_nSubMode=n;
|
||||
ui->widePlot->setSubMode(n);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
void WideGraph::setModeTx(QString modeTx) //setModeTx
|
||||
{
|
||||
m_modeTx=modeTx;
|
||||
ui->widePlot->setModeTx(modeTx);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
//Current-Cumulative-Yellow
|
||||
void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
|
||||
{
|
||||
ui->widePlot->setCurrent(false);
|
||||
ui->widePlot->setCumulative(false);
|
||||
ui->widePlot->setLinearAvg(false);
|
||||
ui->widePlot->setReference(false);
|
||||
ui->smoSpinBox->setEnabled(false);
|
||||
if(arg1=="Current") ui->widePlot->setCurrent(true);
|
||||
if(arg1=="Cumulative") ui->widePlot->setCumulative(true);
|
||||
if(arg1=="Linear Avg") {
|
||||
ui->widePlot->setLinearAvg(true);
|
||||
ui->smoSpinBox->setEnabled(true);
|
||||
}
|
||||
if(arg1=="Reference") {
|
||||
ui->widePlot->setReference(true);
|
||||
}
|
||||
if(ui->widePlot->m_bScaleOK) ui->widePlot->draw(swide,false,false);
|
||||
}
|
||||
|
||||
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
|
||||
{
|
||||
if (m_rxBand != "60m") m_fMin=n;
|
||||
setRxRange ();
|
||||
}
|
||||
|
||||
void WideGraph::setLockTxFreq(bool b) //LockTxFreq
|
||||
{
|
||||
m_lockTxFreq=b;
|
||||
ui->widePlot->setLockTxFreq(b);
|
||||
}
|
||||
|
||||
void WideGraph::setFreq2(int rxFreq, int txFreq) //setFreq2
|
||||
{
|
||||
emit setFreq3(rxFreq,txFreq);
|
||||
}
|
||||
|
||||
void WideGraph::setDialFreq(double d) //setDialFreq
|
||||
{
|
||||
ui->widePlot->setDialFreq(d);
|
||||
}
|
||||
|
||||
void WideGraph::setRxBand (QString const& band)
|
||||
{
|
||||
m_rxBand = band;
|
||||
if ("60m" == m_rxBand)
|
||||
{
|
||||
ui->fSplitSpinBox->setEnabled (false);
|
||||
ui->fSplitSpinBox->setValue (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->fSplitSpinBox->setValue (m_fMin);
|
||||
ui->fSplitSpinBox->setEnabled (true);
|
||||
}
|
||||
ui->widePlot->setRxBand(band);
|
||||
setRxRange ();
|
||||
}
|
||||
|
||||
|
||||
void WideGraph::on_fStartSpinBox_valueChanged(int n) //fStart
|
||||
{
|
||||
ui->widePlot->setStartFreq(n);
|
||||
}
|
||||
|
||||
void WideGraph::readPalette () //readPalette
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user_defined == m_waterfallPalette)
|
||||
{
|
||||
ui->widePlot->setColours (WFPalette {m_userPalette}.interpolate ());
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->widePlot->setColours (WFPalette {m_palettes_path.absoluteFilePath (m_waterfallPalette + ".pal")}.interpolate());
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_paletteComboBox_activated (QString const& palette) //palette selector
|
||||
{
|
||||
m_waterfallPalette = palette;
|
||||
readPalette();
|
||||
}
|
||||
|
||||
void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off
|
||||
{
|
||||
m_bFlatten=b;
|
||||
if(m_bRef and m_bFlatten) {
|
||||
m_bRef=false;
|
||||
ui->cbRef->setChecked(false);
|
||||
}
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
}
|
||||
|
||||
void WideGraph::on_cbRef_toggled(bool b)
|
||||
{
|
||||
m_bRef=b;
|
||||
if(m_bRef and m_bFlatten) {
|
||||
m_bFlatten=false;
|
||||
ui->cbFlatten->setChecked(false);
|
||||
}
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
}
|
||||
|
||||
void WideGraph::on_cbControls_toggled(bool b)
|
||||
{
|
||||
ui->controls_widget->setVisible(b);
|
||||
}
|
||||
|
||||
void WideGraph::on_adjust_palette_push_button_clicked (bool) //Adjust Palette
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_userPalette.design ())
|
||||
{
|
||||
m_waterfallPalette = user_defined;
|
||||
ui->paletteComboBox->setCurrentText (m_waterfallPalette);
|
||||
readPalette ();
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
|
||||
}
|
||||
}
|
||||
|
||||
bool WideGraph::flatten() //Flatten
|
||||
{
|
||||
return m_bFlatten;
|
||||
}
|
||||
|
||||
bool WideGraph::useRef() //Flatten
|
||||
{
|
||||
return m_bRef;
|
||||
}
|
||||
|
||||
void WideGraph::on_gainSlider_valueChanged(int value) //Gain
|
||||
{
|
||||
ui->widePlot->setPlotGain(value);
|
||||
}
|
||||
|
||||
void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
|
||||
{
|
||||
ui->widePlot->setPlotZero(value);
|
||||
}
|
||||
|
||||
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
|
||||
{
|
||||
ui->widePlot->setPlot2dGain(value);
|
||||
if(ui->widePlot->m_bScaleOK) {
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_zero2dSlider_valueChanged(int value) //Zero2
|
||||
{
|
||||
ui->widePlot->setPlot2dZero(value);
|
||||
if(ui->widePlot->m_bScaleOK) {
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::setTol(int n) //setTol
|
||||
{
|
||||
ui->widePlot->setTol(n);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
void WideGraph::on_smoSpinBox_valueChanged(int n)
|
||||
{
|
||||
m_nsmo=n;
|
||||
}
|
||||
|
||||
int WideGraph::smoothYellow()
|
||||
{
|
||||
return m_nsmo;
|
||||
}
|
||||
|
||||
void WideGraph::setWSPRtransmitted()
|
||||
{
|
||||
m_bHaveTransmitted=true;
|
||||
}
|
||||
|
||||
void WideGraph::setVHF(bool bVHF)
|
||||
{
|
||||
ui->widePlot->setVHF(bVHF);
|
||||
}
|
||||
|
||||
void WideGraph::on_sbPercent2dPlot_valueChanged(int n)
|
||||
{
|
||||
m_Percent2DScreen=n;
|
||||
ui->widePlot->SetPercent2DScreen(n);
|
||||
}
|
||||
|
||||
void WideGraph::setRedFile(QString fRed)
|
||||
{
|
||||
ui->widePlot->setRedFile(fRed);
|
||||
}
|
||||
@@ -1,546 +0,0 @@
|
||||
#include "PhaseEqualizationDialog.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
#include <QDir>
|
||||
#include <QVector>
|
||||
#include <QHBoxLayout>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "qcustomplot.h"
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float constexpr PI = 3.1415927f;
|
||||
char const * const title = "Phase Equalization";
|
||||
size_t constexpr intervals = 144;
|
||||
|
||||
// plot data loaders - wraps a plot providing value_type and
|
||||
// push_back so that a std::back_inserter output iterator can be
|
||||
// used to load plot data
|
||||
template<typename T, typename A>
|
||||
struct plot_data_loader
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
// the adjust argument is a function that is passed the plot
|
||||
// pointer, the graph index and a data point, it returns a
|
||||
// possibly adjusted data point and can modify the graph including
|
||||
// adding extra points or gaps (quiet_NaN)
|
||||
plot_data_loader (QCustomPlot * plot, int graph_index, A adjust)
|
||||
: plot_ {plot}
|
||||
, index_ {graph_index}
|
||||
, adjust_ (adjust)
|
||||
{
|
||||
}
|
||||
|
||||
// load point into graph
|
||||
void push_back (value_type const& d)
|
||||
{
|
||||
plot_->graph (index_)->data ()->add (adjust_ (plot_, index_, d));
|
||||
}
|
||||
|
||||
private:
|
||||
QCustomPlot * plot_;
|
||||
int index_;
|
||||
A adjust_;
|
||||
};
|
||||
// helper function template to make a plot_data_loader instance
|
||||
template<typename A>
|
||||
auto make_plot_data_loader (QCustomPlot * plot, int index, A adjust)
|
||||
-> plot_data_loader<QCPGraphData, decltype (adjust)>
|
||||
{
|
||||
return plot_data_loader<QCPGraphData, decltype (adjust)> {plot, index, adjust};
|
||||
}
|
||||
// identity adjust function when no adjustment is needed with the
|
||||
// above instantiation helper
|
||||
QCPGraphData adjust_identity (QCustomPlot *, int, QCPGraphData const& v) {return v;}
|
||||
|
||||
// a plot_data_loader adjustment function that wraps Y values of
|
||||
// (-1..+1) plotting discontinuities as gaps in the graph data
|
||||
auto wrap_pi = [] (QCustomPlot * plot, int index, QCPGraphData d)
|
||||
{
|
||||
double constexpr limit {1};
|
||||
static unsigned wrap_count {0};
|
||||
static double last_x {std::numeric_limits<double>::lowest ()};
|
||||
|
||||
d.value += 2 * limit * wrap_count;
|
||||
if (d.value > limit)
|
||||
{
|
||||
// insert a gap in the graph
|
||||
plot->graph (index)->data ()->add ({last_x + (d.key - last_x) / 2
|
||||
, std::numeric_limits<double>::quiet_NaN ()});
|
||||
while (d.value > limit)
|
||||
{
|
||||
--wrap_count;
|
||||
d.value -= 2 * limit;
|
||||
}
|
||||
}
|
||||
else if (d.value < -limit)
|
||||
{
|
||||
// insert a gap into the graph
|
||||
plot->graph (index)->data ()->add ({last_x + (d.key - last_x) / 2
|
||||
, std::numeric_limits<double>::quiet_NaN ()});
|
||||
while (d.value < -limit)
|
||||
{
|
||||
++wrap_count;
|
||||
d.value += 2 * limit;
|
||||
}
|
||||
}
|
||||
last_x = d.key;
|
||||
return d;
|
||||
};
|
||||
|
||||
// generate points of type R from a function of type F for X in
|
||||
// (-1..+1) with N intervals and function of type SX to scale X and
|
||||
// of type SY to scale Y
|
||||
//
|
||||
// it is up to the user to call the generator sufficient times which
|
||||
// is interval+1 times to reach +1
|
||||
template<typename R, typename F, typename SX, typename SY>
|
||||
struct graph_generator
|
||||
{
|
||||
public:
|
||||
graph_generator (F f, size_t intervals, SX x_scaling, SY y_scaling)
|
||||
: x_ {0}
|
||||
, f_ (f)
|
||||
, intervals_ {intervals}
|
||||
, x_scaling_ (x_scaling)
|
||||
, y_scaling_ (y_scaling)
|
||||
{
|
||||
}
|
||||
|
||||
R operator () ()
|
||||
{
|
||||
typename F::value_type x {x_++ * 2.f / intervals_ - 1.f};
|
||||
return {x_scaling_ (x), y_scaling_ (f_ (x))};
|
||||
}
|
||||
|
||||
private:
|
||||
int x_;
|
||||
F f_;
|
||||
size_t intervals_;
|
||||
SX x_scaling_;
|
||||
SY y_scaling_;
|
||||
};
|
||||
// helper function template to make a graph_generator instance for
|
||||
// QCPGraphData type points with intervals intervals
|
||||
template<typename F, typename SX, typename SY>
|
||||
auto make_graph_generator (F function, SX x_scaling, SY y_scaling)
|
||||
-> graph_generator<QCPGraphData, F, decltype (x_scaling), decltype (y_scaling)>
|
||||
{
|
||||
return graph_generator<QCPGraphData, F, decltype (x_scaling), decltype (y_scaling)>
|
||||
{function, intervals, x_scaling, y_scaling};
|
||||
}
|
||||
|
||||
// template function object for a polynomial with coefficients
|
||||
template<typename C>
|
||||
class polynomial
|
||||
{
|
||||
public:
|
||||
typedef typename C::value_type value_type;
|
||||
|
||||
explicit polynomial (C const& coefficients)
|
||||
: c_ {coefficients}
|
||||
{
|
||||
}
|
||||
|
||||
value_type operator () (value_type const& x)
|
||||
{
|
||||
value_type y {};
|
||||
for (typename C::size_type i = c_.size (); i > 0; --i)
|
||||
{
|
||||
y = c_[i - 1] + x * y;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
C c_;
|
||||
};
|
||||
// helper function template to instantiate a polynomial instance
|
||||
template<typename C>
|
||||
auto make_polynomial (C const& coefficients) -> polynomial<C>
|
||||
{
|
||||
return polynomial<C> (coefficients);
|
||||
}
|
||||
|
||||
// template function object for a group delay with coefficients
|
||||
template<typename C>
|
||||
class group_delay
|
||||
{
|
||||
public:
|
||||
typedef typename C::value_type value_type;
|
||||
|
||||
explicit group_delay (C const& coefficients)
|
||||
: c_ {coefficients}
|
||||
{
|
||||
}
|
||||
|
||||
value_type operator () (value_type const& x)
|
||||
{
|
||||
value_type tau {};
|
||||
for (typename C::size_type i = 2; i < c_.size (); ++i)
|
||||
{
|
||||
tau += i * c_[i] * std::pow (x, i - 1);
|
||||
}
|
||||
return -1 / (2 * PI) * tau;
|
||||
}
|
||||
|
||||
private:
|
||||
C c_;
|
||||
};
|
||||
// helper function template to instantiate a group_delay function
|
||||
// object
|
||||
template<typename C>
|
||||
auto make_group_delay (C const& coefficients) -> group_delay<C>
|
||||
{
|
||||
return group_delay<C> (coefficients);
|
||||
}
|
||||
|
||||
// handy identity function
|
||||
template<typename T> T identity (T const& v) {return v;}
|
||||
|
||||
// a lambda that scales the X axis from normalized to (500..2500)Hz
|
||||
auto freq_scaling = [] (float v) -> float {return 1500.f + 1000.f * v;};
|
||||
|
||||
// a lambda that scales the phase Y axis from radians to units of Pi
|
||||
auto pi_scaling = [] (float v) -> float {return v / PI;};
|
||||
}
|
||||
|
||||
class PhaseEqualizationDialog::impl final
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit impl (PhaseEqualizationDialog * self, QSettings * settings
|
||||
, QDir const& data_directory, QVector<double> const& coefficients
|
||||
, QWidget * parent);
|
||||
~impl () {save_window_state ();}
|
||||
|
||||
protected:
|
||||
void closeEvent (QCloseEvent * e) override
|
||||
{
|
||||
save_window_state ();
|
||||
QDialog::closeEvent (e);
|
||||
}
|
||||
|
||||
private:
|
||||
void save_window_state ()
|
||||
{
|
||||
SettingsGroup g (settings_, title);
|
||||
settings_->setValue ("geometry", saveGeometry ());
|
||||
}
|
||||
|
||||
void plot_current ();
|
||||
void plot_phase ();
|
||||
void plot_amplitude ();
|
||||
|
||||
PhaseEqualizationDialog * self_;
|
||||
QSettings * settings_;
|
||||
QDir data_directory_;
|
||||
QHBoxLayout layout_;
|
||||
QVector<double> current_coefficients_;
|
||||
QVector<double> new_coefficients_;
|
||||
unsigned amp_poly_low_;
|
||||
unsigned amp_poly_high_;
|
||||
QVector<double> amp_coefficients_;
|
||||
QCustomPlot plot_;
|
||||
QDialogButtonBox button_box_;
|
||||
};
|
||||
|
||||
#include "PhaseEqualizationDialog.moc"
|
||||
|
||||
PhaseEqualizationDialog::PhaseEqualizationDialog (QSettings * settings
|
||||
, QDir const& data_directory
|
||||
, QVector<double> const& coefficients
|
||||
, QWidget * parent)
|
||||
: m_ {this, settings, data_directory, coefficients, parent}
|
||||
{
|
||||
}
|
||||
|
||||
void PhaseEqualizationDialog::show ()
|
||||
{
|
||||
m_->show ();
|
||||
}
|
||||
|
||||
PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
||||
, QSettings * settings
|
||||
, QDir const& data_directory
|
||||
, QVector<double> const& coefficients
|
||||
, QWidget * parent)
|
||||
: QDialog {parent}
|
||||
, self_ {self}
|
||||
, settings_ {settings}
|
||||
, data_directory_ {data_directory}
|
||||
, current_coefficients_ {coefficients}
|
||||
, amp_poly_low_ {0}
|
||||
, amp_poly_high_ {6000}
|
||||
, button_box_ {QDialogButtonBox::Discard | QDialogButtonBox::Apply
|
||||
| QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Close
|
||||
, Qt::Vertical}
|
||||
{
|
||||
setWindowTitle (windowTitle () + ' ' + tr (title));
|
||||
resize (500, 600);
|
||||
{
|
||||
SettingsGroup g {settings_, title};
|
||||
restoreGeometry (settings_->value ("geometry", saveGeometry ()).toByteArray ());
|
||||
}
|
||||
|
||||
auto legend_title = new QCPTextElement {&plot_, tr ("Phase"), QFont {"sans", 9, QFont::Bold}};
|
||||
legend_title->setLayer (plot_.legend->layer ());
|
||||
plot_.legend->addElement (0, 0, legend_title);
|
||||
plot_.legend->setVisible (true);
|
||||
|
||||
plot_.xAxis->setLabel (tr ("Freq (Hz)"));
|
||||
plot_.xAxis->setRange (500, 2500);
|
||||
plot_.yAxis->setLabel (tr ("Phase (Π)"));
|
||||
plot_.yAxis->setRange (-1, +1);
|
||||
plot_.yAxis2->setLabel (tr ("Delay (ms)"));
|
||||
plot_.axisRect ()->setRangeDrag (Qt::Vertical);
|
||||
plot_.axisRect ()->setRangeZoom (Qt::Vertical);
|
||||
plot_.yAxis2->setVisible (true);
|
||||
plot_.axisRect ()->setRangeDragAxes (nullptr, plot_.yAxis2);
|
||||
plot_.axisRect ()->setRangeZoomAxes (nullptr, plot_.yAxis2);
|
||||
plot_.axisRect ()->insetLayout ()->setInsetAlignment (0, Qt::AlignBottom|Qt::AlignRight);
|
||||
plot_.setInteractions (QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
|
||||
|
||||
plot_.addGraph ()->setName (tr ("Measured"));
|
||||
plot_.graph ()->setPen (QPen {Qt::blue});
|
||||
plot_.graph ()->setVisible (false);
|
||||
plot_.graph ()->removeFromLegend ();
|
||||
|
||||
plot_.addGraph ()->setName (tr ("Proposed"));
|
||||
plot_.graph ()->setPen (QPen {Qt::red});
|
||||
plot_.graph ()->setVisible (false);
|
||||
plot_.graph ()->removeFromLegend ();
|
||||
|
||||
plot_.addGraph ()->setName (tr ("Current"));
|
||||
plot_.graph ()->setPen (QPen {Qt::green});
|
||||
|
||||
plot_.addGraph (plot_.xAxis, plot_.yAxis2)->setName (tr ("Group Delay"));
|
||||
plot_.graph ()->setPen (QPen {Qt::darkGreen});
|
||||
|
||||
plot_.plotLayout ()->addElement (new QCPAxisRect {&plot_});
|
||||
plot_.plotLayout ()->setRowStretchFactor (1, 0.5);
|
||||
|
||||
auto amp_legend = new QCPLegend;
|
||||
plot_.axisRect (1)->insetLayout ()->addElement (amp_legend, Qt::AlignTop | Qt::AlignRight);
|
||||
plot_.axisRect (1)->insetLayout ()->setMargins (QMargins {12, 12, 12, 12});
|
||||
amp_legend->setVisible (true);
|
||||
amp_legend->setLayer (QLatin1String {"legend"});
|
||||
legend_title = new QCPTextElement {&plot_, tr ("Amplitude"), QFont {"sans", 9, QFont::Bold}};
|
||||
legend_title->setLayer (amp_legend->layer ());
|
||||
amp_legend->addElement (0, 0, legend_title);
|
||||
|
||||
plot_.axisRect (1)->axis (QCPAxis::atBottom)->setLabel (tr ("Freq (Hz)"));
|
||||
plot_.axisRect (1)->axis (QCPAxis::atBottom)->setRange (0, 6000);
|
||||
plot_.axisRect (1)->axis (QCPAxis::atLeft)->setLabel (tr ("Relative Power (dB)"));
|
||||
plot_.axisRect (1)->axis (QCPAxis::atLeft)->setRangeLower (0);
|
||||
plot_.axisRect (1)->setRangeDragAxes (nullptr, nullptr);
|
||||
plot_.axisRect (1)->setRangeZoomAxes (nullptr, nullptr);
|
||||
|
||||
plot_.addGraph (plot_.axisRect (1)->axis (QCPAxis::atBottom)
|
||||
, plot_.axisRect (1)->axis (QCPAxis::atLeft))->setName (tr ("Reference"));
|
||||
plot_.graph ()->setPen (QPen {Qt::blue});
|
||||
plot_.graph ()->removeFromLegend ();
|
||||
plot_.graph ()->addToLegend (amp_legend);
|
||||
|
||||
layout_.addWidget (&plot_);
|
||||
|
||||
auto load_phase_button = button_box_.addButton (tr ("Phase ..."), QDialogButtonBox::ActionRole);
|
||||
auto refresh_button = button_box_.addButton (tr ("Refresh"), QDialogButtonBox::ActionRole);
|
||||
layout_.addWidget (&button_box_);
|
||||
setLayout (&layout_);
|
||||
|
||||
connect (&button_box_, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect (&button_box_, &QDialogButtonBox::clicked, [=] (QAbstractButton * button) {
|
||||
if (button == load_phase_button)
|
||||
{
|
||||
plot_phase ();
|
||||
}
|
||||
else if (button == refresh_button)
|
||||
{
|
||||
plot_current ();
|
||||
}
|
||||
else if (button == button_box_.button (QDialogButtonBox::Apply))
|
||||
{
|
||||
if (plot_.graph (0)->dataCount ()) // something loaded
|
||||
{
|
||||
current_coefficients_ = new_coefficients_;
|
||||
Q_EMIT self_->phase_equalization_changed (current_coefficients_);
|
||||
plot_current ();
|
||||
}
|
||||
}
|
||||
else if (button == button_box_.button (QDialogButtonBox::RestoreDefaults))
|
||||
{
|
||||
current_coefficients_ = QVector<double> {0., 0., 0., 0., 0.};
|
||||
Q_EMIT self_->phase_equalization_changed (current_coefficients_);
|
||||
plot_current ();
|
||||
}
|
||||
else if (button == button_box_.button (QDialogButtonBox::Discard))
|
||||
{
|
||||
new_coefficients_ = QVector<double> {0., 0., 0., 0., 0.};
|
||||
|
||||
plot_.graph (0)->data ()->clear ();
|
||||
plot_.graph (0)->setVisible (false);
|
||||
plot_.graph (0)->removeFromLegend ();
|
||||
|
||||
plot_.graph (1)->data ()->clear ();
|
||||
plot_.graph (1)->setVisible (false);
|
||||
plot_.graph (1)->removeFromLegend ();
|
||||
|
||||
plot_.replot ();
|
||||
}
|
||||
});
|
||||
|
||||
plot_current ();
|
||||
}
|
||||
|
||||
struct PowerSpectrumPoint
|
||||
{
|
||||
operator QCPGraphData () const
|
||||
{
|
||||
return QCPGraphData {freq_, power_};
|
||||
}
|
||||
|
||||
float freq_;
|
||||
float power_;
|
||||
};
|
||||
|
||||
// read an amplitude point line from a stream (refspec.dat)
|
||||
std::istream& operator >> (std::istream& is, PowerSpectrumPoint& r)
|
||||
{
|
||||
float y1, y3, y4; // discard these
|
||||
is >> r.freq_ >> y1 >> r.power_ >> y3 >> y4;
|
||||
return is;
|
||||
}
|
||||
|
||||
void PhaseEqualizationDialog::impl::plot_current ()
|
||||
{
|
||||
auto phase_graph = make_plot_data_loader (&plot_, 2, wrap_pi);
|
||||
plot_.graph (2)->data ()->clear ();
|
||||
std::generate_n (std::back_inserter (phase_graph), intervals + 1
|
||||
, make_graph_generator (make_polynomial (current_coefficients_), freq_scaling, pi_scaling));
|
||||
|
||||
auto group_delay_graph = make_plot_data_loader (&plot_, 3, adjust_identity);
|
||||
plot_.graph (3)->data ()->clear ();
|
||||
std::generate_n (std::back_inserter (group_delay_graph), intervals + 1
|
||||
, make_graph_generator (make_group_delay (current_coefficients_), freq_scaling, identity<double>));
|
||||
plot_.graph (3)->rescaleValueAxis ();
|
||||
|
||||
QFileInfo refspec_file_info {data_directory_.absoluteFilePath ("refspec.dat")};
|
||||
std::ifstream refspec_file (refspec_file_info.absoluteFilePath ().toLatin1 ().constData (), std::ifstream::in);
|
||||
unsigned n;
|
||||
if (refspec_file >> amp_poly_low_ >> amp_poly_high_ >> n)
|
||||
{
|
||||
std::istream_iterator<double> isi {refspec_file};
|
||||
amp_coefficients_.clear ();
|
||||
std::copy_n (isi, n, std::back_inserter (amp_coefficients_));
|
||||
}
|
||||
else
|
||||
{
|
||||
// may be old format refspec.dat with no header so rewind
|
||||
refspec_file.clear ();
|
||||
refspec_file.seekg (0);
|
||||
}
|
||||
|
||||
auto reference_spectrum_graph = make_plot_data_loader (&plot_, 4, adjust_identity);
|
||||
plot_.graph (4)->data ()->clear ();
|
||||
std::copy (std::istream_iterator<PowerSpectrumPoint> {refspec_file},
|
||||
std::istream_iterator<PowerSpectrumPoint> {},
|
||||
std::back_inserter (reference_spectrum_graph));
|
||||
plot_.graph (4)->rescaleValueAxis (true);
|
||||
|
||||
plot_.replot ();
|
||||
}
|
||||
|
||||
struct PhasePoint
|
||||
{
|
||||
operator QCPGraphData () const
|
||||
{
|
||||
return QCPGraphData {freq_, phase_};
|
||||
}
|
||||
|
||||
double freq_;
|
||||
double phase_;
|
||||
};
|
||||
|
||||
// read a phase point line from a stream (pcoeff file)
|
||||
std::istream& operator >> (std::istream& is, PhasePoint& c)
|
||||
{
|
||||
double pp, sigmay; // discard these
|
||||
if (is >> c.freq_ >> pp >> c.phase_ >> sigmay)
|
||||
{
|
||||
c.freq_ = 1500. + 1000. * c.freq_; // scale frequency to Hz
|
||||
c.phase_ /= PI; // scale to units of Pi
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
void PhaseEqualizationDialog::impl::plot_phase ()
|
||||
{
|
||||
auto const& phase_file_name = QFileDialog::getOpenFileName (this
|
||||
, "Select Phase Response Coefficients"
|
||||
, data_directory_.absolutePath ()
|
||||
, "Phase Coefficient Files (*.pcoeff)");
|
||||
if (!phase_file_name.size ()) return;
|
||||
|
||||
std::ifstream phase_file (phase_file_name.toLatin1 ().constData (), std::ifstream::in);
|
||||
int n;
|
||||
float chi;
|
||||
float rmsdiff;
|
||||
unsigned freq_low;
|
||||
unsigned freq_high;
|
||||
unsigned terms;
|
||||
// read header information
|
||||
if (phase_file >> n >> chi >> rmsdiff >> freq_low >> freq_high >> terms)
|
||||
{
|
||||
std::istream_iterator<double> isi {phase_file};
|
||||
new_coefficients_.clear ();
|
||||
std::copy_n (isi, terms, std::back_inserter (new_coefficients_));
|
||||
|
||||
if (phase_file)
|
||||
{
|
||||
plot_.graph (0)->data ()->clear ();
|
||||
plot_.graph (1)->data ()->clear ();
|
||||
|
||||
// read the phase data and plot as graph 0
|
||||
auto graph = make_plot_data_loader (&plot_, 0, adjust_identity);
|
||||
std::copy_n (std::istream_iterator<PhasePoint> {phase_file},
|
||||
intervals + 1, std::back_inserter (graph));
|
||||
|
||||
if (phase_file)
|
||||
{
|
||||
plot_.graph(0)->setLineStyle(QCPGraph::lsNone);
|
||||
plot_.graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 4));
|
||||
plot_.graph (0)->setVisible (true);
|
||||
plot_.graph (0)->addToLegend ();
|
||||
|
||||
// generate the proposed polynomial plot as graph 1
|
||||
auto graph = make_plot_data_loader (&plot_, 1, wrap_pi);
|
||||
std::generate_n (std::back_inserter (graph), intervals + 1
|
||||
, make_graph_generator (make_polynomial (new_coefficients_)
|
||||
, freq_scaling, pi_scaling));
|
||||
plot_.graph (1)->setVisible (true);
|
||||
plot_.graph (1)->addToLegend ();
|
||||
}
|
||||
|
||||
plot_.replot ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_PhaseEqualizationDialog.cpp"
|
||||
@@ -1,181 +0,0 @@
|
||||
// -*- Mode: C++ -*-
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Some code in this file and accompanying files is based on work by
|
||||
// Moe Wheatley, AE4Y, released under the "Simplified BSD License".
|
||||
// For more details see the accompanying file LICENSE_WHEATLEY.TXT
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PLOTTER_H
|
||||
#define PLOTTER_H
|
||||
|
||||
#ifdef QT5
|
||||
#include <QtWidgets>
|
||||
#else
|
||||
#include <QtGui>
|
||||
#endif
|
||||
#include <QFrame>
|
||||
#include <QImage>
|
||||
#include <QVector>
|
||||
#include <cstring>
|
||||
|
||||
#define VERT_DIVS 7 //specify grid screen divisions
|
||||
#define HORZ_DIVS 20
|
||||
|
||||
extern bool g_single_decode;
|
||||
|
||||
class CPlotter : public QFrame
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
explicit CPlotter(QWidget *parent = 0);
|
||||
~CPlotter();
|
||||
|
||||
QSize minimumSizeHint() const;
|
||||
QSize sizeHint() const;
|
||||
bool m_bScaleOK;
|
||||
|
||||
void draw(float swide[], bool bScroll, bool bRed); //Update the waterfall
|
||||
void SetRunningState(bool running);
|
||||
void setPlotZero(int plotZero);
|
||||
int plotZero();
|
||||
void setPlotGain(int plotGain);
|
||||
int plotGain();
|
||||
int plot2dGain();
|
||||
void setPlot2dGain(int n);
|
||||
int plot2dZero();
|
||||
void setPlot2dZero(int plot2dZero);
|
||||
void setStartFreq(int f);
|
||||
int startFreq();
|
||||
int plotWidth();
|
||||
void UpdateOverlay();
|
||||
void setDataFromDisk(bool b);
|
||||
void setRxRange(int fMin);
|
||||
void setBinsPerPixel(int n);
|
||||
int binsPerPixel();
|
||||
void setWaterfallAvg(int n);
|
||||
void setRxFreq(int n);
|
||||
void DrawOverlay();
|
||||
int rxFreq();
|
||||
void setFsample(int n);
|
||||
void setNsps(int ntrperiod, int nsps);
|
||||
void setTxFreq(int n);
|
||||
void setMode(QString mode);
|
||||
void setSubMode(int n);
|
||||
void setModeTx(QString modeTx);
|
||||
void SetPercent2DScreen(int percent);
|
||||
int Fmax();
|
||||
void setDialFreq(double d);
|
||||
void setCurrent(bool b) {m_bCurrent = b;}
|
||||
bool current() const {return m_bCurrent;}
|
||||
void setCumulative(bool b) {m_bCumulative = b;}
|
||||
bool cumulative() const {return m_bCumulative;}
|
||||
void setLinearAvg(bool b) {m_bLinearAvg = b;}
|
||||
bool linearAvg() const {return m_bLinearAvg;}
|
||||
void setBreadth(qint32 w) {m_w = w;}
|
||||
qint32 breadth() const {return m_w;}
|
||||
float fSpan() const {return m_fSpan;}
|
||||
void setColours(QVector<QColor> const& cl);
|
||||
void setFlatten(bool b1, bool b2);
|
||||
void setTol(int n);
|
||||
void setRxBand(QString band);
|
||||
void setReference(bool b) {m_bReference = b;}
|
||||
bool Reference() const {return m_bReference;}
|
||||
void drawRed(int ia, int ib, float swide[]);
|
||||
void setVHF(bool bVHF);
|
||||
void setRedFile(QString fRed);
|
||||
|
||||
signals:
|
||||
void freezeDecode1(int n);
|
||||
void setFreq1(int rxFreq, int txFreq);
|
||||
|
||||
protected:
|
||||
//re-implemented widget event handlers
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
void MakeFrequencyStrs();
|
||||
int XfromFreq(float f);
|
||||
float FreqfromX(int x);
|
||||
|
||||
bool m_bCurrent;
|
||||
bool m_bCumulative;
|
||||
bool m_bLinearAvg;
|
||||
bool m_bReference;
|
||||
bool m_bReference0;
|
||||
bool m_bVHF;
|
||||
|
||||
float m_fSpan;
|
||||
|
||||
qint32 m_plotZero;
|
||||
qint32 m_plotGain;
|
||||
qint32 m_plot2dGain;
|
||||
qint32 m_plot2dZero;
|
||||
qint32 m_binsPerPixel;
|
||||
qint32 m_waterfallAvg;
|
||||
qint32 m_w;
|
||||
qint32 m_Flatten;
|
||||
qint32 m_nSubMode;
|
||||
qint32 m_ia;
|
||||
qint32 m_ib;
|
||||
|
||||
QPixmap m_WaterfallPixmap;
|
||||
QPixmap m_2DPixmap;
|
||||
QPixmap m_ScalePixmap;
|
||||
QPixmap m_OverlayPixmap;
|
||||
|
||||
QSize m_Size;
|
||||
QString m_Str;
|
||||
QString m_HDivText[483];
|
||||
QString m_mode;
|
||||
QString m_modeTx;
|
||||
QString m_rxBand;
|
||||
QString m_redFile;
|
||||
|
||||
bool m_Running;
|
||||
bool m_paintEventBusy;
|
||||
bool m_dataFromDisk;
|
||||
|
||||
double m_fftBinWidth;
|
||||
double m_dialFreq;
|
||||
double m_xOffset;
|
||||
|
||||
float m_sum[2048];
|
||||
|
||||
qint32 m_dBStepSize;
|
||||
qint32 m_FreqUnits;
|
||||
qint32 m_hdivs;
|
||||
qint32 m_line;
|
||||
qint32 m_fSample;
|
||||
qint32 m_xClick;
|
||||
qint32 m_freqPerDiv;
|
||||
qint32 m_nsps;
|
||||
qint32 m_Percent2DScreen;
|
||||
qint32 m_Percent2DScreen0;
|
||||
qint32 m_h;
|
||||
qint32 m_h1;
|
||||
qint32 m_h2;
|
||||
qint32 m_TRperiod;
|
||||
qint32 m_rxFreq;
|
||||
qint32 m_txFreq;
|
||||
qint32 m_fMin;
|
||||
qint32 m_fMax;
|
||||
qint32 m_startFreq;
|
||||
qint32 m_tol;
|
||||
|
||||
char m_sutc[6];
|
||||
|
||||
private slots:
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
};
|
||||
|
||||
extern QVector<QColor> g_ColorTbl;
|
||||
|
||||
extern "C" {
|
||||
void flat4_(float swide[], int* iz, int* nflatten);
|
||||
}
|
||||
|
||||
#endif // PLOTTER_H
|
||||
@@ -1,278 +0,0 @@
|
||||
#include "astro.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QSettings>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "commons.h"
|
||||
#include "MessageBox.hpp"
|
||||
#include "Configuration.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
#include "ui_astro.h"
|
||||
#include "moc_astro.cpp"
|
||||
|
||||
|
||||
extern "C" {
|
||||
void astrosub_(int* nyear, int* month, int* nday, double* uth, double* freqMoon,
|
||||
const char* mygrid, const char* hisgrid, double* azsun,
|
||||
double* elsun, double* azmoon, double* elmoon, double* azmoondx,
|
||||
double* elmoondx, int* ntsky, int* ndop, int* ndop00,
|
||||
double* ramoon, double* decmoon, double* dgrd, double* poloffset,
|
||||
double* xnr, double* techo, double* width1, double* width2,
|
||||
bool* bTx, const char* AzElFileName, const char* jpleph,
|
||||
int len1, int len2, int len3, int len4);
|
||||
}
|
||||
|
||||
Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent)
|
||||
: QDialog {parent, Qt::WindowTitleHint}
|
||||
, settings_ {settings}
|
||||
, configuration_ {configuration}
|
||||
, ui_ {new Ui::Astro}
|
||||
, m_DopplerMethod {0}
|
||||
{
|
||||
ui_->setupUi (this);
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Astronomical Data"));
|
||||
setStyleSheet ("QWidget {background: white;}");
|
||||
connect (ui_->cbDopplerTracking, &QAbstractButton::toggled, ui_->doppler_widget, &QWidget::setVisible);
|
||||
read_settings ();
|
||||
ui_->text_label->clear ();
|
||||
}
|
||||
|
||||
Astro::~Astro ()
|
||||
{
|
||||
ui_->cbDopplerTracking->setChecked (false);
|
||||
Q_EMIT tracking_update ();
|
||||
if (isVisible ()) write_settings ();
|
||||
}
|
||||
|
||||
void Astro::closeEvent (QCloseEvent * e)
|
||||
{
|
||||
write_settings ();
|
||||
QWidget::closeEvent (e);
|
||||
}
|
||||
|
||||
void Astro::read_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
ui_->doppler_widget->setVisible (ui_->cbDopplerTracking->isChecked ());
|
||||
m_DopplerMethod=settings_->value("DopplerMethod",0).toInt();
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 0: ui_->rbNoDoppler->setChecked (true); break;
|
||||
case 1: ui_->rbFullTrack->setChecked (true); break;
|
||||
case 2: ui_->rbConstFreqOnMoon->setChecked (true); break;
|
||||
case 3: ui_->rbRxOnly->setChecked (true); break;
|
||||
}
|
||||
move (settings_->value ("window/pos", pos ()).toPoint ());
|
||||
}
|
||||
|
||||
void Astro::write_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
//settings_->setValue ("DopplerTracking", ui_->cbDopplerTracking->isChecked ());
|
||||
settings_->setValue ("DopplerMethod",m_DopplerMethod);
|
||||
settings_->setValue ("window/pos", pos ());
|
||||
}
|
||||
|
||||
auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq,
|
||||
bool dx_is_self, bool bTx, bool no_tx_QSY, int TR_period) -> Correction
|
||||
{
|
||||
Frequency freq_moon {freq};
|
||||
double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx;
|
||||
double ramoon,decmoon,dgrd,poloffset,xnr,techo,width1,width2;
|
||||
int ntsky;
|
||||
QString date {t.date().toString("yyyy MMM dd").trimmed ()};
|
||||
QString utc {t.time().toString().trimmed ()};
|
||||
int nyear {t.date().year()};
|
||||
int month {t.date().month()};
|
||||
int nday {t.date().day()};
|
||||
int nhr {t.time().hour()};
|
||||
int nmin {t.time().minute()};
|
||||
double sec {t.time().second() + 0.001*t.time().msec()};
|
||||
double uth {nhr + nmin/60.0 + sec/3600.0};
|
||||
if(freq_moon < 1) freq_moon = 144000000;
|
||||
int nfreq {static_cast<int> (freq_moon / 1000000u)};
|
||||
double freq8 {static_cast<double> (freq_moon)};
|
||||
auto const& AzElFileName = QDir::toNativeSeparators (configuration_->azel_directory ().absoluteFilePath ("azel.dat"));
|
||||
auto const& jpleph = configuration_->data_dir ().absoluteFilePath ("JPLEPH");
|
||||
int ndop;
|
||||
int ndop00;
|
||||
|
||||
QString mygrid_padded {(mygrid + " ").left (6)};
|
||||
QString hisgrid_padded {(hisgrid + " ").left (6)};
|
||||
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(),
|
||||
hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
AzElFileName.toLatin1().constData(), jpleph.toLatin1().constData(), 6, 6,
|
||||
AzElFileName.length(), jpleph.length());
|
||||
|
||||
if(hisgrid_padded==" ") {
|
||||
azmoondx=0.0;
|
||||
elmoondx=0.0;
|
||||
ndop=0;
|
||||
width2=0.0;
|
||||
}
|
||||
QString message;
|
||||
{
|
||||
QTextStream out {&message};
|
||||
out << " " << date << "\n"
|
||||
"UTC: " << utc << "\n"
|
||||
<< fixed
|
||||
<< qSetFieldWidth (6)
|
||||
<< qSetRealNumberPrecision (1)
|
||||
<< "Az: " << azmoon << "\n"
|
||||
"El: " << elmoon << "\n"
|
||||
"SelfDop:" << ndop00 << "\n"
|
||||
"Width: " << int(width1) << "\n"
|
||||
<< qSetRealNumberPrecision (2)
|
||||
<< "Delay: " << techo << "\n"
|
||||
<< qSetRealNumberPrecision (1)
|
||||
<< "DxAz: " << azmoondx << "\n"
|
||||
"DxEl: " << elmoondx << "\n"
|
||||
"DxDop: " << ndop << "\n"
|
||||
"DxWid: " << int(width2) << "\n"
|
||||
"Dec: " << decmoon << "\n"
|
||||
"SunAz: " << azsun << "\n"
|
||||
"SunEl: " << elsun << "\n"
|
||||
"Freq: " << nfreq << "\n";
|
||||
if(nfreq>=50) { //Suppress data not relevant below VHF
|
||||
out << "Tsky: " << ntsky << "\n"
|
||||
"Dpol: " << poloffset << "\n"
|
||||
"MNR: " << xnr << "\n"
|
||||
"Dgrd: " << dgrd;
|
||||
}
|
||||
}
|
||||
ui_->text_label->setText(message);
|
||||
|
||||
Correction correction;
|
||||
if (ui_->cbDopplerTracking->isChecked ()) {
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1: // All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
case 3: // Both stations do full correction on Rx and none on Tx
|
||||
correction.rx = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
correction.rx = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (3 != m_DopplerMethod) correction.tx = -correction.rx;
|
||||
if(dx_is_self && m_DopplerMethod == 1) correction.rx = 0;
|
||||
|
||||
if (no_tx_QSY && 3 != m_DopplerMethod && 0 != m_DopplerMethod)
|
||||
{
|
||||
// calculate a single correction for transmit half way through
|
||||
// the period as a compromise for rigs that can't CAT QSY
|
||||
// while transmitting
|
||||
//
|
||||
// use a base time of (secs-since-epoch + 2) so as to be sure
|
||||
// we do the next period if we calculate just before it starts
|
||||
auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2;
|
||||
auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2;
|
||||
auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000);
|
||||
QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()};
|
||||
QString utc {target_date_time.time().toString().trimmed ()};
|
||||
int nyear {target_date_time.date().year()};
|
||||
int month {target_date_time.date().month()};
|
||||
int nday {target_date_time.date().day()};
|
||||
int nhr {target_date_time.time().hour()};
|
||||
int nmin {target_date_time.time().minute()};
|
||||
double sec {target_date_time.time().second() + 0.001*target_date_time.time().msec()};
|
||||
double uth {nhr + nmin/60.0 + sec/3600.0};
|
||||
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(),
|
||||
hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
"", jpleph.toLatin1().constData(), 6, 6,
|
||||
0, jpleph.length());
|
||||
FrequencyDelta offset {0};
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1:
|
||||
// All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
offset = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
offset = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
correction.tx = -offset;
|
||||
}
|
||||
}
|
||||
return correction;
|
||||
}
|
||||
|
||||
void Astro::check_split ()
|
||||
{
|
||||
if (doppler_tracking () && !configuration_->split_mode ())
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Doppler Tracking Error"),
|
||||
tr ("Split operating is required for Doppler tracking"),
|
||||
tr ("Go to \"Menu->File->Settings->Radio\" to enable split operation"));
|
||||
ui_->rbNoDoppler->click ();
|
||||
}
|
||||
}
|
||||
|
||||
void Astro::on_rbFullTrack_clicked()
|
||||
{
|
||||
m_DopplerMethod = 1;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbRxOnly_clicked()
|
||||
{
|
||||
m_DopplerMethod = 3;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbConstFreqOnMoon_clicked()
|
||||
{
|
||||
m_DopplerMethod = 2;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbNoDoppler_clicked()
|
||||
{
|
||||
m_DopplerMethod = 0;
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
bool Astro::doppler_tracking () const
|
||||
{
|
||||
return ui_->cbDopplerTracking->isChecked () && m_DopplerMethod;
|
||||
}
|
||||
|
||||
void Astro::on_cbDopplerTracking_toggled(bool)
|
||||
{
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::nominal_frequency (Frequency rx, Frequency tx)
|
||||
{
|
||||
ui_->sked_frequency_label->setText (Radio::pretty_frequency_MHz_string (rx));
|
||||
ui_->sked_tx_frequency_label->setText (Radio::pretty_frequency_MHz_string (tx));
|
||||
}
|
||||
|
||||
void Astro::hideEvent (QHideEvent * e)
|
||||
{
|
||||
Q_EMIT tracking_update ();
|
||||
QWidget::hideEvent (e);
|
||||
}
|
||||
Reference in New Issue
Block a user