mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-25 21:58:38 -05:00
Add reference spectrum to equalization plots and more plotting enhancements
Use a header format for polynomial coefficients that includes the valid X range in scaled terms and a count of the number of coefficients. Use double precision consistently for polynomial coefficients. This includes formatting with sufficient DPs when writing to files. Many changes to the equalization plots, more to come. Add error handling for reading coefficient, plot and filter files. This includes being backward compatible for old format refspec.dat files with no header. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7578 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
0215ed58c1
commit
2131414791
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QVBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
@ -63,8 +63,8 @@ namespace
|
|||||||
{
|
{
|
||||||
return plot_data_loader<QCPGraphData, decltype (adjust)> {plot, index, adjust};
|
return plot_data_loader<QCPGraphData, decltype (adjust)> {plot, index, adjust};
|
||||||
}
|
}
|
||||||
// identity adjust function when none is needed in the above
|
// identity adjust function when no adjustment is needed with the
|
||||||
// instantiation helper
|
// above instantiation helper
|
||||||
QCPGraphData adjust_identity (QCustomPlot *, int, QCPGraphData const& v) {return v;}
|
QCPGraphData adjust_identity (QCustomPlot *, int, QCPGraphData const& v) {return v;}
|
||||||
|
|
||||||
// a plot_data_loader adjustment function that wraps Y values of
|
// a plot_data_loader adjustment function that wraps Y values of
|
||||||
@ -219,16 +219,6 @@ namespace
|
|||||||
auto pi_scaling = [] (float v) -> float {return v / PI;};
|
auto pi_scaling = [] (float v) -> float {return v / PI;};
|
||||||
}
|
}
|
||||||
|
|
||||||
// read a phase point line from a stream (pcoeff file)
|
|
||||||
std::istream& operator >> (std::istream& is, QCPGraphData& v)
|
|
||||||
{
|
|
||||||
float pp, sigmay; // discard these
|
|
||||||
is >> v.key >> pp >> v.value >> sigmay;
|
|
||||||
v.key = 1500. + 1000. * v.key; // scale frequency to Hz
|
|
||||||
v.value /= PI; // scale to units of Pi
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhaseEqualizationDialog::impl final
|
class PhaseEqualizationDialog::impl final
|
||||||
: public QDialog
|
: public QDialog
|
||||||
{
|
{
|
||||||
@ -236,7 +226,7 @@ class PhaseEqualizationDialog::impl final
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit impl (PhaseEqualizationDialog * self, QSettings * settings
|
explicit impl (PhaseEqualizationDialog * self, QSettings * settings
|
||||||
, QDir const& data_directory, QVector<float> const& coefficients
|
, QDir const& data_directory, QVector<double> const& coefficients
|
||||||
, QWidget * parent);
|
, QWidget * parent);
|
||||||
~impl () {save_window_state ();}
|
~impl () {save_window_state ();}
|
||||||
|
|
||||||
@ -255,14 +245,18 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void plot_current ();
|
void plot_current ();
|
||||||
void plot ();
|
void plot_phase ();
|
||||||
|
void plot_amplitude ();
|
||||||
|
|
||||||
PhaseEqualizationDialog * self_;
|
PhaseEqualizationDialog * self_;
|
||||||
QSettings * settings_;
|
QSettings * settings_;
|
||||||
QDir data_directory_;
|
QDir data_directory_;
|
||||||
QVBoxLayout layout_;
|
QHBoxLayout layout_;
|
||||||
QVector<float> current_coefficients_;
|
QVector<double> current_coefficients_;
|
||||||
QVector<float> new_coefficients_;
|
QVector<double> new_coefficients_;
|
||||||
|
unsigned amp_poly_low_;
|
||||||
|
unsigned amp_poly_high_;
|
||||||
|
QVector<double> amp_coefficients_;
|
||||||
QCustomPlot plot_;
|
QCustomPlot plot_;
|
||||||
QDialogButtonBox button_box_;
|
QDialogButtonBox button_box_;
|
||||||
};
|
};
|
||||||
@ -271,7 +265,7 @@ private:
|
|||||||
|
|
||||||
PhaseEqualizationDialog::PhaseEqualizationDialog (QSettings * settings
|
PhaseEqualizationDialog::PhaseEqualizationDialog (QSettings * settings
|
||||||
, QDir const& data_directory
|
, QDir const& data_directory
|
||||||
, QVector<float> const& coefficients
|
, QVector<double> const& coefficients
|
||||||
, QWidget * parent)
|
, QWidget * parent)
|
||||||
: m_ {this, settings, data_directory, coefficients, parent}
|
: m_ {this, settings, data_directory, coefficients, parent}
|
||||||
{
|
{
|
||||||
@ -285,15 +279,18 @@ void PhaseEqualizationDialog::show ()
|
|||||||
PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
||||||
, QSettings * settings
|
, QSettings * settings
|
||||||
, QDir const& data_directory
|
, QDir const& data_directory
|
||||||
, QVector<float> const& coefficients
|
, QVector<double> const& coefficients
|
||||||
, QWidget * parent)
|
, QWidget * parent)
|
||||||
: QDialog {parent}
|
: QDialog {parent}
|
||||||
, self_ {self}
|
, self_ {self}
|
||||||
, settings_ {settings}
|
, settings_ {settings}
|
||||||
, data_directory_ {data_directory}
|
, data_directory_ {data_directory}
|
||||||
, current_coefficients_ {coefficients}
|
, current_coefficients_ {coefficients}
|
||||||
|
, amp_poly_low_ {0}
|
||||||
|
, amp_poly_high_ {6000}
|
||||||
, button_box_ {QDialogButtonBox::Discard | QDialogButtonBox::Apply
|
, button_box_ {QDialogButtonBox::Discard | QDialogButtonBox::Apply
|
||||||
| QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Close}
|
| QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Close
|
||||||
|
, Qt::Vertical}
|
||||||
{
|
{
|
||||||
setWindowTitle (windowTitle () + ' ' + tr (title));
|
setWindowTitle (windowTitle () + ' ' + tr (title));
|
||||||
resize (500, 600);
|
resize (500, 600);
|
||||||
@ -301,7 +298,11 @@ PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
|||||||
SettingsGroup g {settings_, title};
|
SettingsGroup g {settings_, title};
|
||||||
restoreGeometry (settings_->value ("geometry", saveGeometry ()).toByteArray ());
|
restoreGeometry (settings_->value ("geometry", saveGeometry ()).toByteArray ());
|
||||||
}
|
}
|
||||||
layout_.addWidget (&plot_);
|
|
||||||
|
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->setLabel (tr ("Freq (Hz)"));
|
||||||
plot_.xAxis->setRange (500, 2500);
|
plot_.xAxis->setRange (500, 2500);
|
||||||
@ -311,41 +312,68 @@ PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
|||||||
plot_.axisRect ()->setRangeDrag (Qt::Vertical);
|
plot_.axisRect ()->setRangeDrag (Qt::Vertical);
|
||||||
plot_.axisRect ()->setRangeZoom (Qt::Vertical);
|
plot_.axisRect ()->setRangeZoom (Qt::Vertical);
|
||||||
plot_.yAxis2->setVisible (true);
|
plot_.yAxis2->setVisible (true);
|
||||||
plot_.axisRect ()->setRangeDragAxes (0, plot_.yAxis2);
|
plot_.axisRect ()->setRangeDragAxes (nullptr, plot_.yAxis2);
|
||||||
plot_.axisRect ()->setRangeZoomAxes (0, plot_.yAxis2);
|
plot_.axisRect ()->setRangeZoomAxes (nullptr, plot_.yAxis2);
|
||||||
plot_.axisRect ()->insetLayout ()->setInsetAlignment (0, Qt::AlignBottom|Qt::AlignRight);
|
plot_.axisRect ()->insetLayout ()->setInsetAlignment (0, Qt::AlignBottom|Qt::AlignRight);
|
||||||
plot_.legend->setVisible (true);
|
|
||||||
plot_.setInteractions (QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
|
plot_.setInteractions (QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
|
||||||
|
|
||||||
plot_.addGraph ();
|
plot_.addGraph ()->setName (tr ("Measured"));
|
||||||
plot_.graph ()->setName (tr ("Measured"));
|
|
||||||
plot_.graph ()->setPen (QPen {Qt::blue});
|
plot_.graph ()->setPen (QPen {Qt::blue});
|
||||||
plot_.graph ()->setVisible (false);
|
plot_.graph ()->setVisible (false);
|
||||||
plot_.graph ()->removeFromLegend ();
|
plot_.graph ()->removeFromLegend ();
|
||||||
|
|
||||||
plot_.addGraph ();
|
plot_.addGraph ()->setName (tr ("Proposed"));
|
||||||
plot_.graph ()->setName (tr ("Proposed"));
|
|
||||||
plot_.graph ()->setPen (QPen {Qt::red});
|
plot_.graph ()->setPen (QPen {Qt::red});
|
||||||
plot_.graph ()->setVisible (false);
|
plot_.graph ()->setVisible (false);
|
||||||
plot_.graph ()->removeFromLegend ();
|
plot_.graph ()->removeFromLegend ();
|
||||||
|
|
||||||
plot_.addGraph ();
|
plot_.addGraph ()->setName (tr ("Current"));
|
||||||
plot_.graph ()->setName (tr ("Current"));
|
|
||||||
plot_.graph ()->setPen (QPen {Qt::green});
|
plot_.graph ()->setPen (QPen {Qt::green});
|
||||||
|
|
||||||
plot_.addGraph (plot_.xAxis, plot_.yAxis2);
|
plot_.addGraph (plot_.xAxis, plot_.yAxis2)->setName (tr ("Group Delay"));
|
||||||
plot_.graph ()->setName (tr ("Group Delay"));
|
|
||||||
plot_.graph ()->setPen (QPen {Qt::darkGreen});
|
plot_.graph ()->setPen (QPen {Qt::darkGreen});
|
||||||
|
|
||||||
auto load_button = button_box_.addButton (tr ("Load ..."), QDialogButtonBox::ActionRole);
|
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_);
|
layout_.addWidget (&button_box_);
|
||||||
setLayout (&layout_);
|
setLayout (&layout_);
|
||||||
|
|
||||||
connect (&button_box_, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect (&button_box_, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
connect (&button_box_, &QDialogButtonBox::clicked, [this, load_button] (QAbstractButton * button) {
|
connect (&button_box_, &QDialogButtonBox::clicked, [=] (QAbstractButton * button) {
|
||||||
if (button == load_button)
|
if (button == load_phase_button)
|
||||||
{
|
{
|
||||||
plot ();
|
plot_phase ();
|
||||||
|
}
|
||||||
|
else if (button == refresh_button)
|
||||||
|
{
|
||||||
|
plot_current ();
|
||||||
}
|
}
|
||||||
else if (button == button_box_.button (QDialogButtonBox::Apply))
|
else if (button == button_box_.button (QDialogButtonBox::Apply))
|
||||||
{
|
{
|
||||||
@ -358,13 +386,13 @@ PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
|||||||
}
|
}
|
||||||
else if (button == button_box_.button (QDialogButtonBox::RestoreDefaults))
|
else if (button == button_box_.button (QDialogButtonBox::RestoreDefaults))
|
||||||
{
|
{
|
||||||
current_coefficients_ = QVector<float> {0., 0., 0., 0., 0.};
|
current_coefficients_ = QVector<double> {0., 0., 0., 0., 0.};
|
||||||
Q_EMIT self_->phase_equalization_changed (current_coefficients_);
|
Q_EMIT self_->phase_equalization_changed (current_coefficients_);
|
||||||
plot_current ();
|
plot_current ();
|
||||||
}
|
}
|
||||||
else if (button == button_box_.button (QDialogButtonBox::Discard))
|
else if (button == button_box_.button (QDialogButtonBox::Discard))
|
||||||
{
|
{
|
||||||
new_coefficients_ = QVector<float> {0., 0., 0., 0., 0.};
|
new_coefficients_ = QVector<double> {0., 0., 0., 0., 0.};
|
||||||
|
|
||||||
plot_.graph (0)->data ()->clear ();
|
plot_.graph (0)->data ()->clear ();
|
||||||
plot_.graph (0)->setVisible (false);
|
plot_.graph (0)->setVisible (false);
|
||||||
@ -381,68 +409,136 @@ PhaseEqualizationDialog::impl::impl (PhaseEqualizationDialog * self
|
|||||||
plot_current ();
|
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 ()
|
void PhaseEqualizationDialog::impl::plot_current ()
|
||||||
{
|
{
|
||||||
|
auto phase_graph = make_plot_data_loader (&plot_, 2, wrap_pi);
|
||||||
plot_.graph (2)->data ()->clear ();
|
plot_.graph (2)->data ()->clear ();
|
||||||
plot_.graph (3)->data ()->clear ();
|
std::generate_n (std::back_inserter (phase_graph), intervals + 1
|
||||||
{
|
|
||||||
// plot the current polynomial
|
|
||||||
auto graph = make_plot_data_loader (&plot_, 2, wrap_pi);
|
|
||||||
std::generate_n (std::back_inserter (graph), intervals + 1
|
|
||||||
, make_graph_generator (make_polynomial (current_coefficients_), freq_scaling, pi_scaling));
|
, make_graph_generator (make_polynomial (current_coefficients_), freq_scaling, pi_scaling));
|
||||||
}
|
|
||||||
{
|
auto group_delay_graph = make_plot_data_loader (&plot_, 3, adjust_identity);
|
||||||
// plot the group delay for the current polynomial
|
plot_.graph (3)->data ()->clear ();
|
||||||
auto graph = make_plot_data_loader (&plot_, 3, adjust_identity);
|
std::generate_n (std::back_inserter (group_delay_graph), intervals + 1
|
||||||
std::generate_n (std::back_inserter (graph), intervals + 1
|
, make_graph_generator (make_group_delay (current_coefficients_), freq_scaling, identity<double>));
|
||||||
, make_graph_generator (make_group_delay (current_coefficients_), freq_scaling, identity<float>));
|
|
||||||
plot_.graph (3)->rescaleValueAxis ();
|
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 ();
|
plot_.replot ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhaseEqualizationDialog::impl::plot ()
|
struct PhasePoint
|
||||||
{
|
{
|
||||||
auto const& name = QFileDialog::getOpenFileName (this
|
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"
|
, "Select Phase Response Coefficients"
|
||||||
, data_directory_.absolutePath ()
|
, data_directory_.absolutePath ()
|
||||||
, "Phase Coefficient Files (*.pcoeff)");
|
, "Phase Coefficient Files (*.pcoeff)");
|
||||||
if (name.size ())
|
if (!phase_file_name.size ()) return;
|
||||||
{
|
|
||||||
std::ifstream coeffs_source (name.toLatin1 ().constData (), std::ifstream::in);
|
std::ifstream phase_file (phase_file_name.toLatin1 ().constData (), std::ifstream::in);
|
||||||
int n;
|
int n;
|
||||||
float chi;
|
float chi;
|
||||||
float rmsdiff;
|
float rmsdiff;
|
||||||
|
unsigned freq_low;
|
||||||
|
unsigned freq_high;
|
||||||
|
unsigned terms;
|
||||||
// read header information
|
// read header information
|
||||||
coeffs_source >> n >> chi >> rmsdiff;
|
if (phase_file >> n >> chi >> rmsdiff >> freq_low >> freq_high >> terms)
|
||||||
{
|
{
|
||||||
std::istream_iterator<float> isi {coeffs_source};
|
std::istream_iterator<double> isi {phase_file};
|
||||||
new_coefficients_.clear ();
|
new_coefficients_.clear ();
|
||||||
std::copy_n (isi, 5, std::back_inserter (new_coefficients_));
|
std::copy_n (isi, terms, std::back_inserter (new_coefficients_));
|
||||||
}
|
|
||||||
|
|
||||||
|
if (phase_file)
|
||||||
|
{
|
||||||
plot_.graph (0)->data ()->clear ();
|
plot_.graph (0)->data ()->clear ();
|
||||||
plot_.graph (1)->data ()->clear ();
|
plot_.graph (1)->data ()->clear ();
|
||||||
{
|
|
||||||
// read the phase data to plot into graph 0
|
// read the phase data and plot as graph 0
|
||||||
auto graph = make_plot_data_loader (&plot_, 0, adjust_identity);
|
auto graph = make_plot_data_loader (&plot_, 0, adjust_identity);
|
||||||
std::istream_iterator<QCPGraphData> start {coeffs_source};
|
std::copy_n (std::istream_iterator<PhasePoint> {phase_file},
|
||||||
std::copy_n (start, intervals + 1, std::back_inserter (graph));
|
intervals + 1, std::back_inserter (graph));
|
||||||
}
|
|
||||||
|
if (phase_file)
|
||||||
{
|
{
|
||||||
// generate the proposed polynomial plot in 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 (0)->setVisible (true);
|
plot_.graph (0)->setVisible (true);
|
||||||
plot_.graph (0)->addToLegend ();
|
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)->setVisible (true);
|
||||||
plot_.graph (1)->addToLegend ();
|
plot_.graph (1)->addToLegend ();
|
||||||
|
}
|
||||||
|
|
||||||
plot_.replot ();
|
plot_.replot ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_PhaseEqualizationDialog.cpp"
|
#include "moc_PhaseEqualizationDialog.cpp"
|
||||||
|
@ -17,11 +17,11 @@ class PhaseEqualizationDialog
|
|||||||
public:
|
public:
|
||||||
explicit PhaseEqualizationDialog (QSettings *
|
explicit PhaseEqualizationDialog (QSettings *
|
||||||
, QDir const& data_directory
|
, QDir const& data_directory
|
||||||
, QVector<float> const& coefficients
|
, QVector<double> const& coefficients
|
||||||
, QWidget * = nullptr);
|
, QWidget * = nullptr);
|
||||||
Q_SLOT void show ();
|
Q_SLOT void show ();
|
||||||
|
|
||||||
Q_SIGNAL void phase_equalization_changed (QVector<float> const&);
|
Q_SIGNAL void phase_equalization_changed (QVector<double> const&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class impl;
|
class impl;
|
||||||
|
@ -6,9 +6,9 @@ subroutine analytic(d,npts,nfft,c,pc,beq)
|
|||||||
|
|
||||||
real d(npts) ! passband signal
|
real d(npts) ! passband signal
|
||||||
real h(NFFTMAX/2) ! real BPF magnitude
|
real h(NFFTMAX/2) ! real BPF magnitude
|
||||||
real pc(5),pclast(5) ! static phase coeffs
|
real*8 pc(5),pclast(5) ! static phase coeffs
|
||||||
real ac(5),aclast(5) ! amp coeffs
|
real*8 ac(5),aclast(5) ! amp coeffs
|
||||||
real fp
|
real*8 fp
|
||||||
|
|
||||||
complex corr(NFFTMAX/2) ! complex frequency-dependent correction
|
complex corr(NFFTMAX/2) ! complex frequency-dependent correction
|
||||||
complex c(NFFTMAX) ! analytic signal
|
complex c(NFFTMAX) ! analytic signal
|
||||||
|
@ -27,7 +27,7 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144,bcontest, &
|
|||||||
real green(0:JZ-1)
|
real green(0:JZ-1)
|
||||||
real s(0:63,0:JZ-1)
|
real s(0:63,0:JZ-1)
|
||||||
real x(512)
|
real x(512)
|
||||||
real pcoeffs(5)
|
real*8 pcoeffs(5)
|
||||||
complex cx(0:256)
|
complex cx(0:256)
|
||||||
data rms/999.0/,k0/99999999/
|
data rms/999.0/,k0/99999999/
|
||||||
equivalence (x,cx)
|
equivalence (x,cx)
|
||||||
|
@ -36,8 +36,9 @@ subroutine msk144signalquality(cframe,snr,freq,t0,softbits,msg,dxcall, &
|
|||||||
real phase(864)
|
real phase(864)
|
||||||
real twopi,freq,phi,dphi0,dphi1,dphi
|
real twopi,freq,phi,dphi0,dphi1,dphi
|
||||||
real*8 x(145),y(145),pp(145),sigmay(145),a(5),chisqr
|
real*8 x(145),y(145),pp(145),sigmay(145),a(5),chisqr
|
||||||
real pcoeffs(5)
|
real*8 pcoeffs(5)
|
||||||
|
|
||||||
|
parameter (NFREQLOW=500,NFREQHIGH=2500)
|
||||||
data first/.true./
|
data first/.true./
|
||||||
save cross_avg,wt_avg,first,currently_training, &
|
save cross_avg,wt_avg,first,currently_training, &
|
||||||
navg,tlast,training_dxcall,trained_dxcall
|
navg,tlast,training_dxcall,trained_dxcall
|
||||||
@ -202,7 +203,7 @@ write(*,*) 'training ',navg,sqrt(chisqr),rmsdiff
|
|||||||
pcoeff_filename=datadir(1:l1+1)//trim(pcoeff_filename)
|
pcoeff_filename=datadir(1:l1+1)//trim(pcoeff_filename)
|
||||||
write(*,*) 'trained - writing coefficients to: ',pcoeff_filename
|
write(*,*) 'trained - writing coefficients to: ',pcoeff_filename
|
||||||
open(17,file=pcoeff_filename,status='new')
|
open(17,file=pcoeff_filename,status='new')
|
||||||
write(17,'(i4,2f10.2,5f10.4)') navg,sqrt(chisqr),rmsdiff,a(1),a(2),a(3),a(4),a(5)
|
write(17,'(i4,2f10.2,3i5,5e25.16)') navg,sqrt(chisqr),rmsdiff,NFREQLOW,NFREQHIGH,nterms,a
|
||||||
do i=1, 145
|
do i=1, 145
|
||||||
write(17,*) x(i),pp(i),y(i),sigmay(i)
|
write(17,*) x(i),pp(i),y(i),sigmay(i)
|
||||||
enddo
|
enddo
|
||||||
|
@ -37,7 +37,7 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
|
|||||||
real pow(8)
|
real pow(8)
|
||||||
real softbits(144)
|
real softbits(144)
|
||||||
real xmc(NPATTERNS)
|
real xmc(NPATTERNS)
|
||||||
real pcoeffs(5)
|
real*8 pcoeffs(5)
|
||||||
|
|
||||||
logical*1 bshmsg,bcontest,btrain,bswl
|
logical*1 bshmsg,bcontest,btrain,bswl
|
||||||
logical*1 first
|
logical*1 first
|
||||||
|
@ -4,9 +4,9 @@ subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
|
|||||||
! id2 i*2 Raw 16-bit integer data, 12000 Hz sample rate
|
! id2 i*2 Raw 16-bit integer data, 12000 Hz sample rate
|
||||||
! brefspec logical True when accumulating a reference spectrum
|
! brefspec logical True when accumulating a reference spectrum
|
||||||
|
|
||||||
parameter (NFFT=6912,NH=NFFT/2)
|
parameter (NFFT=6912,NH=NFFT/2,NPOLYLOW=400,NPOLYHIGH=2600)
|
||||||
integer*2 id2(NFFT)
|
integer*2 id2(NFFT)
|
||||||
logical*1 bclear,brefspec,buseref
|
logical*1 bclear,brefspec,buseref,blastuse
|
||||||
|
|
||||||
real x0(0:NH-1) !Input samples
|
real x0(0:NH-1) !Input samples
|
||||||
real x1(0:NH-1) !Output samples (delayed by one block)
|
real x1(0:NH-1) !Output samples (delayed by one block)
|
||||||
@ -17,12 +17,12 @@ subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
|
|||||||
real*4 s(0:NH) !Average spectrum
|
real*4 s(0:NH) !Average spectrum
|
||||||
real*4 fil(0:NH)
|
real*4 fil(0:NH)
|
||||||
real*8 xfit(1500),yfit(1500),sigmay(1500),a(5),chisqr !Polyfit arrays
|
real*8 xfit(1500),yfit(1500),sigmay(1500),a(5),chisqr !Polyfit arrays
|
||||||
logical first,firstuse
|
logical first
|
||||||
complex cx(0:NH) !Complex frequency-domain work array
|
complex cx(0:NH) !Complex frequency-domain work array
|
||||||
character*(*) fname
|
character*(*) fname
|
||||||
common/spectra/syellow(6827),ref(0:NH),filter(0:NH)
|
common/spectra/syellow(6827),ref(0:NH),filter(0:NH)
|
||||||
equivalence(x,cx)
|
equivalence(x,cx)
|
||||||
data first/.true./,firstuse/.true./
|
data first/.true./,blastuse/.false./
|
||||||
save
|
save
|
||||||
|
|
||||||
if(first) then
|
if(first) then
|
||||||
@ -98,8 +98,8 @@ subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
|
|||||||
if(s(i).gt.0.0) filter(i)=20.0*log10(fil(i))
|
if(s(i).gt.0.0) filter(i)=20.0*log10(fil(i))
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
il=nint(400.0/df)
|
il=nint(NPOLYLOW/df)
|
||||||
ih=nint(2600.0/df)
|
ih=nint(NPOLYHIGH/df)
|
||||||
nfit=ih-il+1
|
nfit=ih-il+1
|
||||||
mode=0
|
mode=0
|
||||||
nterms=5
|
nterms=5
|
||||||
@ -111,8 +111,8 @@ subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
|
|||||||
call polyfit(xfit,yfit,sigmay,nfit,nterms,mode,a,chisqr)
|
call polyfit(xfit,yfit,sigmay,nfit,nterms,mode,a,chisqr)
|
||||||
|
|
||||||
open(16,file=fname,status='unknown')
|
open(16,file=fname,status='unknown')
|
||||||
write(16,1003) a
|
write(16,1003) NPOLYLOW,NPOLYHIGH,nterms,a
|
||||||
1003 format(5f10.4)
|
1003 format(3i5,5e25.16)
|
||||||
do i=1,NH
|
do i=1,NH
|
||||||
freq=i*df
|
freq=i*df
|
||||||
ref(i)=db(s(i)/avemid)
|
ref(i)=db(s(i)/avemid)
|
||||||
@ -125,17 +125,18 @@ subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
if(buseref) then
|
if(buseref) then
|
||||||
if(firstuse) then
|
if(blastuse.neqv.buseref) then !just enabled so read filter
|
||||||
fil=1.0
|
fil=1.0
|
||||||
open(16,file=fname,status='old',err=10)
|
open(16,file=fname,status='old',err=110)
|
||||||
read(16,1003,err=10,end=10) a
|
read(16,1003,err=20,end=100) ndummy,ndummy,nterms,a
|
||||||
do i=1,NH
|
goto 30
|
||||||
read(16,1005,err=10,end=10) freq,s(i),ref(i),fil(i),filter(i)
|
20 rewind(16) !allow for old style refspec.dat with no header
|
||||||
|
30 do i=1,NH
|
||||||
|
read(16,1005,err=100,end=100) freq,s(i),ref(i),fil(i),filter(i)
|
||||||
enddo
|
enddo
|
||||||
10 close(16)
|
100 close(16)
|
||||||
firstuse=.false.
|
110 continue
|
||||||
endif
|
endif
|
||||||
! x0=id2(NH+1:NFFT)
|
|
||||||
x0=id2(1:NH)
|
x0=id2(1:NH)
|
||||||
x(0:NH-1)=x0s !Previous 2nd half to new 1st half
|
x(0:NH-1)=x0s !Previous 2nd half to new 1st half
|
||||||
x(NH:NFFT-1)=x0 !New 2nd half
|
x(NH:NFFT-1)=x0 !New 2nd half
|
||||||
@ -148,6 +149,6 @@ subroutine refspectrum(id2,bclear,brefspec,buseref,fname)
|
|||||||
id2(1:NH)=nint(x1)
|
id2(1:NH)=nint(x1)
|
||||||
x1s=x(NH:NFFT-1) !Save the new 2nd half
|
x1s=x(NH:NFFT-1) !Save the new 2nd half
|
||||||
endif
|
endif
|
||||||
|
blastuse=buseref
|
||||||
return
|
return
|
||||||
end subroutine refspectrum
|
end subroutine refspectrum
|
||||||
|
@ -69,7 +69,7 @@ extern "C" {
|
|||||||
int* minw, float* px, float s[], float* df3, int* nhsym, int* npts8);
|
int* minw, float* px, float s[], float* df3, int* nhsym, int* npts8);
|
||||||
|
|
||||||
void hspec_(short int d2[], int* k, int* nutc0, int* ntrperiod, int* nrxfreq, int* ntol,
|
void hspec_(short int d2[], int* k, int* nutc0, int* ntrperiod, int* nrxfreq, int* ntol,
|
||||||
bool* bmsk144, bool* bcontest, bool* btrain, float const pcoeffs[], int* ingain,
|
bool* bmsk144, bool* bcontest, bool* btrain, double const pcoeffs[], int* ingain,
|
||||||
char mycall[], char hiscall[], bool* bshmsg, bool* bswl, char ddir[], float green[],
|
char mycall[], char hiscall[], bool* bshmsg, bool* bswl, char ddir[], float green[],
|
||||||
float s[], int* jh, char line[], char mygrid[],
|
float s[], int* jh, char line[], char mygrid[],
|
||||||
int len1, int len2, int len3, int len4, int len5);
|
int len1, int len2, int len3, int len4, int len5);
|
||||||
@ -515,7 +515,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
|||||||
{
|
{
|
||||||
m_phaseEqualizationDialog.reset (new PhaseEqualizationDialog {m_settings, m_dataDir, m_phaseEqCoefficients, this});
|
m_phaseEqualizationDialog.reset (new PhaseEqualizationDialog {m_settings, m_dataDir, m_phaseEqCoefficients, this});
|
||||||
connect (m_phaseEqualizationDialog.data (), &PhaseEqualizationDialog::phase_equalization_changed,
|
connect (m_phaseEqualizationDialog.data (), &PhaseEqualizationDialog::phase_equalization_changed,
|
||||||
[this] (QVector<float> const& coeffs) {
|
[this] (QVector<double> const& coeffs) {
|
||||||
m_phaseEqCoefficients = coeffs;
|
m_phaseEqCoefficients = coeffs;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -986,7 +986,7 @@ void MainWindow::writeSettings()
|
|||||||
QList<QVariant> coeffs; // suitable for QSettings
|
QList<QVariant> coeffs; // suitable for QSettings
|
||||||
for (auto const& coeff : m_phaseEqCoefficients)
|
for (auto const& coeff : m_phaseEqCoefficients)
|
||||||
{
|
{
|
||||||
coeffs << static_cast<double> (coeff);
|
coeffs << coeff;
|
||||||
}
|
}
|
||||||
m_settings->setValue ("PhaseEqualizationCoefficients", QVariant {coeffs});
|
m_settings->setValue ("PhaseEqualizationCoefficients", QVariant {coeffs});
|
||||||
}
|
}
|
||||||
|
@ -542,7 +542,7 @@ private:
|
|||||||
QHash<QString, QVariant> m_pwrBandTxMemory; // Remembers power level by band
|
QHash<QString, QVariant> m_pwrBandTxMemory; // Remembers power level by band
|
||||||
QHash<QString, QVariant> m_pwrBandTuneMemory; // Remembers power level by band for tuning
|
QHash<QString, QVariant> m_pwrBandTuneMemory; // Remembers power level by band for tuning
|
||||||
QByteArray m_geometryNoControls;
|
QByteArray m_geometryNoControls;
|
||||||
QVector<float> m_phaseEqCoefficients;
|
QVector<double> m_phaseEqCoefficients;
|
||||||
|
|
||||||
//---------------------------------------------------- private functions
|
//---------------------------------------------------- private functions
|
||||||
void readSettings();
|
void readSettings();
|
||||||
|
Loading…
Reference in New Issue
Block a user