Waterfall display
This commit is contained in:
parent
a7fcaf7d97
commit
5897705f32
@ -39,6 +39,7 @@ void TileWidget::clear()
|
|||||||
{
|
{
|
||||||
if(hasContent) {
|
if(hasContent) {
|
||||||
delete content;
|
delete content;
|
||||||
|
content = nullptr;
|
||||||
hasContent = false;
|
hasContent = false;
|
||||||
}
|
}
|
||||||
if(isSplit) {
|
if(isSplit) {
|
||||||
@ -99,11 +100,13 @@ void TileWidget::fromJSON(nlohmann::json j)
|
|||||||
content = new TraceSmithChart(model);
|
content = new TraceSmithChart(model);
|
||||||
} else if (plotname == "XY-plot"){
|
} else if (plotname == "XY-plot"){
|
||||||
content = new TraceXYPlot(model);
|
content = new TraceXYPlot(model);
|
||||||
} else {
|
} else if (plotname == "Waterfall"){
|
||||||
content = new TraceWaterfall(model);
|
content = new TraceWaterfall(model);
|
||||||
}
|
}
|
||||||
setContent(content);
|
if(content) {
|
||||||
content->fromJSON(j["plotsettings"]);
|
setContent(content);
|
||||||
|
content->fromJSON(j["plotsettings"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ HEADERS += \
|
|||||||
Traces/fftcomplex.h \
|
Traces/fftcomplex.h \
|
||||||
Traces/sparamtraceselector.h \
|
Traces/sparamtraceselector.h \
|
||||||
Traces/trace.h \
|
Traces/trace.h \
|
||||||
|
Traces/traceaxis.h \
|
||||||
Traces/tracecsvexport.h \
|
Traces/tracecsvexport.h \
|
||||||
Traces/traceeditdialog.h \
|
Traces/traceeditdialog.h \
|
||||||
Traces/traceimportdialog.h \
|
Traces/traceimportdialog.h \
|
||||||
@ -101,6 +102,7 @@ HEADERS += \
|
|||||||
Traces/tracewaterfall.h \
|
Traces/tracewaterfall.h \
|
||||||
Traces/tracewidget.h \
|
Traces/tracewidget.h \
|
||||||
Traces/tracexyplot.h \
|
Traces/tracexyplot.h \
|
||||||
|
Traces/waterfallaxisdialog.h \
|
||||||
Traces/xyplotaxisdialog.h \
|
Traces/xyplotaxisdialog.h \
|
||||||
Util/qpointervariant.h \
|
Util/qpointervariant.h \
|
||||||
Util/util.h \
|
Util/util.h \
|
||||||
@ -209,6 +211,7 @@ SOURCES += \
|
|||||||
Traces/fftcomplex.cpp \
|
Traces/fftcomplex.cpp \
|
||||||
Traces/sparamtraceselector.cpp \
|
Traces/sparamtraceselector.cpp \
|
||||||
Traces/trace.cpp \
|
Traces/trace.cpp \
|
||||||
|
Traces/traceaxis.cpp \
|
||||||
Traces/tracecsvexport.cpp \
|
Traces/tracecsvexport.cpp \
|
||||||
Traces/traceeditdialog.cpp \
|
Traces/traceeditdialog.cpp \
|
||||||
Traces/traceimportdialog.cpp \
|
Traces/traceimportdialog.cpp \
|
||||||
@ -219,6 +222,7 @@ SOURCES += \
|
|||||||
Traces/tracewaterfall.cpp \
|
Traces/tracewaterfall.cpp \
|
||||||
Traces/tracewidget.cpp \
|
Traces/tracewidget.cpp \
|
||||||
Traces/tracexyplot.cpp \
|
Traces/tracexyplot.cpp \
|
||||||
|
Traces/waterfallaxisdialog.cpp \
|
||||||
Traces/xyplotaxisdialog.cpp \
|
Traces/xyplotaxisdialog.cpp \
|
||||||
Util/util.cpp \
|
Util/util.cpp \
|
||||||
VNA/Deembedding/deembedding.cpp \
|
VNA/Deembedding/deembedding.cpp \
|
||||||
@ -286,6 +290,7 @@ FORMS += \
|
|||||||
Traces/traceimportdialog.ui \
|
Traces/traceimportdialog.ui \
|
||||||
Traces/tracetouchstoneexport.ui \
|
Traces/tracetouchstoneexport.ui \
|
||||||
Traces/tracewidget.ui \
|
Traces/tracewidget.ui \
|
||||||
|
Traces/waterfallaxisdialog.ui \
|
||||||
Traces/xyplotaxisdialog.ui \
|
Traces/xyplotaxisdialog.ui \
|
||||||
VNA/Deembedding/deembeddingdialog.ui \
|
VNA/Deembedding/deembeddingdialog.ui \
|
||||||
VNA/Deembedding/manualdeembeddingdialog.ui \
|
VNA/Deembedding/manualdeembeddingdialog.ui \
|
||||||
|
@ -70,8 +70,8 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
|||||||
auto traceXY = new TraceXYPlot(traceModel);
|
auto traceXY = new TraceXYPlot(traceModel);
|
||||||
traceXY->enableTrace(tPort1, true);
|
traceXY->enableTrace(tPort1, true);
|
||||||
traceXY->enableTrace(tPort2, true);
|
traceXY->enableTrace(tPort2, true);
|
||||||
traceXY->setYAxis(0, TraceXYPlot::YAxisType::Magnitude, false, false, -120,0,10);
|
traceXY->setYAxis(0, YAxis::Type::Magnitude, false, false, -120,0,10);
|
||||||
traceXY->setYAxis(1, TraceXYPlot::YAxisType::Disabled, false, true, 0,0,1);
|
traceXY->setYAxis(1, YAxis::Type::Disabled, false, true, 0,0,1);
|
||||||
|
|
||||||
connect(this, &SpectrumAnalyzer::graphColorsChanged, [=](){
|
connect(this, &SpectrumAnalyzer::graphColorsChanged, [=](){
|
||||||
for (auto p : TracePlot::getPlots()) {
|
for (auto p : TracePlot::getPlots()) {
|
||||||
|
441
Software/PC_Application/Traces/traceaxis.cpp
Normal file
441
Software/PC_Application/Traces/traceaxis.cpp
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
#include "traceaxis.h"
|
||||||
|
#include "Util/util.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static void createEvenlySpacedTicks(vector<double>& ticks, double start, double stop, double step) {
|
||||||
|
ticks.clear();
|
||||||
|
if(start > stop) {
|
||||||
|
swap(start, stop);
|
||||||
|
}
|
||||||
|
step = abs(step);
|
||||||
|
constexpr unsigned int maxTicks = 100;
|
||||||
|
for(double tick = start; tick - stop < numeric_limits<double>::epsilon() && ticks.size() <= maxTicks;tick+= step) {
|
||||||
|
ticks.push_back(tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double createAutomaticTicks(vector<double>& ticks, double start, double stop, int minDivisions) {
|
||||||
|
Q_ASSERT(stop > start);
|
||||||
|
ticks.clear();
|
||||||
|
double max_div_step = (stop - start) / minDivisions;
|
||||||
|
int zeros = floor(log10(max_div_step));
|
||||||
|
double decimals_shift = pow(10, zeros);
|
||||||
|
max_div_step /= decimals_shift;
|
||||||
|
if(max_div_step >= 5) {
|
||||||
|
max_div_step = 5;
|
||||||
|
} else if(max_div_step >= 2) {
|
||||||
|
max_div_step = 2;
|
||||||
|
} else {
|
||||||
|
max_div_step = 1;
|
||||||
|
}
|
||||||
|
auto div_step = max_div_step * decimals_shift;
|
||||||
|
// round min up to next multiple of div_step
|
||||||
|
auto start_div = ceil(start / div_step) * div_step;
|
||||||
|
for(double tick = start_div;tick <= stop;tick += div_step) {
|
||||||
|
ticks.push_back(tick);
|
||||||
|
}
|
||||||
|
return div_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createLogarithmicTicks(vector<double>& ticks, double start, double stop, int minDivisions) {
|
||||||
|
// enforce usable log settings
|
||||||
|
if(start <= 0) {
|
||||||
|
start = 1.0;
|
||||||
|
}
|
||||||
|
if(stop <= start) {
|
||||||
|
stop = start + 1.0;
|
||||||
|
}
|
||||||
|
ticks.clear();
|
||||||
|
|
||||||
|
auto decades = log10(stop) - log10(start);
|
||||||
|
double max_div_decade = minDivisions / decades;
|
||||||
|
int zeros = floor(log10(max_div_decade));
|
||||||
|
double decimals_shift = pow(10, zeros);
|
||||||
|
max_div_decade /= decimals_shift;
|
||||||
|
if(max_div_decade < 2) {
|
||||||
|
max_div_decade = 2;
|
||||||
|
} else if(max_div_decade < 5) {
|
||||||
|
max_div_decade = 5;
|
||||||
|
} else {
|
||||||
|
max_div_decade = 10;
|
||||||
|
}
|
||||||
|
auto step = pow(10, floor(log10(start))+1) / (max_div_decade * decimals_shift);
|
||||||
|
// round min up to next multiple of div_step
|
||||||
|
auto div = ceil(start / step) * step;
|
||||||
|
if(floor(log10(div)) != floor(log10(start))) {
|
||||||
|
// first div is already at the next decade
|
||||||
|
step *= 10;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
ticks.push_back(div);
|
||||||
|
if(ticks.size() > 1 && div != step && floor(log10(div)) != floor(log10(div - step))) {
|
||||||
|
// reached a new decade with this switch
|
||||||
|
step *= 10;
|
||||||
|
div = step;
|
||||||
|
} else {
|
||||||
|
div += step;
|
||||||
|
}
|
||||||
|
} while(div <= stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case YAxis::Type::Magnitude:
|
||||||
|
return Util::SparamTodB(data.y);
|
||||||
|
case YAxis::Type::MagnitudedBuV:
|
||||||
|
return Util::dBmTodBuV(Util::SparamTodB(data.y));
|
||||||
|
case YAxis::Type::MagnitudeLinear:
|
||||||
|
return abs(data.y);
|
||||||
|
case YAxis::Type::Phase:
|
||||||
|
return Util::SparamToDegree(data.y);
|
||||||
|
case YAxis::Type::UnwrappedPhase:
|
||||||
|
if(!t) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return t->getUnwrappedPhase(sample) * 180.0 / M_PI;
|
||||||
|
case YAxis::Type::VSWR:
|
||||||
|
return Util::SparamToVSWR(data.y);
|
||||||
|
case YAxis::Type::Real:
|
||||||
|
return data.y.real();
|
||||||
|
case YAxis::Type::Imaginary:
|
||||||
|
return data.y.imag();
|
||||||
|
case YAxis::Type::SeriesR:
|
||||||
|
return Util::SparamToResistance(data.y);
|
||||||
|
case YAxis::Type::Reactance:
|
||||||
|
return Util::SparamToImpedance(data.y).imag();
|
||||||
|
case YAxis::Type::Capacitance:
|
||||||
|
return Util::SparamToCapacitance(data.y, data.x);
|
||||||
|
case YAxis::Type::Inductance:
|
||||||
|
return Util::SparamToInductance(data.y, data.x);
|
||||||
|
case YAxis::Type::QualityFactor:
|
||||||
|
return Util::SparamToQualityFactor(data.y);
|
||||||
|
case YAxis::Type::GroupDelay: {
|
||||||
|
constexpr int requiredSamples = 5;
|
||||||
|
if(!t || t->size() < requiredSamples) {
|
||||||
|
// unable to calculate
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
// needs at least some samples before/after current sample for calculating the derivative.
|
||||||
|
// For samples too far at either end of the trace, return group delay of "inner" trace sample instead
|
||||||
|
if(sample < requiredSamples / 2) {
|
||||||
|
return sampleToCoordinate(data, t, requiredSamples / 2);
|
||||||
|
} else if(sample >= t->size() - requiredSamples / 2) {
|
||||||
|
return sampleToCoordinate(data, t, t->size() - requiredSamples / 2 - 1);
|
||||||
|
} else {
|
||||||
|
// got enough samples at either end to calculate derivative.
|
||||||
|
// acquire phases of the required samples
|
||||||
|
std::vector<double> phases;
|
||||||
|
phases.reserve(requiredSamples);
|
||||||
|
for(unsigned int index = sample - requiredSamples / 2;index <= sample + requiredSamples / 2;index++) {
|
||||||
|
phases.push_back(arg(t->sample(index).y));
|
||||||
|
}
|
||||||
|
// make sure there are no phase jumps
|
||||||
|
Util::unwrapPhase(phases);
|
||||||
|
// calculate linearRegression to get derivative
|
||||||
|
double B_0, B_1;
|
||||||
|
Util::linearRegression(phases, B_0, B_1);
|
||||||
|
// B_1 now contains the derived phase vs. the sample. Scale by frequency to get group delay
|
||||||
|
double freq_step = t->sample(sample).x - t->sample(sample - 1).x;
|
||||||
|
return -B_1 / (2.0*M_PI * freq_step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case YAxis::Type::ImpulseReal:
|
||||||
|
return real(data.y);
|
||||||
|
case YAxis::Type::ImpulseMag:
|
||||||
|
return Util::SparamTodB(data.y);
|
||||||
|
case YAxis::Type::Step:
|
||||||
|
if(!t) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return t->sample(sample, true).y.real();
|
||||||
|
case YAxis::Type::Impedance: {
|
||||||
|
if(!t) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
double step = t->sample(sample, true).y.real();
|
||||||
|
if(abs(step) < 1.0) {
|
||||||
|
return Util::SparamToImpedance(step).real();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case YAxis::Type::Disabled:
|
||||||
|
case YAxis::Type::Last:
|
||||||
|
// no valid axis
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void YAxis::set(Type type, bool log, bool autorange, double min, double max, double div)
|
||||||
|
{
|
||||||
|
this->type = type;
|
||||||
|
this->log = log;
|
||||||
|
this->autorange = autorange;
|
||||||
|
this->rangeMin = min;
|
||||||
|
this->rangeMax = max;
|
||||||
|
this->rangeDiv = div;
|
||||||
|
if(type != Type::Disabled) {
|
||||||
|
updateTicks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString YAxis::TypeToName(Type type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case Type::Disabled: return "Disabled";
|
||||||
|
case Type::Magnitude: return "Magnitude (dB/dBm)";
|
||||||
|
case Type::MagnitudedBuV: return "Magnitude (dBuV)";
|
||||||
|
case Type::MagnitudeLinear: return "Magnitude (linear)";
|
||||||
|
case Type::Phase: return "Phase";
|
||||||
|
case Type::UnwrappedPhase: return "Unwrapped Phase";
|
||||||
|
case Type::VSWR: return "VSWR";
|
||||||
|
case Type::Real: return "Real";
|
||||||
|
case Type::Imaginary: return "Imaginary";
|
||||||
|
case Type::SeriesR: return "Resistance";
|
||||||
|
case Type::Reactance: return "Reactance";
|
||||||
|
case Type::Capacitance: return "Capacitance";
|
||||||
|
case Type::Inductance: return "Inductance";
|
||||||
|
case Type::QualityFactor: return "Quality Factor";
|
||||||
|
case Type::GroupDelay: return "Group delay";
|
||||||
|
case Type::ImpulseReal: return "Impulse Response (Real)";
|
||||||
|
case Type::ImpulseMag: return "Impulse Response (Magnitude)";
|
||||||
|
case Type::Step: return "Step Response";
|
||||||
|
case Type::Impedance: return "Impedance";
|
||||||
|
case Type::Last: return "Unknown";
|
||||||
|
}
|
||||||
|
return "Missing case";
|
||||||
|
}
|
||||||
|
|
||||||
|
YAxis::Type YAxis::TypeFromName(QString name)
|
||||||
|
{
|
||||||
|
for(unsigned int i=0;i<(int) Type::Last;i++) {
|
||||||
|
if(TypeToName((Type) i) == name) {
|
||||||
|
return (Type) i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// not found, use default
|
||||||
|
return Type::Magnitude;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString YAxis::Unit(Type type, TraceModel::DataSource source)
|
||||||
|
{
|
||||||
|
if(source == TraceModel::DataSource::VNA) {
|
||||||
|
switch(type) {
|
||||||
|
case Type::Magnitude: return "dB";
|
||||||
|
case Type::MagnitudeLinear: return "";
|
||||||
|
case Type::Phase: return "°";
|
||||||
|
case Type::UnwrappedPhase: return "°";
|
||||||
|
case Type::VSWR: return "";
|
||||||
|
case Type::ImpulseReal: return "";
|
||||||
|
case Type::ImpulseMag: return "dB";
|
||||||
|
case Type::Step: return "";
|
||||||
|
case Type::Impedance: return "Ω";
|
||||||
|
case Type::GroupDelay: return "s";
|
||||||
|
case Type::Disabled:
|
||||||
|
case Type::Real:
|
||||||
|
case Type::Imaginary:
|
||||||
|
case Type::QualityFactor:
|
||||||
|
return "";
|
||||||
|
case Type::SeriesR: return "Ω";
|
||||||
|
case Type::Reactance: return "Ω";
|
||||||
|
case Type::Capacitance: return "F";
|
||||||
|
case Type::Inductance: return "H";
|
||||||
|
case Type::Last: return "";
|
||||||
|
}
|
||||||
|
} else if(source == TraceModel::DataSource::SA) {
|
||||||
|
switch(type) {
|
||||||
|
case Type::Magnitude: return "dBm";
|
||||||
|
case Type::MagnitudedBuV: return "dBuV";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString YAxis::Prefixes(Type type, TraceModel::DataSource source)
|
||||||
|
{
|
||||||
|
if(source == TraceModel::DataSource::VNA) {
|
||||||
|
switch(type) {
|
||||||
|
case Type::Magnitude: return " ";
|
||||||
|
case Type::MagnitudeLinear: return "num ";
|
||||||
|
case Type::Phase: return " ";
|
||||||
|
case Type::UnwrappedPhase: return " ";
|
||||||
|
case Type::VSWR: return " ";
|
||||||
|
case Type::ImpulseReal: return "pnum kMG";
|
||||||
|
case Type::ImpulseMag: return " ";
|
||||||
|
case Type::Step: return "pnum kMG";
|
||||||
|
case Type::Impedance: return "m kM";
|
||||||
|
case Type::GroupDelay: return "pnum ";
|
||||||
|
case Type::Disabled: return " ";
|
||||||
|
case Type::Real: return "pnum ";
|
||||||
|
case Type::Imaginary: return "pnum ";
|
||||||
|
case Type::QualityFactor: return " ";
|
||||||
|
case Type::SeriesR: return "m kM";
|
||||||
|
case Type::Reactance: return "m kM";
|
||||||
|
case Type::Capacitance: return "pnum ";
|
||||||
|
case Type::Inductance: return "pnum ";
|
||||||
|
case Type::Last: return " ";
|
||||||
|
}
|
||||||
|
} else if(source == TraceModel::DataSource::SA) {
|
||||||
|
switch(type) {
|
||||||
|
case Type::Magnitude: return " ";
|
||||||
|
case Type::MagnitudedBuV: return " ";
|
||||||
|
default: return " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString YAxis::TypeToName()
|
||||||
|
{
|
||||||
|
return TypeToName(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString YAxis::Unit(TraceModel::DataSource source)
|
||||||
|
{
|
||||||
|
return Unit(type, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString YAxis::Prefixes(TraceModel::DataSource source)
|
||||||
|
{
|
||||||
|
return Prefixes(type, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
YAxis::Type YAxis::getType() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Axis::updateTicks()
|
||||||
|
{
|
||||||
|
if(log) {
|
||||||
|
createLogarithmicTicks(ticks, rangeMin, rangeMax, 20);
|
||||||
|
} else if(autorange) {
|
||||||
|
if(rangeMin >= rangeMax) {
|
||||||
|
// problem, min must be less than max
|
||||||
|
rangeMin -= 1.0;
|
||||||
|
rangeMax += 1.0;
|
||||||
|
}
|
||||||
|
rangeDiv = createAutomaticTicks(ticks, rangeMin, rangeMax, 8);
|
||||||
|
} else {
|
||||||
|
createEvenlySpacedTicks(ticks, rangeMin, rangeMax, rangeDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<double> &Axis::getTicks() const
|
||||||
|
{
|
||||||
|
return ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Axis::getRangeDiv() const
|
||||||
|
{
|
||||||
|
return rangeDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Axis::getRangeMax() const
|
||||||
|
{
|
||||||
|
return rangeMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Axis::getRangeMin() const
|
||||||
|
{
|
||||||
|
return rangeMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Axis::getAutorange() const
|
||||||
|
{
|
||||||
|
return autorange;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Axis::getLog() const
|
||||||
|
{
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
double XAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case Type::Distance:
|
||||||
|
if(!t) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return t->timeToDistance(data.x);
|
||||||
|
default:
|
||||||
|
return data.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAxis::set(Type type, bool log, bool autorange, double min, double max, double div)
|
||||||
|
{
|
||||||
|
this->type = type;
|
||||||
|
this->log = log;
|
||||||
|
this->autorange = autorange;
|
||||||
|
this->rangeMin = min;
|
||||||
|
this->rangeMax = max;
|
||||||
|
this->rangeDiv = div;
|
||||||
|
updateTicks();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString XAxis::TypeToName(Type type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case Type::Frequency: return "Frequency";
|
||||||
|
case Type::Time: return "Time";
|
||||||
|
case Type::Distance: return "Distance";
|
||||||
|
case Type::Power: return "Power";
|
||||||
|
default: return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XAxis::Type XAxis::TypeFromName(QString name)
|
||||||
|
{
|
||||||
|
for(unsigned int i=0;i<(int) Type::Last;i++) {
|
||||||
|
if(TypeToName((Type) i) == name) {
|
||||||
|
return (Type) i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// not found, use default
|
||||||
|
return Type::Frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString XAxis::Unit(Type type)
|
||||||
|
{
|
||||||
|
switch(type) {
|
||||||
|
case Type::Frequency: return "Hz";
|
||||||
|
case Type::Time: return "s";
|
||||||
|
case Type::Distance: return "m";
|
||||||
|
case Type::Power: return "dBm";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString XAxis::TypeToName()
|
||||||
|
{
|
||||||
|
return TypeToName(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString XAxis::Unit()
|
||||||
|
{
|
||||||
|
return Unit(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
XAxis::Type XAxis::getType() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Axis::transform(double value, double to_low, double to_high)
|
||||||
|
{
|
||||||
|
return Util::Scale(value, rangeMin, rangeMax, to_low, to_high, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Axis::inverseTransform(double value, double to_low, double to_high)
|
||||||
|
{
|
||||||
|
return Util::Scale(value, to_low, to_high, rangeMin, rangeMax, false, log);
|
||||||
|
}
|
97
Software/PC_Application/Traces/traceaxis.h
Normal file
97
Software/PC_Application/Traces/traceaxis.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#ifndef TRACEAXIS_H
|
||||||
|
#define TRACEAXIS_H
|
||||||
|
|
||||||
|
#include "tracemodel.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class Axis {
|
||||||
|
public:
|
||||||
|
virtual double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) = 0;
|
||||||
|
double transform(double value, double to_low, double to_high);
|
||||||
|
double inverseTransform(double value, double to_low, double to_high);
|
||||||
|
bool getLog() const;
|
||||||
|
bool getAutorange() const;
|
||||||
|
double getRangeMin() const;
|
||||||
|
double getRangeMax() const;
|
||||||
|
double getRangeDiv() const;
|
||||||
|
const std::vector<double> &getTicks() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateTicks();
|
||||||
|
bool log;
|
||||||
|
bool autorange;
|
||||||
|
double rangeMin;
|
||||||
|
double rangeMax;
|
||||||
|
double rangeDiv;
|
||||||
|
std::vector<double> ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
class YAxis : public Axis {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Disabled,
|
||||||
|
// S parameter options
|
||||||
|
Magnitude,
|
||||||
|
MagnitudedBuV,
|
||||||
|
MagnitudeLinear,
|
||||||
|
Phase,
|
||||||
|
UnwrappedPhase,
|
||||||
|
VSWR,
|
||||||
|
Real,
|
||||||
|
Imaginary,
|
||||||
|
// derived parameter options
|
||||||
|
SeriesR,
|
||||||
|
Reactance,
|
||||||
|
Capacitance,
|
||||||
|
Inductance,
|
||||||
|
QualityFactor,
|
||||||
|
GroupDelay,
|
||||||
|
// TDR options
|
||||||
|
ImpulseReal,
|
||||||
|
ImpulseMag,
|
||||||
|
Step,
|
||||||
|
Impedance,
|
||||||
|
Last,
|
||||||
|
};
|
||||||
|
double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override;
|
||||||
|
void set(Type type, bool log, bool autorange, double min, double max, double div);
|
||||||
|
static QString TypeToName(Type type);
|
||||||
|
static Type TypeFromName(QString name);
|
||||||
|
static QString Unit(Type type, TraceModel::DataSource source = TraceModel::DataSource::VNA);
|
||||||
|
static QString Prefixes(Type type, TraceModel::DataSource source = TraceModel::DataSource::VNA);
|
||||||
|
QString TypeToName();
|
||||||
|
QString Unit(TraceModel::DataSource source = TraceModel::DataSource::VNA);
|
||||||
|
QString Prefixes(TraceModel::DataSource source = TraceModel::DataSource::VNA);
|
||||||
|
|
||||||
|
Type getType() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class XAxis : public Axis {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Frequency,
|
||||||
|
Time,
|
||||||
|
Distance,
|
||||||
|
Power,
|
||||||
|
Last,
|
||||||
|
};
|
||||||
|
double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override;
|
||||||
|
void set(Type type, bool log, bool autorange, double min, double max, double div);
|
||||||
|
static QString TypeToName(Type type);
|
||||||
|
static Type TypeFromName(QString name);
|
||||||
|
static QString Unit(Type type);
|
||||||
|
QString TypeToName();
|
||||||
|
QString Unit();
|
||||||
|
|
||||||
|
Type getType() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRACEAXIS_H
|
@ -185,7 +185,7 @@ void TracePlot::paintEvent(QPaintEvent *event)
|
|||||||
|
|
||||||
auto tmarkers = t.first->getMarkers();
|
auto tmarkers = t.first->getMarkers();
|
||||||
for(auto m : tmarkers) {
|
for(auto m : tmarkers) {
|
||||||
if(!xCoordinateVisible(m->getPosition())) {
|
if(!markerVisible(m->getPosition())) {
|
||||||
// marker not visible with current plot settings
|
// marker not visible with current plot settings
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ protected slots:
|
|||||||
void checkIfStillSupported(Trace *t);
|
void checkIfStillSupported(Trace *t);
|
||||||
virtual void markerAdded(Marker *m);
|
virtual void markerAdded(Marker *m);
|
||||||
virtual void markerRemoved(Marker *m);
|
virtual void markerRemoved(Marker *m);
|
||||||
virtual bool xCoordinateVisible(double x) = 0;
|
virtual bool markerVisible(double x) = 0;
|
||||||
protected:
|
protected:
|
||||||
static constexpr unsigned int marginTop = 20;
|
static constexpr unsigned int marginTop = 20;
|
||||||
static constexpr unsigned int marginBottom = 0;
|
static constexpr unsigned int marginBottom = 0;
|
||||||
|
@ -250,7 +250,7 @@ double TraceSmithChart::nearestTracePoint(Trace *t, QPoint pixel, double *distan
|
|||||||
return closestXpos;
|
return closestXpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraceSmithChart::xCoordinateVisible(double x)
|
bool TraceSmithChart::markerVisible(double x)
|
||||||
{
|
{
|
||||||
if(limitToSpan) {
|
if(limitToSpan) {
|
||||||
if(x >= sweep_fmin && x <= sweep_fmax) {
|
if(x >= sweep_fmin && x <= sweep_fmax) {
|
||||||
|
@ -123,7 +123,7 @@ protected:
|
|||||||
std::complex<double> pixelToData(QPoint p);
|
std::complex<double> pixelToData(QPoint p);
|
||||||
QPoint markerToPixel(Marker *m) override;
|
QPoint markerToPixel(Marker *m) override;
|
||||||
double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) override;
|
double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) override;
|
||||||
virtual bool xCoordinateVisible(double x);
|
virtual bool markerVisible(double x);
|
||||||
|
|
||||||
//void paintEvent(QPaintEvent *event) override;
|
//void paintEvent(QPaintEvent *event) override;
|
||||||
virtual void updateContextMenu() override;
|
virtual void updateContextMenu() override;
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "Util/util.h"
|
#include "Util/util.h"
|
||||||
|
#include "waterfallaxisdialog.h"
|
||||||
|
#include "appwindow.h"
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
@ -11,8 +13,14 @@ using namespace std;
|
|||||||
|
|
||||||
TraceWaterfall::TraceWaterfall(TraceModel &model, QWidget *parent)
|
TraceWaterfall::TraceWaterfall(TraceModel &model, QWidget *parent)
|
||||||
: TracePlot(model, parent),
|
: TracePlot(model, parent),
|
||||||
pixelsPerLine(1)
|
dir(Direction::TopToBottom),
|
||||||
|
trace(nullptr),
|
||||||
|
pixelsPerLine(1),
|
||||||
|
keepDataBeyondPlotSize(false),
|
||||||
|
maxDataSweeps(500)
|
||||||
{
|
{
|
||||||
|
XAxis.set(XAxis::Type::Frequency, false, true, 0, 6000000000, 500000000);
|
||||||
|
YAxis.set(YAxis::Type::Magnitude, false, true, -1, 1, 1);
|
||||||
initializeTraceInfo();
|
initializeTraceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,32 +31,39 @@ void TraceWaterfall::enableTrace(Trace *t, bool enabled)
|
|||||||
for(auto t : traces) {
|
for(auto t : traces) {
|
||||||
if(t.second) {
|
if(t.second) {
|
||||||
TracePlot::enableTrace(t.first, false);
|
TracePlot::enableTrace(t.first, false);
|
||||||
|
disconnect(t.first, &Trace::dataChanged, this, &TraceWaterfall::traceDataChanged);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TracePlot::enableTrace(t, enabled);
|
TracePlot::enableTrace(t, enabled);
|
||||||
resetWaterfall();
|
resetWaterfall();
|
||||||
}
|
if(enabled) {
|
||||||
|
trace = t;
|
||||||
|
connect(t, &Trace::dataChanged, this, &TraceWaterfall::traceDataChanged);
|
||||||
|
} else {
|
||||||
|
trace = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void TraceWaterfall::updateSpan(double min, double max)
|
|
||||||
{
|
|
||||||
TracePlot::updateSpan(min, max);
|
|
||||||
updateAxisTicks();
|
|
||||||
resetWaterfall();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWaterfall::replot()
|
void TraceWaterfall::replot()
|
||||||
{
|
{
|
||||||
if(XAxis.mode != XAxisMode::Manual) {
|
|
||||||
updateAxisTicks();
|
|
||||||
}
|
|
||||||
TracePlot::replot();
|
TracePlot::replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWaterfall::fromJSON(nlohmann::json j)
|
void TraceWaterfall::fromJSON(nlohmann::json j)
|
||||||
{
|
{
|
||||||
resetWaterfall();
|
resetWaterfall();
|
||||||
pixelsPerLine = j.value("pixelsPerLine", 1);
|
pixelsPerLine = j.value("pixelsPerLine", pixelsPerLine);
|
||||||
|
maxDataSweeps = j.value("maxLines", maxDataSweeps);
|
||||||
|
keepDataBeyondPlotSize = j.value("keepDataBeyondPlot", keepDataBeyondPlotSize);
|
||||||
|
if(QString::fromStdString(j.value("direction", "TopToBottom")) == "TopToBottom") {
|
||||||
|
dir = Direction::TopToBottom;
|
||||||
|
} else {
|
||||||
|
dir = Direction::BottomToTop;
|
||||||
|
}
|
||||||
|
|
||||||
for(unsigned int hash : j["traces"]) {
|
for(unsigned int hash : j["traces"]) {
|
||||||
// attempt to find the traces with this hash
|
// attempt to find the traces with this hash
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -69,6 +84,9 @@ nlohmann::json TraceWaterfall::toJSON()
|
|||||||
{
|
{
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
j["pixelsPerLine"] = pixelsPerLine;
|
j["pixelsPerLine"] = pixelsPerLine;
|
||||||
|
j["direction"] = dir == Direction::TopToBottom ? "TopToBottom" : "BottomToTop";
|
||||||
|
j["keepDataBeyondPlot"] = keepDataBeyondPlotSize;
|
||||||
|
j["maxLines"] = maxDataSweeps;
|
||||||
nlohmann::json jtraces;
|
nlohmann::json jtraces;
|
||||||
for(auto t : traces) {
|
for(auto t : traces) {
|
||||||
if(t.second) {
|
if(t.second) {
|
||||||
@ -79,37 +97,59 @@ nlohmann::json TraceWaterfall::toJSON()
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWaterfall::setXAxis(XAxisType type, XAxisMode mode, bool log, double min, double max, double div)
|
|
||||||
{
|
|
||||||
XAxis.type = type;
|
|
||||||
XAxis.mode = mode;
|
|
||||||
XAxis.log = log;
|
|
||||||
XAxis.rangeMin = min;
|
|
||||||
XAxis.rangeMax = max;
|
|
||||||
XAxis.rangeDiv = div;
|
|
||||||
traceRemovalPending = true;
|
|
||||||
updateAxisTicks();
|
|
||||||
updateContextMenu();
|
|
||||||
replot();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TraceWaterfall::axisSetupDialog()
|
void TraceWaterfall::axisSetupDialog()
|
||||||
{
|
{
|
||||||
// TODO
|
auto setup = new WaterfallAxisDialog(this);
|
||||||
|
if(AppWindow::showGUI()) {
|
||||||
|
setup->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWaterfall::resetWaterfall()
|
void TraceWaterfall::resetWaterfall()
|
||||||
{
|
{
|
||||||
data.clear();
|
data.clear();
|
||||||
|
updateYAxis();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraceWaterfall::configureForTrace(Trace *t)
|
bool TraceWaterfall::configureForTrace(Trace *t)
|
||||||
{
|
{
|
||||||
// TODO
|
switch(t->outputType()) {
|
||||||
|
case Trace::DataType::Frequency:
|
||||||
|
XAxis.set(XAxis::Type::Frequency, false, true, 0, 1, 0.1);
|
||||||
|
YAxis.set(YAxis::Type::Magnitude, false, true, 0, 1, 1.0);
|
||||||
|
break;
|
||||||
|
case Trace::DataType::Time:
|
||||||
|
XAxis.set(XAxis::Type::Time, false, true, 0, 1, 0.1);
|
||||||
|
YAxis.set(YAxis::Type::ImpulseMag, false, true, 0, 1, 1.0);
|
||||||
|
break;
|
||||||
|
case Trace::DataType::Power:
|
||||||
|
XAxis.set(XAxis::Type::Power, false, true, 0, 1, 0.1);
|
||||||
|
YAxis.set(YAxis::Type::Magnitude, false, true, 0, 1, 1.0);
|
||||||
|
break;
|
||||||
|
case Trace::DataType::Invalid:
|
||||||
|
// unable to add
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
traceRemovalPending = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TraceWaterfall::domainMatch(Trace *t)
|
||||||
|
{
|
||||||
|
switch(XAxis.getType()) {
|
||||||
|
case XAxis::Type::Frequency:
|
||||||
|
return t->outputType() == Trace::DataType::Frequency;
|
||||||
|
case XAxis::Type::Distance:
|
||||||
|
case XAxis::Type::Time:
|
||||||
|
return t->outputType() == Trace::DataType::Time;
|
||||||
|
case XAxis::Type::Power:
|
||||||
|
return t->outputType() == Trace::DataType::Power;
|
||||||
|
case XAxis::Type::Last:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void TraceWaterfall::updateContextMenu()
|
void TraceWaterfall::updateContextMenu()
|
||||||
{
|
{
|
||||||
contextmenu->clear();
|
contextmenu->clear();
|
||||||
@ -162,7 +202,7 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
{
|
{
|
||||||
auto pref = Preferences::getInstance();
|
auto pref = Preferences::getInstance();
|
||||||
|
|
||||||
constexpr int yAxisSpace = 55;
|
constexpr int yAxisLegendSpace = 25;
|
||||||
constexpr int yAxisDisabledSpace = 10;
|
constexpr int yAxisDisabledSpace = 10;
|
||||||
constexpr int xAxisSpace = 30;
|
constexpr int xAxisSpace = 30;
|
||||||
auto w = p.window();
|
auto w = p.window();
|
||||||
@ -170,32 +210,59 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
pen.setCosmetic(true);
|
pen.setCosmetic(true);
|
||||||
p.setPen(pen);
|
p.setPen(pen);
|
||||||
plotAreaLeft = yAxisDisabledSpace;
|
plotAreaLeft = yAxisDisabledSpace;
|
||||||
plotAreaWidth = w.width() - 2 * yAxisDisabledSpace;
|
plotAreaWidth = w.width() - 3 * yAxisDisabledSpace - yAxisLegendSpace;
|
||||||
plotAreaTop = 10;
|
plotAreaTop = 10;
|
||||||
plotAreaBottom = w.height() - xAxisSpace;
|
plotAreaBottom = w.height() - xAxisSpace;
|
||||||
|
|
||||||
auto plotRect = QRect(plotAreaLeft, plotAreaTop, plotAreaWidth + 1, plotAreaBottom-plotAreaTop);
|
// draw Y legend
|
||||||
|
auto plotRect = QRect(w.width() - yAxisDisabledSpace - yAxisLegendSpace, plotAreaTop, yAxisLegendSpace, plotAreaBottom-plotAreaTop);
|
||||||
|
p.drawRect(plotRect);
|
||||||
|
for(int i=plotAreaTop + 1;i<plotAreaBottom;i++) {
|
||||||
|
auto color = getColor(Util::Scale<double>(i, plotAreaTop, plotAreaBottom, 1.0, 0.0));
|
||||||
|
p.setPen(QColor(color));
|
||||||
|
pen.setCosmetic(true);
|
||||||
|
p.drawLine(w.width() - yAxisDisabledSpace - yAxisLegendSpace + 1, i, w.width() - yAxisDisabledSpace - 1, i);
|
||||||
|
}
|
||||||
|
QString unit = "";
|
||||||
|
if(pref.Graphs.showUnits) {
|
||||||
|
unit = YAxis.Unit();
|
||||||
|
}
|
||||||
|
QString labelMin = Unit::ToString(YAxis.getRangeMin(), unit, YAxis.Prefixes(), 4);
|
||||||
|
QString labelMax = Unit::ToString(YAxis.getRangeMax(), unit, YAxis.Prefixes(), 4);
|
||||||
|
p.setPen(QPen(pref.Graphs.Color.axis, 1));
|
||||||
|
p.save();
|
||||||
|
p.translate(w.width() - yAxisDisabledSpace - yAxisLegendSpace, w.height());
|
||||||
|
p.rotate(-90);
|
||||||
|
p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, yAxisLegendSpace), Qt::AlignRight | Qt::AlignVCenter, labelMax);
|
||||||
|
p.drawText(QRect(xAxisSpace + 10, 0, plotAreaBottom - plotAreaTop - 20, yAxisLegendSpace), Qt::AlignLeft | Qt::AlignVCenter, labelMin);
|
||||||
|
p.restore();
|
||||||
|
|
||||||
|
|
||||||
|
pen = QPen(pref.Graphs.Color.axis, 0);
|
||||||
|
pen.setCosmetic(true);
|
||||||
|
p.setPen(pen);
|
||||||
|
plotRect = QRect(plotAreaLeft, plotAreaTop, plotAreaWidth + 1, plotAreaBottom-plotAreaTop);
|
||||||
p.drawRect(plotRect);
|
p.drawRect(plotRect);
|
||||||
|
|
||||||
// draw axis types
|
// draw axis types
|
||||||
auto font = p.font();
|
auto font = p.font();
|
||||||
font.setPixelSize(AxisLabelSize);
|
font.setPixelSize(AxisLabelSize);
|
||||||
p.setFont(font);
|
p.setFont(font);
|
||||||
p.drawText(QRect(0, w.height()-AxisLabelSize*1.5, w.width(), AxisLabelSize*1.5), Qt::AlignHCenter, AxisTypeToName(XAxis.type));
|
p.drawText(QRect(0, w.height()-AxisLabelSize*1.5, w.width(), AxisLabelSize*1.5), Qt::AlignHCenter, XAxis.TypeToName());
|
||||||
|
|
||||||
if(XAxis.ticks.size() >= 1) {
|
if(XAxis.getTicks().size() >= 1) {
|
||||||
// draw X ticks
|
// draw X ticks
|
||||||
int significantDigits;
|
int significantDigits;
|
||||||
bool displayFullFreq;
|
bool displayFullFreq;
|
||||||
if(XAxis.log) {
|
if(XAxis.getLog()) {
|
||||||
significantDigits = 5;
|
significantDigits = 5;
|
||||||
displayFullFreq = true;
|
displayFullFreq = true;
|
||||||
} else {
|
} else {
|
||||||
// this only works for evenly distributed ticks:
|
// this only works for evenly distributed ticks:
|
||||||
auto max = qMax(abs(XAxis.ticks.front()), abs(XAxis.ticks.back()));
|
auto max = qMax(abs(XAxis.getTicks().front()), abs(XAxis.getTicks().back()));
|
||||||
double step;
|
double step;
|
||||||
if(XAxis.ticks.size() >= 2) {
|
if(XAxis.getTicks().size() >= 2) {
|
||||||
step = abs(XAxis.ticks[0] - XAxis.ticks[1]);
|
step = abs(XAxis.getTicks()[0] - XAxis.getTicks()[1]);
|
||||||
} else {
|
} else {
|
||||||
// only one tick, set arbitrary number of digits
|
// only one tick, set arbitrary number of digits
|
||||||
step = max / 1000;
|
step = max / 1000;
|
||||||
@ -207,11 +274,11 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
QString prefixes = "fpnum kMG";
|
QString prefixes = "fpnum kMG";
|
||||||
QString unit = "";
|
QString unit = "";
|
||||||
if(pref.Graphs.showUnits) {
|
if(pref.Graphs.showUnits) {
|
||||||
unit = AxisUnit(XAxis.type);
|
unit = XAxis.Unit();
|
||||||
}
|
}
|
||||||
QString commonPrefix = QString();
|
QString commonPrefix = QString();
|
||||||
if(!displayFullFreq) {
|
if(!displayFullFreq) {
|
||||||
auto fullFreq = Unit::ToString(XAxis.ticks.front(), unit, prefixes, significantDigits);
|
auto fullFreq = Unit::ToString(XAxis.getTicks().front(), unit, prefixes, significantDigits);
|
||||||
commonPrefix = fullFreq.at(fullFreq.size() - 1);
|
commonPrefix = fullFreq.at(fullFreq.size() - 1);
|
||||||
auto front = fullFreq;
|
auto front = fullFreq;
|
||||||
front.truncate(fullFreq.size() - displayLastDigits - unit.length());
|
front.truncate(fullFreq.size() - displayLastDigits - unit.length());
|
||||||
@ -226,8 +293,8 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lastTickLabelEnd = 0;
|
int lastTickLabelEnd = 0;
|
||||||
for(auto t : XAxis.ticks) {
|
for(auto t : XAxis.getTicks()) {
|
||||||
auto xCoord = Util::Scale<double>(t, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth, XAxis.log);
|
auto xCoord = XAxis.transform(t, plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||||
p.setPen(QPen(pref.Graphs.Color.axis, 1));
|
p.setPen(QPen(pref.Graphs.Color.axis, 1));
|
||||||
p.drawLine(xCoord, plotAreaBottom, xCoord, plotAreaBottom + 2);
|
p.drawLine(xCoord, plotAreaBottom, xCoord, plotAreaBottom + 2);
|
||||||
if(xCoord != plotAreaLeft && xCoord != plotAreaLeft + plotAreaWidth) {
|
if(xCoord != plotAreaLeft && xCoord != plotAreaLeft + plotAreaWidth) {
|
||||||
@ -261,6 +328,76 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.setClipRect(QRect(plotRect.x()+1, plotRect.y()+1, plotRect.width()-1, plotRect.height()-1));
|
||||||
|
if(data.size()) {
|
||||||
|
// plot waterfall data
|
||||||
|
int ytop, ybottom;
|
||||||
|
bool lastLine = false;
|
||||||
|
if(dir == Direction::TopToBottom) {
|
||||||
|
ytop = plotAreaTop;
|
||||||
|
ybottom = ytop + pixelsPerLine - 1;
|
||||||
|
} else {
|
||||||
|
ybottom = plotAreaBottom - 1;
|
||||||
|
ytop = ybottom - pixelsPerLine + 1;
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
for(i=data.size() - 1;i>=0;i--) {
|
||||||
|
auto sweep = data[i];
|
||||||
|
for(unsigned int s=0;s<sweep.size();s++) {
|
||||||
|
auto x = XAxis.sampleToCoordinate(sweep[s], trace);
|
||||||
|
double x_start;
|
||||||
|
double x_stop;
|
||||||
|
if(x < XAxis.getRangeMin() || x > XAxis.getRangeMax()) {
|
||||||
|
// out of range, skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(s == 0) {
|
||||||
|
x_start = x;
|
||||||
|
} else {
|
||||||
|
auto prev_x = XAxis.sampleToCoordinate(sweep[s-1], trace);
|
||||||
|
x_start = (prev_x + x) / 2.0;
|
||||||
|
}
|
||||||
|
x_start = XAxis.transform(x_start, plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||||
|
if(s == sweep.size() - 1) {
|
||||||
|
x_stop = x;
|
||||||
|
} else {
|
||||||
|
auto next_x = XAxis.sampleToCoordinate(sweep[s+1], trace);
|
||||||
|
x_stop = (next_x + x) / 2.0;
|
||||||
|
}
|
||||||
|
x_stop = XAxis.transform(x_stop, plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||||
|
auto y = YAxis.sampleToCoordinate(sweep[s]);
|
||||||
|
auto color = getColor(YAxis.transform(y, 0.0, 1.0));
|
||||||
|
auto rect = QRect(round(x_start), ytop, round(x_stop - x_start) + 1, ybottom - ytop + 1);
|
||||||
|
p.fillRect(rect, QBrush(color));
|
||||||
|
}
|
||||||
|
if(lastLine) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// update ycoords for next line
|
||||||
|
if(dir == Direction::TopToBottom) {
|
||||||
|
ytop = ybottom + 1;
|
||||||
|
ybottom = ytop + pixelsPerLine - 1;
|
||||||
|
if(ybottom >= plotAreaBottom) {
|
||||||
|
ybottom = plotAreaBottom;
|
||||||
|
lastLine = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ybottom = ytop - 1;
|
||||||
|
ytop = ybottom - pixelsPerLine + 1;
|
||||||
|
if(ytop <= plotAreaTop) {
|
||||||
|
ytop = plotAreaTop;
|
||||||
|
lastLine = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!keepDataBeyondPlotSize && i >= 0) {
|
||||||
|
// not all data could be plotted, drop
|
||||||
|
data.erase(data.begin(), data.begin() + i);
|
||||||
|
updateYAxis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.setClipping(false);
|
||||||
|
|
||||||
if(dropPending) {
|
if(dropPending) {
|
||||||
p.setOpacity(0.5);
|
p.setOpacity(0.5);
|
||||||
p.setBrush(Qt::white);
|
p.setBrush(Qt::white);
|
||||||
@ -279,208 +416,144 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
|
|
||||||
bool TraceWaterfall::supported(Trace *t)
|
bool TraceWaterfall::supported(Trace *t)
|
||||||
{
|
{
|
||||||
// TODO
|
if(!domainMatch(t)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(YAxis.getType()) {
|
||||||
|
case YAxis::Type::Disabled:
|
||||||
|
return false;
|
||||||
|
case YAxis::Type::VSWR:
|
||||||
|
case YAxis::Type::SeriesR:
|
||||||
|
case YAxis::Type::Reactance:
|
||||||
|
case YAxis::Type::Capacitance:
|
||||||
|
case YAxis::Type::Inductance:
|
||||||
|
case YAxis::Type::QualityFactor:
|
||||||
|
if(!t->isReflection()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case YAxis::Type::GroupDelay:
|
||||||
|
if(t->isReflection()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double TraceWaterfall::nearestTracePoint(Trace *t, QPoint pixel, double *distance)
|
double TraceWaterfall::nearestTracePoint(Trace *t, QPoint pixel, double *distance)
|
||||||
{
|
{
|
||||||
// TODO
|
// this function is used for the movement of markers.
|
||||||
|
// No markers on waterfall plot, nothing to do
|
||||||
|
Q_UNUSED(t)
|
||||||
|
Q_UNUSED(pixel)
|
||||||
|
Q_UNUSED(distance)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TraceWaterfall::mouseText(QPoint pos)
|
QString TraceWaterfall::mouseText(QPoint pos)
|
||||||
{
|
{
|
||||||
// TODO
|
QString ret;
|
||||||
return "Test";
|
if(QRect(plotAreaLeft, 0, plotAreaWidth + 1, plotAreaBottom).contains(pos)) {
|
||||||
|
double x = XAxis.inverseTransform(pos.x(), plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||||
|
int significantDigits = floor(log10(abs(XAxis.getRangeMax()))) - floor(log10((abs(XAxis.getRangeMax() - XAxis.getRangeMin())) / 1000.0)) + 1;
|
||||||
|
ret += Unit::ToString(x, XAxis.Unit(), "fpnum kMG", significantDigits) + "\n";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraceWaterfall::xCoordinateVisible(double x)
|
bool TraceWaterfall::markerVisible(double x)
|
||||||
{
|
{
|
||||||
// TODO
|
// no markers on waterfall
|
||||||
return true;
|
Q_UNUSED(x)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWaterfall::updateAxisTicks()
|
void TraceWaterfall::traceDataChanged(unsigned int begin, unsigned int end)
|
||||||
{
|
{
|
||||||
auto createEvenlySpacedTicks = [](vector<double>& ticks, double start, double stop, double step) {
|
if(XAxis.getAutorange()) {
|
||||||
ticks.clear();
|
double min_x = trace->sample(0).x;
|
||||||
if(start > stop) {
|
double max_x = trace->sample(trace->size() - 1).x;
|
||||||
swap(start, stop);
|
if(min_x != XAxis.getRangeMin() || max_x != XAxis.getRangeMax()) {
|
||||||
|
resetWaterfall();
|
||||||
|
// adjust axis
|
||||||
|
XAxis.set(XAxis.getType(), XAxis.getLog(), true, min_x, max_x, 0);
|
||||||
}
|
}
|
||||||
step = abs(step);
|
}
|
||||||
constexpr unsigned int maxTicks = 100;
|
bool YAxisUpdateRequired = false;
|
||||||
for(double tick = start; tick - stop < numeric_limits<double>::epsilon() && ticks.size() <= maxTicks;tick+= step) {
|
if (begin == 0 || data.size() == 0) {
|
||||||
ticks.push_back(tick);
|
if(data.size() == 1) {
|
||||||
|
YAxisUpdateRequired = true;
|
||||||
}
|
}
|
||||||
};
|
// start new row
|
||||||
|
data.push_back(std::vector<Trace::Data>());
|
||||||
auto createAutomaticTicks = [](vector<double>& ticks, double start, double stop, int minDivisions) -> double {
|
while (data.size() > maxDataSweeps) {
|
||||||
Q_ASSERT(stop > start);
|
data.pop_front();
|
||||||
ticks.clear();
|
// min/max might have changed due to removed data
|
||||||
double max_div_step = (stop - start) / minDivisions;
|
YAxisUpdateRequired = true;
|
||||||
int zeros = floor(log10(max_div_step));
|
|
||||||
double decimals_shift = pow(10, zeros);
|
|
||||||
max_div_step /= decimals_shift;
|
|
||||||
if(max_div_step >= 5) {
|
|
||||||
max_div_step = 5;
|
|
||||||
} else if(max_div_step >= 2) {
|
|
||||||
max_div_step = 2;
|
|
||||||
} else {
|
|
||||||
max_div_step = 1;
|
|
||||||
}
|
}
|
||||||
auto div_step = max_div_step * decimals_shift;
|
}
|
||||||
// round min up to next multiple of div_step
|
// grab trace data
|
||||||
auto start_div = ceil(start / div_step) * div_step;
|
data.back().resize(trace->size());
|
||||||
for(double tick = start_div;tick <= stop;tick += div_step) {
|
double min = YAxis.getRangeMin();
|
||||||
ticks.push_back(tick);
|
double max = YAxis.getRangeMax();
|
||||||
}
|
for(unsigned int i=begin;i<end;i++) {
|
||||||
return div_step;
|
data.back()[i] = trace->sample(i);
|
||||||
};
|
if(YAxis.getAutorange() && !YAxisUpdateRequired) {
|
||||||
|
double val = YAxis.sampleToCoordinate(trace->sample(i));
|
||||||
auto createLogarithmicTicks = [](vector<double>& ticks, double start, double stop, int minDivisions) {
|
if(val < min) {
|
||||||
// enforce usable log settings
|
min = val;
|
||||||
if(start <= 0) {
|
}
|
||||||
start = 1.0;
|
if(val > max) {
|
||||||
}
|
max = val;
|
||||||
if(stop <= start) {
|
|
||||||
stop = start + 1.0;
|
|
||||||
}
|
|
||||||
ticks.clear();
|
|
||||||
|
|
||||||
auto decades = log10(stop) - log10(start);
|
|
||||||
double max_div_decade = minDivisions / decades;
|
|
||||||
int zeros = floor(log10(max_div_decade));
|
|
||||||
double decimals_shift = pow(10, zeros);
|
|
||||||
max_div_decade /= decimals_shift;
|
|
||||||
if(max_div_decade < 2) {
|
|
||||||
max_div_decade = 2;
|
|
||||||
} else if(max_div_decade < 5) {
|
|
||||||
max_div_decade = 5;
|
|
||||||
} else {
|
|
||||||
max_div_decade = 10;
|
|
||||||
}
|
|
||||||
auto step = pow(10, floor(log10(start))+1) / (max_div_decade * decimals_shift);
|
|
||||||
// round min up to next multiple of div_step
|
|
||||||
auto div = ceil(start / step) * step;
|
|
||||||
if(floor(log10(div)) != floor(log10(start))) {
|
|
||||||
// first div is already at the next decade
|
|
||||||
step *= 10;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
ticks.push_back(div);
|
|
||||||
if(ticks.size() > 1 && div != step && floor(log10(div)) != floor(log10(div - step))) {
|
|
||||||
// reached a new decade with this switch
|
|
||||||
step *= 10;
|
|
||||||
div = step;
|
|
||||||
} else {
|
|
||||||
div += step;
|
|
||||||
}
|
}
|
||||||
} while(div <= stop);
|
|
||||||
};
|
|
||||||
|
|
||||||
if(XAxis.mode == XAxisMode::Manual) {
|
|
||||||
if(XAxis.log) {
|
|
||||||
createLogarithmicTicks(XAxis.ticks, XAxis.rangeMin, XAxis.rangeMax, 20);
|
|
||||||
} else {
|
|
||||||
createEvenlySpacedTicks(XAxis.ticks, XAxis.rangeMin, XAxis.rangeMax, XAxis.rangeDiv);
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
XAxis.ticks.clear();
|
if(YAxis.getAutorange() && !YAxisUpdateRequired && (min != YAxis.getRangeMin() || max != YAxis.getRangeMax())) {
|
||||||
// automatic mode, figure out limits
|
// axis scaling needs update due to new trace data
|
||||||
double max = std::numeric_limits<double>::lowest();
|
YAxis.set(YAxis.getType(), YAxis.getLog(), true, min, max, 0);
|
||||||
|
} else if(YAxisUpdateRequired) {
|
||||||
|
updateYAxis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceWaterfall::updateYAxis()
|
||||||
|
{
|
||||||
|
if(YAxis.getAutorange()) {
|
||||||
double min = std::numeric_limits<double>::max();
|
double min = std::numeric_limits<double>::max();
|
||||||
if(XAxis.mode == XAxisMode::UseSpan) {
|
double max = std::numeric_limits<double>::lowest();
|
||||||
min = sweep_fmin;
|
for(auto sweep : data) {
|
||||||
max = sweep_fmax;
|
for(unsigned int i=0;i<sweep.size();i++) {
|
||||||
} else if(XAxis.mode == XAxisMode::FitTraces) {
|
double val = YAxis.sampleToCoordinate(sweep[i]);
|
||||||
for(auto t : traces) {
|
if(isnan(val) || isinf(val)) {
|
||||||
bool enabled = t.second;
|
continue;
|
||||||
auto trace = t.first;
|
}
|
||||||
if(enabled && trace->isVisible()) {
|
if(val < min) {
|
||||||
if(!trace->size()) {
|
min = val;
|
||||||
// empty trace, do not use for automatic axis calculation
|
}
|
||||||
continue;
|
if(val > max) {
|
||||||
}
|
max = val;
|
||||||
// this trace is currently displayed
|
|
||||||
double trace_min = trace->minX();
|
|
||||||
double trace_max = trace->maxX();
|
|
||||||
if(XAxis.type == XAxisType::Distance) {
|
|
||||||
trace_min = trace->timeToDistance(trace_min);
|
|
||||||
trace_max = trace->timeToDistance(trace_max);
|
|
||||||
}
|
|
||||||
if(trace_min < min) {
|
|
||||||
min = trace_min;
|
|
||||||
}
|
|
||||||
if(trace_max > max) {
|
|
||||||
max = trace_max;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(min < max) {
|
if(max > min) {
|
||||||
// found min/max values
|
YAxis.set(YAxis.getType(), YAxis.getLog(), true, min, max, 0);
|
||||||
XAxis.rangeMin = min;
|
|
||||||
XAxis.rangeMax = max;
|
|
||||||
if(XAxis.log) {
|
|
||||||
createLogarithmicTicks(XAxis.ticks, XAxis.rangeMin, XAxis.rangeMax, 20);
|
|
||||||
} else {
|
|
||||||
XAxis.rangeDiv = createAutomaticTicks(XAxis.ticks, min, max, 8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TraceWaterfall::AxisTypeToName(TraceWaterfall::XAxisType type)
|
QColor TraceWaterfall::getColor(double scale)
|
||||||
{
|
{
|
||||||
switch(type) {
|
if(scale < 0.0) {
|
||||||
case XAxisType::Frequency: return "Frequency";
|
return Qt::black;
|
||||||
case XAxisType::Time: return "Time";
|
} else if(scale > 1.0) {
|
||||||
case XAxisType::Distance: return "Distance";
|
return Qt::white;
|
||||||
case XAxisType::Power: return "Power";
|
} else if(scale >= 0.0 && scale <= 1.0) {
|
||||||
default: return "Unknown";
|
return QColor::fromHsv(Util::Scale<double>(scale, 0.0, 1.0, 240, 0), 255, 255);
|
||||||
}
|
} else {
|
||||||
}
|
return Qt::black;
|
||||||
|
|
||||||
QString TraceWaterfall::AxisModeToName(TraceWaterfall::XAxisMode mode)
|
|
||||||
{
|
|
||||||
switch(mode) {
|
|
||||||
case XAxisMode::Manual: return "Manual"; break;
|
|
||||||
case XAxisMode::FitTraces: return "Fit Traces"; break;
|
|
||||||
case XAxisMode::UseSpan: return "Use Span"; break;
|
|
||||||
default: return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceWaterfall::XAxisType TraceWaterfall::XAxisTypeFromName(QString name)
|
|
||||||
{
|
|
||||||
for(unsigned int i=0;i<(int) XAxisType::Last;i++) {
|
|
||||||
if(AxisTypeToName((XAxisType) i) == name) {
|
|
||||||
return (XAxisType) i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// not found, use default
|
|
||||||
return XAxisType::Frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceWaterfall::XAxisMode TraceWaterfall::AxisModeFromName(QString name)
|
|
||||||
{
|
|
||||||
for(unsigned int i=0;i<(int) XAxisMode::Last;i++) {
|
|
||||||
if(AxisModeToName((XAxisMode) i) == name) {
|
|
||||||
return (XAxisMode) i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// not found, use default
|
|
||||||
return XAxisMode::UseSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TraceWaterfall::AxisUnit(XAxisType type)
|
|
||||||
{
|
|
||||||
switch(type) {
|
|
||||||
case XAxisType::Frequency: return "Hz";
|
|
||||||
case XAxisType::Time: return "s";
|
|
||||||
case XAxisType::Distance: return "m";
|
|
||||||
case XAxisType::Power: return "dBm";
|
|
||||||
default: return "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,38 +3,25 @@
|
|||||||
|
|
||||||
#include "traceplot.h"
|
#include "traceplot.h"
|
||||||
|
|
||||||
|
#include "traceaxis.h"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
class TraceWaterfall : public TracePlot
|
class TraceWaterfall : public TracePlot
|
||||||
{
|
{
|
||||||
|
friend class WaterfallAxisDialog;
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
TraceWaterfall(TraceModel &model, QWidget *parent = 0);;
|
TraceWaterfall(TraceModel &model, QWidget *parent = 0);;
|
||||||
|
|
||||||
virtual void enableTrace(Trace *t, bool enabled) override;
|
virtual void enableTrace(Trace *t, bool enabled) override;
|
||||||
|
|
||||||
void updateSpan(double min, double max) override;
|
|
||||||
void replot() override;
|
void replot() override;
|
||||||
virtual Type getType() override { return Type::Waterfall;};
|
virtual Type getType() override { return Type::Waterfall;};
|
||||||
|
|
||||||
void fromJSON(nlohmann::json j) override;
|
void fromJSON(nlohmann::json j) override;
|
||||||
nlohmann::json toJSON() override;
|
nlohmann::json toJSON() override;
|
||||||
|
|
||||||
enum class XAxisType {
|
|
||||||
Frequency,
|
|
||||||
Time,
|
|
||||||
Distance,
|
|
||||||
Power,
|
|
||||||
Last,
|
|
||||||
};
|
|
||||||
enum class XAxisMode {
|
|
||||||
UseSpan,
|
|
||||||
FitTraces,
|
|
||||||
Manual,
|
|
||||||
Last,
|
|
||||||
};
|
|
||||||
|
|
||||||
void setXAxis(XAxisType type, XAxisMode mode, bool log, double min, double max, double div);
|
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void axisSetupDialog();
|
void axisSetupDialog();
|
||||||
void resetWaterfall();
|
void resetWaterfall();
|
||||||
@ -43,6 +30,7 @@ protected:
|
|||||||
virtual bool configureForTrace(Trace *t) override;
|
virtual bool configureForTrace(Trace *t) override;
|
||||||
virtual void updateContextMenu() override;
|
virtual void updateContextMenu() override;
|
||||||
virtual void draw(QPainter& p) override;
|
virtual void draw(QPainter& p) override;
|
||||||
|
bool domainMatch(Trace *t);
|
||||||
virtual bool supported(Trace *t) override;
|
virtual bool supported(Trace *t) override;
|
||||||
|
|
||||||
virtual QPoint markerToPixel(Marker *m) override { Q_UNUSED(m) return QPoint(0,0);};
|
virtual QPoint markerToPixel(Marker *m) override { Q_UNUSED(m) return QPoint(0,0);};
|
||||||
@ -51,34 +39,33 @@ protected:
|
|||||||
virtual QString mouseText(QPoint pos) override;
|
virtual QString mouseText(QPoint pos) override;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
virtual bool xCoordinateVisible(double x) override;
|
virtual bool markerVisible(double x) override;
|
||||||
|
void traceDataChanged(unsigned int begin, unsigned int end);
|
||||||
private slots:
|
private slots:
|
||||||
void updateAxisTicks();
|
void updateYAxis();
|
||||||
private:
|
private:
|
||||||
static constexpr int AxisLabelSize = 10;
|
static constexpr int AxisLabelSize = 10;
|
||||||
static QString AxisTypeToName(XAxisType type);
|
|
||||||
static QString AxisModeToName(XAxisMode mode);
|
|
||||||
static XAxisType XAxisTypeFromName(QString name);
|
|
||||||
static XAxisMode AxisModeFromName(QString name);
|
|
||||||
|
|
||||||
static QString AxisUnit(XAxisType type);
|
// color scale, input value from 0.0 to 1.0
|
||||||
|
QColor getColor(double scale);
|
||||||
|
|
||||||
class XAxis {
|
enum class Direction {
|
||||||
public:
|
TopToBottom,
|
||||||
XAxisType type;
|
BottomToTop,
|
||||||
XAxisMode mode;
|
|
||||||
bool log;
|
|
||||||
double rangeMin;
|
|
||||||
double rangeMax;
|
|
||||||
double rangeDiv;
|
|
||||||
std::vector<double> ticks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
XAxis XAxis;
|
Direction dir;
|
||||||
|
|
||||||
std::vector<std::vector<Trace::Data>> data;
|
Trace *trace;
|
||||||
|
|
||||||
|
XAxis XAxis;
|
||||||
|
YAxis YAxis;
|
||||||
|
|
||||||
|
std::deque<std::vector<Trace::Data>> data;
|
||||||
unsigned int pixelsPerLine;
|
unsigned int pixelsPerLine;
|
||||||
int plotAreaLeft, plotAreaWidth, plotAreaBottom, plotAreaTop;
|
int plotAreaLeft, plotAreaWidth, plotAreaBottom, plotAreaTop;
|
||||||
|
bool keepDataBeyondPlotSize;
|
||||||
|
unsigned int maxDataSweeps;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRACEWATERFALL_H
|
#endif // TRACEWATERFALL_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
#define TRACEXYPLOT_H
|
#define TRACEXYPLOT_H
|
||||||
|
|
||||||
#include "traceplot.h"
|
#include "traceplot.h"
|
||||||
|
#include "traceaxis.h"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -12,39 +13,6 @@ class TraceXYPlot : public TracePlot
|
|||||||
public:
|
public:
|
||||||
TraceXYPlot(TraceModel &model, QWidget *parent = nullptr);
|
TraceXYPlot(TraceModel &model, QWidget *parent = nullptr);
|
||||||
|
|
||||||
enum class YAxisType {
|
|
||||||
Disabled,
|
|
||||||
// S parameter options
|
|
||||||
Magnitude,
|
|
||||||
MagnitudedBuV,
|
|
||||||
MagnitudeLinear,
|
|
||||||
Phase,
|
|
||||||
UnwrappedPhase,
|
|
||||||
VSWR,
|
|
||||||
Real,
|
|
||||||
Imaginary,
|
|
||||||
// derived parameter options
|
|
||||||
SeriesR,
|
|
||||||
Reactance,
|
|
||||||
Capacitance,
|
|
||||||
Inductance,
|
|
||||||
QualityFactor,
|
|
||||||
GroupDelay,
|
|
||||||
// TDR options
|
|
||||||
ImpulseReal,
|
|
||||||
ImpulseMag,
|
|
||||||
Step,
|
|
||||||
Impedance,
|
|
||||||
Last,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class XAxisType {
|
|
||||||
Frequency,
|
|
||||||
Time,
|
|
||||||
Distance,
|
|
||||||
Power,
|
|
||||||
Last,
|
|
||||||
};
|
|
||||||
enum class XAxisMode {
|
enum class XAxisMode {
|
||||||
UseSpan,
|
UseSpan,
|
||||||
FitTraces,
|
FitTraces,
|
||||||
@ -52,8 +20,8 @@ public:
|
|||||||
Last,
|
Last,
|
||||||
};
|
};
|
||||||
|
|
||||||
void setYAxis(int axis, YAxisType type, bool log, bool autorange, double min, double max, double div);
|
void setYAxis(int axis, YAxis::Type type, bool log, bool autorange, double min, double max, double div);
|
||||||
void setXAxis(XAxisType type, XAxisMode mode, bool log, double min, double max, double div);
|
void setXAxis(XAxis::Type type, XAxisMode mode, bool log, double min, double max, double div);
|
||||||
void enableTrace(Trace *t, bool enabled) override;
|
void enableTrace(Trace *t, bool enabled) override;
|
||||||
void updateSpan(double min, double max) override;
|
void updateSpan(double min, double max) override;
|
||||||
void replot() override;
|
void replot() override;
|
||||||
@ -62,7 +30,7 @@ public:
|
|||||||
virtual nlohmann::json toJSON() override;
|
virtual nlohmann::json toJSON() override;
|
||||||
virtual void fromJSON(nlohmann::json j) override;
|
virtual void fromJSON(nlohmann::json j) override;
|
||||||
|
|
||||||
bool isTDRtype(YAxisType type);
|
bool isTDRtype(YAxis::Type type);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void axisSetupDialog();
|
void axisSetupDialog();
|
||||||
@ -77,54 +45,26 @@ private slots:
|
|||||||
void updateAxisTicks();
|
void updateAxisTicks();
|
||||||
private:
|
private:
|
||||||
static constexpr int AxisLabelSize = 10;
|
static constexpr int AxisLabelSize = 10;
|
||||||
static QString AxisTypeToName(YAxisType type);
|
|
||||||
static QString AxisTypeToName(XAxisType type);
|
|
||||||
static QString AxisModeToName(XAxisMode mode);
|
static QString AxisModeToName(XAxisMode mode);
|
||||||
static XAxisType XAxisTypeFromName(QString name);
|
|
||||||
static YAxisType YAxisTypeFromName(QString name);
|
|
||||||
static XAxisMode AxisModeFromName(QString name);
|
static XAxisMode AxisModeFromName(QString name);
|
||||||
void enableTraceAxis(Trace *t, int axis, bool enabled);
|
void enableTraceAxis(Trace *t, int axis, bool enabled);
|
||||||
bool domainMatch(Trace *t);
|
bool domainMatch(Trace *t);
|
||||||
bool supported(Trace *t) override;
|
bool supported(Trace *t) override;
|
||||||
bool supported(Trace *t, YAxisType type);
|
bool supported(Trace *t, YAxis::Type type);
|
||||||
QPointF traceToCoordinate(Trace *t, unsigned int sample, YAxisType type);
|
QPointF traceToCoordinate(Trace *t, unsigned int sample, YAxis &yaxis);
|
||||||
QPoint plotValueToPixel(QPointF plotValue, int Yaxis);
|
QPoint plotValueToPixel(QPointF plotValue, int Yaxis);
|
||||||
QPointF pixelToPlotValue(QPoint pixel, int YAxis);
|
QPointF pixelToPlotValue(QPoint pixel, int YAxis);
|
||||||
QPoint markerToPixel(Marker *m) override;
|
QPoint markerToPixel(Marker *m) override;
|
||||||
double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) override;
|
double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) override;
|
||||||
virtual bool xCoordinateVisible(double x) override;
|
virtual bool markerVisible(double x) override;
|
||||||
void traceDropped(Trace *t, QPoint position) override;
|
void traceDropped(Trace *t, QPoint position) override;
|
||||||
QString mouseText(QPoint pos) override;
|
QString mouseText(QPoint pos) override;
|
||||||
|
|
||||||
QString AxisUnit(YAxisType type);
|
|
||||||
QString AxisPrefixes(YAxisType type);
|
|
||||||
static QString AxisUnit(XAxisType type);
|
|
||||||
|
|
||||||
std::set<Trace*> tracesAxis[2];
|
std::set<Trace*> tracesAxis[2];
|
||||||
|
|
||||||
class YAxis {
|
|
||||||
public:
|
|
||||||
YAxisType type;
|
|
||||||
bool log; // not used yet
|
|
||||||
bool autorange;
|
|
||||||
double rangeMin;
|
|
||||||
double rangeMax;
|
|
||||||
double rangeDiv;
|
|
||||||
std::vector<double> ticks;
|
|
||||||
};
|
|
||||||
class XAxis {
|
|
||||||
public:
|
|
||||||
XAxisType type;
|
|
||||||
XAxisMode mode;
|
|
||||||
bool log; // not used yet
|
|
||||||
double rangeMin;
|
|
||||||
double rangeMax;
|
|
||||||
double rangeDiv;
|
|
||||||
std::vector<double> ticks;
|
|
||||||
};
|
|
||||||
|
|
||||||
YAxis YAxis[2];
|
YAxis YAxis[2];
|
||||||
XAxis XAxis;
|
XAxis XAxis;
|
||||||
|
XAxisMode xAxisMode;
|
||||||
|
|
||||||
int plotAreaLeft, plotAreaWidth, plotAreaBottom, plotAreaTop;
|
int plotAreaLeft, plotAreaWidth, plotAreaBottom, plotAreaTop;
|
||||||
};
|
};
|
||||||
|
209
Software/PC_Application/Traces/waterfallaxisdialog.cpp
Normal file
209
Software/PC_Application/Traces/waterfallaxisdialog.cpp
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
#include "waterfallaxisdialog.h"
|
||||||
|
|
||||||
|
#include "ui_waterfallaxisdialog.h"
|
||||||
|
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static void enableComboBoxItem(QComboBox *cb, int itemNum, bool enable) {
|
||||||
|
auto *model = qobject_cast<QStandardItemModel *>(cb->model());
|
||||||
|
auto item = model->item(itemNum);
|
||||||
|
item->setFlags(enable ? item->flags() | Qt::ItemIsEnabled
|
||||||
|
: item->flags() & ~Qt::ItemIsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
WaterfallAxisDialog::WaterfallAxisDialog(TraceWaterfall *plot) :
|
||||||
|
QDialog(nullptr),
|
||||||
|
ui(new Ui::WaterfallAxisDialog),
|
||||||
|
plot(plot)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
ui->Wtype->clear();
|
||||||
|
ui->Wtype->setMaxVisibleItems(20);
|
||||||
|
|
||||||
|
for(int i=0;i<(int) YAxis::Type::Last;i++) {
|
||||||
|
ui->Wtype->addItem(YAxis::TypeToName((YAxis::Type) i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<(int) XAxis::Type::Last;i++) {
|
||||||
|
ui->XType->addItem(XAxis::TypeToName((XAxis::Type) i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(plot->getModel().getSource() == TraceModel::DataSource::SA) {
|
||||||
|
for(int i=0;i<ui->XType->count();i++) {
|
||||||
|
auto xtype = XAxis::TypeFromName(ui->XType->itemText(i));
|
||||||
|
if(!isSupported(xtype)) {
|
||||||
|
enableComboBoxItem(ui->XType, i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup GUI connections
|
||||||
|
connect(ui->Wtype, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) {
|
||||||
|
//ui->Y1log->setEnabled(index != 0);
|
||||||
|
ui->Wlinear->setEnabled(index != 0);
|
||||||
|
ui->Wauto->setEnabled(index != 0);
|
||||||
|
bool autoRange = ui->Wauto->isChecked();
|
||||||
|
ui->Wmin->setEnabled(index != 0 && !autoRange);
|
||||||
|
ui->Wmax->setEnabled(index != 0 && !autoRange);
|
||||||
|
auto type = (YAxis::Type) index;
|
||||||
|
QString unit = YAxis::Unit(type);
|
||||||
|
QString prefixes = YAxis::Prefixes(type);
|
||||||
|
ui->Wmin->setUnit(unit);
|
||||||
|
ui->Wmin->setPrefixes(prefixes);
|
||||||
|
ui->Wmax->setUnit(unit);
|
||||||
|
ui->Wmax->setPrefixes(prefixes);
|
||||||
|
});
|
||||||
|
connect(ui->Wauto, &QCheckBox::toggled, [this](bool checked) {
|
||||||
|
ui->Wmin->setEnabled(!checked);
|
||||||
|
ui->Wmax->setEnabled(!checked);
|
||||||
|
});
|
||||||
|
connect(ui->Wmode, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
|
||||||
|
ui->WmaxSweeps->setEnabled(index == 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
ui->XType->setCurrentIndex((int) plot->XAxis.getType());
|
||||||
|
|
||||||
|
ui->Wmin->setPrefixes("pnum kMG");
|
||||||
|
ui->Wmax->setPrefixes("pnum kMG");
|
||||||
|
|
||||||
|
XAxisTypeChanged((int) plot->XAxis.getType());
|
||||||
|
connect(ui->XType, qOverload<int>(&QComboBox::currentIndexChanged), this, &WaterfallAxisDialog::XAxisTypeChanged);
|
||||||
|
|
||||||
|
// Fill initial values
|
||||||
|
ui->Wtype->setCurrentIndex((int) plot->YAxis.getType());
|
||||||
|
if(plot->YAxis.getLog()) {
|
||||||
|
ui->Wlog->setChecked(true);
|
||||||
|
} else {
|
||||||
|
ui->Wlinear->setChecked(true);
|
||||||
|
}
|
||||||
|
ui->Wauto->setChecked(plot->YAxis.getAutorange());
|
||||||
|
ui->Wmin->setValueQuiet(plot->YAxis.getRangeMin());
|
||||||
|
ui->Wmax->setValueQuiet(plot->YAxis.getRangeMax());
|
||||||
|
if(plot->dir == TraceWaterfall::Direction::TopToBottom) {
|
||||||
|
ui->Wdir->setCurrentIndex(0);
|
||||||
|
} else {
|
||||||
|
ui->Wdir->setCurrentIndex(1);
|
||||||
|
}
|
||||||
|
ui->Wpixels->setValue(plot->pixelsPerLine);
|
||||||
|
ui->Wmode->setCurrentIndex(plot->keepDataBeyondPlotSize ? 1 : 0);
|
||||||
|
ui->WmaxSweeps->setValue(plot->maxDataSweeps);
|
||||||
|
|
||||||
|
if(plot->XAxis.getLog()) {
|
||||||
|
ui->Xlog->setChecked(true);
|
||||||
|
} else {
|
||||||
|
ui->Xlinear->setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WaterfallAxisDialog::~WaterfallAxisDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallAxisDialog::on_buttonBox_accepted()
|
||||||
|
{
|
||||||
|
// set plot values to the ones selected in the dialog
|
||||||
|
plot->XAxis.set(plot->XAxis.getType(), ui->Xlog->isChecked(), true, plot->XAxis.getRangeMin(), plot->XAxis.getRangeMax(), 0);
|
||||||
|
plot->YAxis.set((YAxis::Type) ui->Wtype->currentIndex(), ui->Wlog->isChecked(), ui->Wauto->isChecked(), ui->Wmin->value(), ui->Wmax->value(), 2);
|
||||||
|
if(ui->Wdir->currentIndex() == 0) {
|
||||||
|
plot->dir = TraceWaterfall::Direction::TopToBottom;
|
||||||
|
} else {
|
||||||
|
plot->dir = TraceWaterfall::Direction::BottomToTop;
|
||||||
|
}
|
||||||
|
plot->pixelsPerLine = ui->Wpixels->value();
|
||||||
|
plot->maxDataSweeps = ui->WmaxSweeps->value();
|
||||||
|
if(ui->Wmode->currentIndex() == 0) {
|
||||||
|
plot->keepDataBeyondPlotSize = false;
|
||||||
|
} else {
|
||||||
|
plot->keepDataBeyondPlotSize = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
||||||
|
{
|
||||||
|
auto type = (XAxis::Type) XAxisIndex;
|
||||||
|
auto supported = supportedYAxis(type);
|
||||||
|
for(unsigned int i=0;i<(int) YAxis::Type::Last;i++) {
|
||||||
|
auto t = (YAxis::Type) i;
|
||||||
|
auto enable = supported.count(t) > 0;
|
||||||
|
auto index = (int) t;
|
||||||
|
enableComboBoxItem(ui->Wtype, index, enable);
|
||||||
|
}
|
||||||
|
// Disable Yaxis if previously selected type is not supported
|
||||||
|
if(!supported.count((YAxis::Type)ui->Wtype->currentIndex())) {
|
||||||
|
ui->Wtype->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == XAxis::Type::Frequency) {
|
||||||
|
ui->Xlog->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
// log option only available for frequency axis
|
||||||
|
if(ui->Xlog->isChecked()) {
|
||||||
|
ui->Xlinear->setChecked(true);
|
||||||
|
}
|
||||||
|
ui->Xlog->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<YAxis::Type> WaterfallAxisDialog::supportedYAxis(XAxis::Type type)
|
||||||
|
{
|
||||||
|
set<YAxis::Type> ret = {YAxis::Type::Disabled};
|
||||||
|
auto source = plot->getModel().getSource();
|
||||||
|
if(source == TraceModel::DataSource::VNA) {
|
||||||
|
switch(type) {
|
||||||
|
case XAxis::Type::Frequency:
|
||||||
|
case XAxis::Type::Power:
|
||||||
|
ret.insert(YAxis::Type::Magnitude);
|
||||||
|
ret.insert(YAxis::Type::MagnitudeLinear);
|
||||||
|
ret.insert(YAxis::Type::Phase);
|
||||||
|
ret.insert(YAxis::Type::UnwrappedPhase);
|
||||||
|
ret.insert(YAxis::Type::VSWR);
|
||||||
|
ret.insert(YAxis::Type::Real);
|
||||||
|
ret.insert(YAxis::Type::Imaginary);
|
||||||
|
ret.insert(YAxis::Type::SeriesR);
|
||||||
|
ret.insert(YAxis::Type::Reactance);
|
||||||
|
ret.insert(YAxis::Type::Capacitance);
|
||||||
|
ret.insert(YAxis::Type::Inductance);
|
||||||
|
ret.insert(YAxis::Type::QualityFactor);
|
||||||
|
ret.insert(YAxis::Type::GroupDelay);
|
||||||
|
break;
|
||||||
|
case XAxis::Type::Time:
|
||||||
|
case XAxis::Type::Distance:
|
||||||
|
ret.insert(YAxis::Type::ImpulseReal);
|
||||||
|
ret.insert(YAxis::Type::ImpulseMag);
|
||||||
|
ret.insert(YAxis::Type::Step);
|
||||||
|
ret.insert(YAxis::Type::Impedance);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(source == TraceModel::DataSource::SA) {
|
||||||
|
switch(type) {
|
||||||
|
case XAxis::Type::Frequency:
|
||||||
|
ret.insert(YAxis::Type::Magnitude);
|
||||||
|
ret.insert(YAxis::Type::MagnitudedBuV);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaterfallAxisDialog::isSupported(XAxis::Type type)
|
||||||
|
{
|
||||||
|
auto source = plot->getModel().getSource();
|
||||||
|
if(source == TraceModel::DataSource::VNA) {
|
||||||
|
// all X axis types are supported
|
||||||
|
return true;
|
||||||
|
} else if(source == TraceModel::DataSource::SA) {
|
||||||
|
if (type == XAxis::Type::Frequency) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
31
Software/PC_Application/Traces/waterfallaxisdialog.h
Normal file
31
Software/PC_Application/Traces/waterfallaxisdialog.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef WATERFALLAXISDIALOG_H
|
||||||
|
#define WATERFALLAXISDIALOG_H
|
||||||
|
|
||||||
|
#include "tracewaterfall.h"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class WaterfallAxisDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WaterfallAxisDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit WaterfallAxisDialog(TraceWaterfall *plot);
|
||||||
|
~WaterfallAxisDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_buttonBox_accepted();
|
||||||
|
void XAxisTypeChanged(int XAxisIndex);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<YAxis::Type> supportedYAxis(XAxis::Type type);
|
||||||
|
bool isSupported(XAxis::Type type);
|
||||||
|
Ui::WaterfallAxisDialog *ui;
|
||||||
|
TraceWaterfall *plot;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WATERFALLAXISDIALOG_H
|
378
Software/PC_Application/Traces/waterfallaxisdialog.ui
Normal file
378
Software/PC_Application/Traces/waterfallaxisdialog.ui
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>WaterfallAxisDialog</class>
|
||||||
|
<widget class="QDialog" name="WaterfallAxisDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::NonModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>539</width>
|
||||||
|
<height>351</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Axis Setup</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>15</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Waterfall</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Type:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="Wtype"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="Wlinear">
|
||||||
|
<property name="text">
|
||||||
|
<string>Linear</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">Y1group</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="Wlog">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Log</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">Y1group</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Range:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Maximum:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="Wmax"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Minimum:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="Wmin"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Direction:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QCheckBox" name="Wauto">
|
||||||
|
<property name="text">
|
||||||
|
<string>Auto</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QComboBox" name="Wdir">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Top to bottom</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Bottom to top</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pixels per line:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QSpinBox" name="Wpixels">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QComboBox" name="Wmode">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Only keep visible data</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Keep offscreen data</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number of sweeps:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QSpinBox" name="WmaxSweeps">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>15</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>X axis</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_5">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>Type:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="XType">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_7">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="Xlinear">
|
||||||
|
<property name="text">
|
||||||
|
<string>Linear</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">Xgroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="Xlog">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Log</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">Xgroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<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>
|
||||||
|
<widget class="Line" name="line_8">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>SIUnitEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>CustomWidgets/siunitedit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>WaterfallAxisDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>WaterfallAxisDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
<buttongroups>
|
||||||
|
<buttongroup name="Y1group"/>
|
||||||
|
<buttongroup name="Y2group"/>
|
||||||
|
<buttongroup name="Xgroup"/>
|
||||||
|
</buttongroups>
|
||||||
|
</ui>
|
@ -24,18 +24,18 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Y1type->setMaxVisibleItems(20);
|
ui->Y1type->setMaxVisibleItems(20);
|
||||||
ui->Y2type->setMaxVisibleItems(20);
|
ui->Y2type->setMaxVisibleItems(20);
|
||||||
|
|
||||||
for(int i=0;i<(int) TraceXYPlot::YAxisType::Last;i++) {
|
for(int i=0;i<(int) YAxis::Type::Last;i++) {
|
||||||
ui->Y1type->addItem(TraceXYPlot::AxisTypeToName((TraceXYPlot::YAxisType) i));
|
ui->Y1type->addItem(YAxis::TypeToName((YAxis::Type) i));
|
||||||
ui->Y2type->addItem(TraceXYPlot::AxisTypeToName((TraceXYPlot::YAxisType) i));
|
ui->Y2type->addItem(YAxis::TypeToName((YAxis::Type) i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i=0;i<(int) TraceXYPlot::XAxisType::Last;i++) {
|
for(int i=0;i<(int) XAxis::Type::Last;i++) {
|
||||||
ui->XType->addItem(TraceXYPlot::AxisTypeToName((TraceXYPlot::XAxisType) i));
|
ui->XType->addItem(XAxis::TypeToName((XAxis::Type) i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plot->getModel().getSource() == TraceModel::DataSource::SA) {
|
if(plot->getModel().getSource() == TraceModel::DataSource::SA) {
|
||||||
for(int i=0;i<ui->XType->count();i++) {
|
for(int i=0;i<ui->XType->count();i++) {
|
||||||
auto xtype = TraceXYPlot::XAxisTypeFromName(ui->XType->itemText(i));
|
auto xtype = XAxis::TypeFromName(ui->XType->itemText(i));
|
||||||
if(!isSupported(xtype)) {
|
if(!isSupported(xtype)) {
|
||||||
enableComboBoxItem(ui->XType, i, false);
|
enableComboBoxItem(ui->XType, i, false);
|
||||||
}
|
}
|
||||||
@ -51,9 +51,9 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Y1min->setEnabled(index != 0 && !autoRange);
|
ui->Y1min->setEnabled(index != 0 && !autoRange);
|
||||||
ui->Y1max->setEnabled(index != 0 && !autoRange);
|
ui->Y1max->setEnabled(index != 0 && !autoRange);
|
||||||
ui->Y1divs->setEnabled(index != 0 && !autoRange);
|
ui->Y1divs->setEnabled(index != 0 && !autoRange);
|
||||||
auto type = (TraceXYPlot::YAxisType) index;
|
auto type = (YAxis::Type) index;
|
||||||
QString unit = plot->AxisUnit(type);
|
QString unit = YAxis::Unit(type);
|
||||||
QString prefixes = plot->AxisPrefixes(type);
|
QString prefixes = YAxis::Prefixes(type);
|
||||||
ui->Y1min->setUnit(unit);
|
ui->Y1min->setUnit(unit);
|
||||||
ui->Y1min->setPrefixes(prefixes);
|
ui->Y1min->setPrefixes(prefixes);
|
||||||
ui->Y1max->setUnit(unit);
|
ui->Y1max->setUnit(unit);
|
||||||
@ -75,9 +75,9 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Y2min->setEnabled(index != 0 && !autoRange);
|
ui->Y2min->setEnabled(index != 0 && !autoRange);
|
||||||
ui->Y2max->setEnabled(index != 0 && !autoRange);
|
ui->Y2max->setEnabled(index != 0 && !autoRange);
|
||||||
ui->Y2divs->setEnabled(index != 0 && !autoRange);
|
ui->Y2divs->setEnabled(index != 0 && !autoRange);
|
||||||
auto type = (TraceXYPlot::YAxisType) index;
|
auto type = (YAxis::Type) index;
|
||||||
QString unit = plot->AxisUnit(type);
|
QString unit = YAxis::Unit(type);
|
||||||
QString prefixes = plot->AxisPrefixes(type);
|
QString prefixes = YAxis::Prefixes(type);
|
||||||
ui->Y2min->setUnit(unit);
|
ui->Y2min->setUnit(unit);
|
||||||
ui->Y2min->setPrefixes(prefixes);
|
ui->Y2min->setPrefixes(prefixes);
|
||||||
ui->Y2max->setUnit(unit);
|
ui->Y2max->setUnit(unit);
|
||||||
@ -99,7 +99,7 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Xautomode->setEnabled(checked);
|
ui->Xautomode->setEnabled(checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
ui->XType->setCurrentIndex((int) plot->XAxis.type);
|
ui->XType->setCurrentIndex((int) plot->XAxis.getType());
|
||||||
ui->Xmin->setPrefixes("pnum kMG");
|
ui->Xmin->setPrefixes("pnum kMG");
|
||||||
ui->Xmax->setPrefixes("pnum kMG");
|
ui->Xmax->setPrefixes("pnum kMG");
|
||||||
ui->Xdivs->setPrefixes("pnum kMG");
|
ui->Xdivs->setPrefixes("pnum kMG");
|
||||||
@ -112,49 +112,49 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Y2max->setPrefixes("pnum kMG");
|
ui->Y2max->setPrefixes("pnum kMG");
|
||||||
ui->Y2divs->setPrefixes("pnum kMG");
|
ui->Y2divs->setPrefixes("pnum kMG");
|
||||||
|
|
||||||
XAxisTypeChanged((int) plot->XAxis.type);
|
XAxisTypeChanged((int) plot->XAxis.getType());
|
||||||
connect(ui->XType, qOverload<int>(&QComboBox::currentIndexChanged), this, &XYplotAxisDialog::XAxisTypeChanged);
|
connect(ui->XType, qOverload<int>(&QComboBox::currentIndexChanged), this, &XYplotAxisDialog::XAxisTypeChanged);
|
||||||
connect(ui->Xlog, &QCheckBox::toggled, [=](bool checked){
|
connect(ui->Xlog, &QCheckBox::toggled, [=](bool checked){
|
||||||
ui->Xdivs->setEnabled(!checked && !ui->Xauto->isChecked());
|
ui->Xdivs->setEnabled(!checked && !ui->Xauto->isChecked());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fill initial values
|
// Fill initial values
|
||||||
ui->Y1type->setCurrentIndex((int) plot->YAxis[0].type);
|
ui->Y1type->setCurrentIndex((int) plot->YAxis[0].getType());
|
||||||
if(plot->YAxis[0].log) {
|
if(plot->YAxis[0].getLog()) {
|
||||||
ui->Y1log->setChecked(true);
|
ui->Y1log->setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
ui->Y1linear->setChecked(true);
|
ui->Y1linear->setChecked(true);
|
||||||
}
|
}
|
||||||
ui->Y1auto->setChecked(plot->YAxis[0].autorange);
|
ui->Y1auto->setChecked(plot->YAxis[0].getAutorange());
|
||||||
ui->Y1min->setValueQuiet(plot->YAxis[0].rangeMin);
|
ui->Y1min->setValueQuiet(plot->YAxis[0].getRangeMin());
|
||||||
ui->Y1max->setValueQuiet(plot->YAxis[0].rangeMax);
|
ui->Y1max->setValueQuiet(plot->YAxis[0].getRangeMax());
|
||||||
ui->Y1divs->setValueQuiet(plot->YAxis[0].rangeDiv);
|
ui->Y1divs->setValueQuiet(plot->YAxis[0].getRangeDiv());
|
||||||
|
|
||||||
ui->Y2type->setCurrentIndex((int) plot->YAxis[1].type);
|
ui->Y2type->setCurrentIndex((int) plot->YAxis[1].getType());
|
||||||
if(plot->YAxis[1].log) {
|
if(plot->YAxis[1].getLog()) {
|
||||||
ui->Y2log->setChecked(true);
|
ui->Y2log->setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
ui->Y2linear->setChecked(true);
|
ui->Y2linear->setChecked(true);
|
||||||
}
|
}
|
||||||
ui->Y2auto->setChecked(plot->YAxis[1].autorange);
|
ui->Y2auto->setChecked(plot->YAxis[1].getAutorange());
|
||||||
ui->Y2min->setValueQuiet(plot->YAxis[1].rangeMin);
|
ui->Y2min->setValueQuiet(plot->YAxis[1].getRangeMin());
|
||||||
ui->Y2max->setValueQuiet(plot->YAxis[1].rangeMax);
|
ui->Y2max->setValueQuiet(plot->YAxis[1].getRangeMax());
|
||||||
ui->Y2divs->setValueQuiet(plot->YAxis[1].rangeDiv);
|
ui->Y2divs->setValueQuiet(plot->YAxis[1].getRangeDiv());
|
||||||
|
|
||||||
if(plot->XAxis.log) {
|
if(plot->XAxis.getLog()) {
|
||||||
ui->Xlog->setChecked(true);
|
ui->Xlog->setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
ui->Xlinear->setChecked(true);
|
ui->Xlinear->setChecked(true);
|
||||||
}
|
}
|
||||||
ui->Xauto->setChecked(plot->XAxis.mode != TraceXYPlot::XAxisMode::Manual);
|
ui->Xauto->setChecked(plot->xAxisMode != TraceXYPlot::XAxisMode::Manual);
|
||||||
if(plot->XAxis.mode == TraceXYPlot::XAxisMode::UseSpan) {
|
if(plot->xAxisMode == TraceXYPlot::XAxisMode::UseSpan) {
|
||||||
ui->Xautomode->setCurrentIndex(0);
|
ui->Xautomode->setCurrentIndex(0);
|
||||||
} else {
|
} else {
|
||||||
ui->Xautomode->setCurrentIndex(1);
|
ui->Xautomode->setCurrentIndex(1);
|
||||||
}
|
}
|
||||||
ui->Xmin->setValueQuiet(plot->XAxis.rangeMin);
|
ui->Xmin->setValueQuiet(plot->XAxis.getRangeMin());
|
||||||
ui->Xmax->setValueQuiet(plot->XAxis.rangeMax);
|
ui->Xmax->setValueQuiet(plot->XAxis.getRangeMax());
|
||||||
ui->Xdivs->setValueQuiet(plot->XAxis.rangeDiv);
|
ui->Xdivs->setValueQuiet(plot->XAxis.getRangeDiv());
|
||||||
}
|
}
|
||||||
|
|
||||||
XYplotAxisDialog::~XYplotAxisDialog()
|
XYplotAxisDialog::~XYplotAxisDialog()
|
||||||
@ -165,8 +165,8 @@ XYplotAxisDialog::~XYplotAxisDialog()
|
|||||||
void XYplotAxisDialog::on_buttonBox_accepted()
|
void XYplotAxisDialog::on_buttonBox_accepted()
|
||||||
{
|
{
|
||||||
// set plot values to the ones selected in the dialog
|
// set plot values to the ones selected in the dialog
|
||||||
plot->setYAxis(0, (TraceXYPlot::YAxisType) ui->Y1type->currentIndex(), ui->Y1log->isChecked(), ui->Y1auto->isChecked(), ui->Y1min->value(), ui->Y1max->value(), ui->Y1divs->value());
|
plot->setYAxis(0, (YAxis::Type) ui->Y1type->currentIndex(), ui->Y1log->isChecked(), ui->Y1auto->isChecked(), ui->Y1min->value(), ui->Y1max->value(), ui->Y1divs->value());
|
||||||
plot->setYAxis(1, (TraceXYPlot::YAxisType) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2divs->value());
|
plot->setYAxis(1, (YAxis::Type) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2divs->value());
|
||||||
TraceXYPlot::XAxisMode mode;
|
TraceXYPlot::XAxisMode mode;
|
||||||
if(ui->Xauto->isChecked()) {
|
if(ui->Xauto->isChecked()) {
|
||||||
if(ui->Xautomode->currentIndex() == 0) {
|
if(ui->Xautomode->currentIndex() == 0) {
|
||||||
@ -177,29 +177,29 @@ void XYplotAxisDialog::on_buttonBox_accepted()
|
|||||||
} else {
|
} else {
|
||||||
mode = TraceXYPlot::XAxisMode::Manual;
|
mode = TraceXYPlot::XAxisMode::Manual;
|
||||||
}
|
}
|
||||||
plot->setXAxis((TraceXYPlot::XAxisType) ui->XType->currentIndex(), mode, ui->Xlog->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
plot->setXAxis((XAxis::Type) ui->XType->currentIndex(), mode, ui->Xlog->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
||||||
{
|
{
|
||||||
auto type = (TraceXYPlot::XAxisType) XAxisIndex;
|
auto type = (XAxis::Type) XAxisIndex;
|
||||||
auto supported = supportedYAxis(type);
|
auto supported = supportedYAxis(type);
|
||||||
for(unsigned int i=0;i<(int) TraceXYPlot::YAxisType::Last;i++) {
|
for(unsigned int i=0;i<(int) YAxis::Type::Last;i++) {
|
||||||
auto t = (TraceXYPlot::YAxisType) i;
|
auto t = (YAxis::Type) i;
|
||||||
auto enable = supported.count(t) > 0;
|
auto enable = supported.count(t) > 0;
|
||||||
auto index = (int) t;
|
auto index = (int) t;
|
||||||
enableComboBoxItem(ui->Y1type, index, enable);
|
enableComboBoxItem(ui->Y1type, index, enable);
|
||||||
enableComboBoxItem(ui->Y2type, index, enable);
|
enableComboBoxItem(ui->Y2type, index, enable);
|
||||||
}
|
}
|
||||||
// Disable Yaxis if previously selected type is not supported
|
// Disable Yaxis if previously selected type is not supported
|
||||||
if(!supported.count((TraceXYPlot::YAxisType)ui->Y1type->currentIndex())) {
|
if(!supported.count((YAxis::Type)ui->Y1type->currentIndex())) {
|
||||||
ui->Y1type->setCurrentIndex(0);
|
ui->Y1type->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
if(!supported.count((TraceXYPlot::YAxisType)ui->Y2type->currentIndex())) {
|
if(!supported.count((YAxis::Type)ui->Y2type->currentIndex())) {
|
||||||
ui->Y2type->setCurrentIndex(0);
|
ui->Y2type->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type == TraceXYPlot::XAxisType::Frequency) {
|
if(type == XAxis::Type::Frequency) {
|
||||||
enableComboBoxItem(ui->Xautomode, 0, true);
|
enableComboBoxItem(ui->Xautomode, 0, true);
|
||||||
ui->Xlog->setEnabled(true);
|
ui->Xlog->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
@ -215,49 +215,49 @@ void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
|||||||
ui->Xlog->setEnabled(false);
|
ui->Xlog->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString unit = TraceXYPlot::AxisUnit(type);
|
QString unit = XAxis::Unit(type);
|
||||||
ui->Xmin->setUnit(unit);
|
ui->Xmin->setUnit(unit);
|
||||||
ui->Xmax->setUnit(unit);
|
ui->Xmax->setUnit(unit);
|
||||||
ui->Xdivs->setUnit(unit);
|
ui->Xdivs->setUnit(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<TraceXYPlot::YAxisType> XYplotAxisDialog::supportedYAxis(TraceXYPlot::XAxisType type)
|
std::set<YAxis::Type> XYplotAxisDialog::supportedYAxis(XAxis::Type type)
|
||||||
{
|
{
|
||||||
set<TraceXYPlot::YAxisType> ret = {TraceXYPlot::YAxisType::Disabled};
|
set<YAxis::Type> ret = {YAxis::Type::Disabled};
|
||||||
auto source = plot->getModel().getSource();
|
auto source = plot->getModel().getSource();
|
||||||
if(source == TraceModel::DataSource::VNA) {
|
if(source == TraceModel::DataSource::VNA) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case TraceXYPlot::XAxisType::Frequency:
|
case XAxis::Type::Frequency:
|
||||||
case TraceXYPlot::XAxisType::Power:
|
case XAxis::Type::Power:
|
||||||
ret.insert(TraceXYPlot::YAxisType::Magnitude);
|
ret.insert(YAxis::Type::Magnitude);
|
||||||
ret.insert(TraceXYPlot::YAxisType::MagnitudeLinear);
|
ret.insert(YAxis::Type::MagnitudeLinear);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Phase);
|
ret.insert(YAxis::Type::Phase);
|
||||||
ret.insert(TraceXYPlot::YAxisType::UnwrappedPhase);
|
ret.insert(YAxis::Type::UnwrappedPhase);
|
||||||
ret.insert(TraceXYPlot::YAxisType::VSWR);
|
ret.insert(YAxis::Type::VSWR);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Real);
|
ret.insert(YAxis::Type::Real);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Imaginary);
|
ret.insert(YAxis::Type::Imaginary);
|
||||||
ret.insert(TraceXYPlot::YAxisType::SeriesR);
|
ret.insert(YAxis::Type::SeriesR);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Reactance);
|
ret.insert(YAxis::Type::Reactance);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Capacitance);
|
ret.insert(YAxis::Type::Capacitance);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Inductance);
|
ret.insert(YAxis::Type::Inductance);
|
||||||
ret.insert(TraceXYPlot::YAxisType::QualityFactor);
|
ret.insert(YAxis::Type::QualityFactor);
|
||||||
ret.insert(TraceXYPlot::YAxisType::GroupDelay);
|
ret.insert(YAxis::Type::GroupDelay);
|
||||||
break;
|
break;
|
||||||
case TraceXYPlot::XAxisType::Time:
|
case XAxis::Type::Time:
|
||||||
case TraceXYPlot::XAxisType::Distance:
|
case XAxis::Type::Distance:
|
||||||
ret.insert(TraceXYPlot::YAxisType::ImpulseReal);
|
ret.insert(YAxis::Type::ImpulseReal);
|
||||||
ret.insert(TraceXYPlot::YAxisType::ImpulseMag);
|
ret.insert(YAxis::Type::ImpulseMag);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Step);
|
ret.insert(YAxis::Type::Step);
|
||||||
ret.insert(TraceXYPlot::YAxisType::Impedance);
|
ret.insert(YAxis::Type::Impedance);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(source == TraceModel::DataSource::SA) {
|
} else if(source == TraceModel::DataSource::SA) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case TraceXYPlot::XAxisType::Frequency:
|
case XAxis::Type::Frequency:
|
||||||
ret.insert(TraceXYPlot::YAxisType::Magnitude);
|
ret.insert(YAxis::Type::Magnitude);
|
||||||
ret.insert(TraceXYPlot::YAxisType::MagnitudedBuV);
|
ret.insert(YAxis::Type::MagnitudedBuV);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -266,14 +266,14 @@ std::set<TraceXYPlot::YAxisType> XYplotAxisDialog::supportedYAxis(TraceXYPlot::X
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XYplotAxisDialog::isSupported(TraceXYPlot::XAxisType type)
|
bool XYplotAxisDialog::isSupported(XAxis::Type type)
|
||||||
{
|
{
|
||||||
auto source = plot->getModel().getSource();
|
auto source = plot->getModel().getSource();
|
||||||
if(source == TraceModel::DataSource::VNA) {
|
if(source == TraceModel::DataSource::VNA) {
|
||||||
// all X axis types are supported
|
// all X axis types are supported
|
||||||
return true;
|
return true;
|
||||||
} else if(source == TraceModel::DataSource::SA) {
|
} else if(source == TraceModel::DataSource::SA) {
|
||||||
if (type == TraceXYPlot::XAxisType::Frequency) {
|
if (type == XAxis::Type::Frequency) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -22,8 +22,8 @@ private slots:
|
|||||||
void XAxisTypeChanged(int XAxisIndex);
|
void XAxisTypeChanged(int XAxisIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<TraceXYPlot::YAxisType> supportedYAxis(TraceXYPlot::XAxisType type);
|
std::set<YAxis::Type> supportedYAxis(XAxis::Type type);
|
||||||
bool isSupported(TraceXYPlot::XAxisType type);
|
bool isSupported(XAxis::Type type);
|
||||||
Ui::XYplotAxisDialog *ui;
|
Ui::XYplotAxisDialog *ui;
|
||||||
TraceXYPlot *plot;
|
TraceXYPlot *plot;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user