Autoscale improvements
This commit is contained in:
parent
3976db8f9d
commit
32270dc747
@ -130,7 +130,9 @@ void TileWidget::on_bSmithchart_clicked()
|
|||||||
|
|
||||||
void TileWidget::on_bXYplot_clicked()
|
void TileWidget::on_bXYplot_clicked()
|
||||||
{
|
{
|
||||||
setContent(new TraceXYPlot(model));
|
auto plot = new TraceXYPlot(model);
|
||||||
|
setContent(plot);
|
||||||
|
plot->axisSetupDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileWidget::traceDeleted(TracePlot *)
|
void TileWidget::traceDeleted(TracePlot *)
|
||||||
|
@ -18,6 +18,7 @@ MarkerWidget::MarkerWidget(TraceMarkerModel &model, QWidget *parent) :
|
|||||||
|
|
||||||
connect(&model.getModel(), &TraceModel::traceAdded, this, &MarkerWidget::updatePersistentEditors);
|
connect(&model.getModel(), &TraceModel::traceAdded, this, &MarkerWidget::updatePersistentEditors);
|
||||||
connect(&model.getModel(), &TraceModel::traceRemoved, this, &MarkerWidget::updatePersistentEditors);
|
connect(&model.getModel(), &TraceModel::traceRemoved, this, &MarkerWidget::updatePersistentEditors);
|
||||||
|
connect(&model.getModel(), &TraceModel::traceNameChanged, this, &MarkerWidget::updatePersistentEditors);
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkerWidget::~MarkerWidget()
|
MarkerWidget::~MarkerWidget()
|
||||||
|
@ -156,16 +156,22 @@ void Trace::updateTimeDomainData()
|
|||||||
// system_clock::now().time_since_epoch()
|
// system_clock::now().time_since_epoch()
|
||||||
// ).count();
|
// ).count();
|
||||||
auto steps = size();
|
auto steps = size();
|
||||||
if(minFreq() * size() != maxFreq()) {
|
auto firstStep = minFreq();
|
||||||
|
if(firstStep == 0) {
|
||||||
|
// zero as first step would result in infinite number of points, skip and start with second
|
||||||
|
firstStep = _data[1].frequency;
|
||||||
|
steps--;
|
||||||
|
}
|
||||||
|
if(firstStep * steps != maxFreq()) {
|
||||||
// data is not available with correct frequency spacing, calculate required steps
|
// data is not available with correct frequency spacing, calculate required steps
|
||||||
steps = maxFreq() / minFreq();
|
steps = maxFreq() / firstStep;
|
||||||
}
|
}
|
||||||
const double PI = 3.141592653589793238463;
|
const double PI = 3.141592653589793238463;
|
||||||
// reserve vector for negative frequenies and DC as well
|
// reserve vector for negative frequenies and DC as well
|
||||||
vector<complex<double>> frequencyDomain(2*steps + 1);
|
vector<complex<double>> frequencyDomain(2*steps + 1);
|
||||||
// copy frequencies, use the flipped conjugate for negative part
|
// copy frequencies, use the flipped conjugate for negative part
|
||||||
for(unsigned int i = 1;i<=steps;i++) {
|
for(unsigned int i = 1;i<=steps;i++) {
|
||||||
auto S = getData(minFreq() * i);
|
auto S = getData(firstStep * i);
|
||||||
constexpr double alpha0 = 0.54;
|
constexpr double alpha0 = 0.54;
|
||||||
auto hamming = alpha0 - (1.0 - alpha0) * -cos(PI * i / steps);
|
auto hamming = alpha0 - (1.0 - alpha0) * -cos(PI * i / steps);
|
||||||
S *= hamming;
|
S *= hamming;
|
||||||
@ -180,13 +186,18 @@ void Trace::updateTimeDomainData()
|
|||||||
auto fft_bins = frequencyDomain.size();
|
auto fft_bins = frequencyDomain.size();
|
||||||
timeDomain.clear();
|
timeDomain.clear();
|
||||||
timeDomain.resize(fft_bins);
|
timeDomain.resize(fft_bins);
|
||||||
const double fs = 1.0 / (minFreq() * fft_bins);
|
const double fs = 1.0 / (firstStep * fft_bins);
|
||||||
double last_step = 0.0;
|
double last_step = 0.0;
|
||||||
|
|
||||||
Fft::transform(frequencyDomain, true);
|
Fft::transform(frequencyDomain, true);
|
||||||
|
constexpr double c = 299792458;
|
||||||
for(unsigned int i = 0;i<fft_bins;i++) {
|
for(unsigned int i = 0;i<fft_bins;i++) {
|
||||||
TimedomainData t;
|
TimedomainData t;
|
||||||
t.time = fs * i;
|
t.time = fs * i;
|
||||||
|
t.distance = t.time * c * 0.66; // TODO user settable velocity factor
|
||||||
|
if(isReflection()) {
|
||||||
|
t.distance /= 2;
|
||||||
|
}
|
||||||
t.impulseResponse = real(frequencyDomain[i]) / fft_bins;
|
t.impulseResponse = real(frequencyDomain[i]) / fft_bins;
|
||||||
t.stepResponse = last_step;
|
t.stepResponse = last_step;
|
||||||
last_step += t.impulseResponse;
|
last_step += t.impulseResponse;
|
||||||
|
@ -24,6 +24,7 @@ public:
|
|||||||
class TimedomainData {
|
class TimedomainData {
|
||||||
public:
|
public:
|
||||||
double time;
|
double time;
|
||||||
|
double distance;
|
||||||
double impulseResponse;
|
double impulseResponse;
|
||||||
double stepResponse;
|
double stepResponse;
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,9 @@ TraceModel::~TraceModel()
|
|||||||
void TraceModel::addTrace(Trace *t)
|
void TraceModel::addTrace(Trace *t)
|
||||||
{
|
{
|
||||||
beginInsertRows(QModelIndex(), traces.size(), traces.size());
|
beginInsertRows(QModelIndex(), traces.size(), traces.size());
|
||||||
|
connect(t, &Trace::nameChanged, [=]() {
|
||||||
|
emit traceNameChanged(t);
|
||||||
|
});
|
||||||
traces.push_back(t);
|
traces.push_back(t);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
emit traceAdded(t);
|
emit traceAdded(t);
|
||||||
|
@ -32,6 +32,7 @@ signals:
|
|||||||
void traceAdded(Trace *t);
|
void traceAdded(Trace *t);
|
||||||
void traceRemoved(Trace *t);
|
void traceRemoved(Trace *t);
|
||||||
void requiredExcitation(bool excitePort1, bool excitePort2);
|
void requiredExcitation(bool excitePort1, bool excitePort2);
|
||||||
|
void traceNameChanged(Trace *t);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clearVNAData();
|
void clearVNAData();
|
||||||
|
@ -121,8 +121,8 @@ void TracePlot::triggerReplot()
|
|||||||
{
|
{
|
||||||
auto now = QTime::currentTime();
|
auto now = QTime::currentTime();
|
||||||
if (lastUpdate.msecsTo(now) >= MinUpdateInterval) {
|
if (lastUpdate.msecsTo(now) >= MinUpdateInterval) {
|
||||||
replot();
|
|
||||||
lastUpdate = now;
|
lastUpdate = now;
|
||||||
|
replot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ public:
|
|||||||
|
|
||||||
virtual void enableTrace(Trace *t, bool enabled);
|
virtual void enableTrace(Trace *t, bool enabled);
|
||||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
virtual void setXAxis(double min, double max){Q_UNUSED(min);Q_UNUSED(max)};
|
virtual void updateSpan(double min, double max){Q_UNUSED(min);Q_UNUSED(max)};
|
||||||
|
|
||||||
static std::set<TracePlot *> getPlots();
|
static std::set<TracePlot *> getPlots();
|
||||||
|
|
||||||
|
@ -91,8 +91,11 @@ public:
|
|||||||
case TraceXYPlot::YAxisType::Impedance: {
|
case TraceXYPlot::YAxisType::Impedance: {
|
||||||
auto sample = t.getTDR()[i];
|
auto sample = t.getTDR()[i];
|
||||||
QPointF p;
|
QPointF p;
|
||||||
// TODO set distance
|
if(Xtype == TraceXYPlot::XAxisType::Time) {
|
||||||
p.setX(sample.time);
|
p.setX(sample.time);
|
||||||
|
} else {
|
||||||
|
p.setX(sample.distance);
|
||||||
|
}
|
||||||
p.setY(TimeAxisTransformation(Ytype, &t, i));
|
p.setY(TimeAxisTransformation(Ytype, &t, i));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -116,23 +119,23 @@ TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
|||||||
selectedMarker(nullptr)
|
selectedMarker(nullptr)
|
||||||
{
|
{
|
||||||
YAxis[0].log = false;
|
YAxis[0].log = false;
|
||||||
YAxis[0].Ytype = YAxisType::Disabled;
|
YAxis[0].type = YAxisType::Disabled;
|
||||||
YAxis[0].rangeDiv = 1;
|
YAxis[0].rangeDiv = 1;
|
||||||
YAxis[0].rangeMax = 10;
|
YAxis[0].rangeMax = 10;
|
||||||
YAxis[0].rangeMin = 0;
|
YAxis[0].rangeMin = 0;
|
||||||
YAxis[0].autorange = false;
|
YAxis[0].autorange = false;
|
||||||
YAxis[1].log = false;
|
YAxis[1].log = false;
|
||||||
YAxis[1].Ytype = YAxisType::Disabled;
|
YAxis[1].type = YAxisType::Disabled;
|
||||||
YAxis[1].rangeDiv = 1;
|
YAxis[1].rangeDiv = 1;
|
||||||
YAxis[1].rangeMax = 10;
|
YAxis[1].rangeMax = 10;
|
||||||
YAxis[1].rangeMin = 0;
|
YAxis[1].rangeMin = 0;
|
||||||
YAxis[1].autorange = false;
|
YAxis[1].autorange = false;
|
||||||
XAxis.Xtype = XAxisType::Frequency;
|
XAxis.type = XAxisType::Frequency;
|
||||||
XAxis.log = false;
|
XAxis.log = false;
|
||||||
XAxis.rangeDiv = 1;
|
XAxis.rangeDiv = 1;
|
||||||
XAxis.rangeMax = 10;
|
XAxis.rangeMax = 10;
|
||||||
XAxis.rangeMin = 0;
|
XAxis.rangeMin = 0;
|
||||||
XAxis.autorange = true;
|
XAxis.mode = XAxisMode::UseSpan;
|
||||||
|
|
||||||
plot = new QwtPlot(this);
|
plot = new QwtPlot(this);
|
||||||
|
|
||||||
@ -168,10 +171,10 @@ TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
|||||||
setYAxis(0, YAxisType::Magnitude, false, false, -120, 20, 10);
|
setYAxis(0, YAxisType::Magnitude, false, false, -120, 20, 10);
|
||||||
setYAxis(1, YAxisType::Phase, false, false, -180, 180, 30);
|
setYAxis(1, YAxisType::Phase, false, false, -180, 180, 30);
|
||||||
// enable autoscaling and set for full span (no information about actual span available yet)
|
// enable autoscaling and set for full span (no information about actual span available yet)
|
||||||
setXAxis(0, 6000000000);
|
updateSpan(0, 6000000000);
|
||||||
setXAxis(XAxisType::Frequency, true, 0, 6000000000, 600000000);
|
setXAxis(XAxisType::Frequency, XAxisMode::UseSpan, 0, 6000000000, 600000000);
|
||||||
// get notified when the span changes
|
// get notified when the span changes
|
||||||
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TraceXYPlot::setXAxis));
|
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TraceXYPlot::updateSpan));
|
||||||
|
|
||||||
allPlots.insert(this);
|
allPlots.insert(this);
|
||||||
}
|
}
|
||||||
@ -187,16 +190,15 @@ TraceXYPlot::~TraceXYPlot()
|
|||||||
allPlots.erase(this);
|
allPlots.erase(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceXYPlot::setXAxis(double min, double max)
|
void TraceXYPlot::updateSpan(double min, double max)
|
||||||
{
|
{
|
||||||
sweep_fmin = min;
|
sweep_fmin = min;
|
||||||
sweep_fmax = max;
|
sweep_fmax = max;
|
||||||
updateXAxis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool autorange, double min, double max, double div)
|
void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool autorange, double min, double max, double div)
|
||||||
{
|
{
|
||||||
if(YAxis[axis].Ytype != type) {
|
if(YAxis[axis].type != type) {
|
||||||
// remove traces that are active but not supported with the new axis type
|
// remove traces that are active but not supported with the new axis type
|
||||||
bool erased = false;
|
bool erased = false;
|
||||||
do {
|
do {
|
||||||
@ -210,12 +212,12 @@ void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool
|
|||||||
}
|
}
|
||||||
} while(erased);
|
} while(erased);
|
||||||
|
|
||||||
if(isTDRtype(YAxis[axis].Ytype)) {
|
if(isTDRtype(YAxis[axis].type)) {
|
||||||
for(auto t : tracesAxis[axis]) {
|
for(auto t : tracesAxis[axis]) {
|
||||||
t->removeTDRinterest();
|
t->removeTDRinterest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
YAxis[axis].Ytype = type;
|
YAxis[axis].type = type;
|
||||||
|
|
||||||
for(auto t : tracesAxis[axis]) {
|
for(auto t : tracesAxis[axis]) {
|
||||||
// supported but needs an adjusted QwtSeriesData
|
// supported but needs an adjusted QwtSeriesData
|
||||||
@ -252,20 +254,19 @@ void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool
|
|||||||
replot();
|
replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceXYPlot::setXAxis(XAxisType type, bool autorange, double min, double max, double div)
|
void TraceXYPlot::setXAxis(XAxisType type, XAxisMode mode, double min, double max, double div)
|
||||||
{
|
{
|
||||||
XAxis.Xtype = type;
|
XAxis.type = type;
|
||||||
XAxis.autorange = autorange;
|
XAxis.mode = mode;
|
||||||
XAxis.rangeMin = min;
|
XAxis.rangeMin = min;
|
||||||
XAxis.rangeMax = max;
|
XAxis.rangeMax = max;
|
||||||
XAxis.rangeDiv = div;
|
XAxis.rangeDiv = div;
|
||||||
updateXAxis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceXYPlot::enableTrace(Trace *t, bool enabled)
|
void TraceXYPlot::enableTrace(Trace *t, bool enabled)
|
||||||
{
|
{
|
||||||
for(int axis = 0;axis < 2;axis++) {
|
for(int axis = 0;axis < 2;axis++) {
|
||||||
if(supported(t, YAxis[axis].Ytype)) {
|
if(supported(t, YAxis[axis].type)) {
|
||||||
enableTraceAxis(t, axis, enabled);
|
enableTraceAxis(t, axis, enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,17 +291,20 @@ bool TraceXYPlot::isTDRtype(TraceXYPlot::YAxisType type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TraceXYPlot::axisSetupDialog()
|
||||||
|
{
|
||||||
|
auto setup = new XYplotAxisDialog(this);
|
||||||
|
setup->show();
|
||||||
|
}
|
||||||
|
|
||||||
void TraceXYPlot::updateContextMenu()
|
void TraceXYPlot::updateContextMenu()
|
||||||
{
|
{
|
||||||
contextmenu->clear();
|
contextmenu->clear();
|
||||||
auto setup = new QAction("Axis setup...", contextmenu);
|
auto setup = new QAction("Axis setup...", contextmenu);
|
||||||
connect(setup, &QAction::triggered, [this]() {
|
connect(setup, &QAction::triggered, this, &TraceXYPlot::axisSetupDialog);
|
||||||
auto setup = new XYplotAxisDialog(this);
|
|
||||||
setup->show();
|
|
||||||
});
|
|
||||||
contextmenu->addAction(setup);
|
contextmenu->addAction(setup);
|
||||||
for(int axis = 0;axis < 2;axis++) {
|
for(int axis = 0;axis < 2;axis++) {
|
||||||
if(YAxis[axis].Ytype == YAxisType::Disabled) {
|
if(YAxis[axis].type == YAxisType::Disabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(axis == 0) {
|
if(axis == 0) {
|
||||||
@ -310,7 +314,7 @@ void TraceXYPlot::updateContextMenu()
|
|||||||
}
|
}
|
||||||
for(auto t : traces) {
|
for(auto t : traces) {
|
||||||
// Skip traces that are not applicable for the selected axis type
|
// Skip traces that are not applicable for the selected axis type
|
||||||
if(!supported(t.first, YAxis[axis].Ytype)) {
|
if(!supported(t.first, YAxis[axis].type)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,6 +345,7 @@ bool TraceXYPlot::supported(Trace *)
|
|||||||
|
|
||||||
void TraceXYPlot::replot()
|
void TraceXYPlot::replot()
|
||||||
{
|
{
|
||||||
|
updateXAxis();
|
||||||
plot->replot();
|
plot->replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,12 +386,12 @@ void TraceXYPlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
|||||||
markerAdded(m);
|
markerAdded(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(isTDRtype(YAxis[axis].Ytype)) {
|
if(isTDRtype(YAxis[axis].type)) {
|
||||||
t->addTDRinterest();
|
t->addTDRinterest();
|
||||||
}
|
}
|
||||||
traceColorChanged(t);
|
traceColorChanged(t);
|
||||||
} else {
|
} else {
|
||||||
if(isTDRtype(YAxis[axis].Ytype)) {
|
if(isTDRtype(YAxis[axis].type)) {
|
||||||
t->removeTDRinterest();
|
t->removeTDRinterest();
|
||||||
}
|
}
|
||||||
tracesAxis[axis].erase(t);
|
tracesAxis[axis].erase(t);
|
||||||
@ -436,22 +441,78 @@ bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
|
|||||||
|
|
||||||
void TraceXYPlot::updateXAxis()
|
void TraceXYPlot::updateXAxis()
|
||||||
{
|
{
|
||||||
if(XAxis.autorange && sweep_fmax-sweep_fmin > 0) {
|
if(XAxis.mode == XAxisMode::Manual) {
|
||||||
|
plot->setAxisScale(QwtPlot::xBottom, XAxis.rangeMin, XAxis.rangeMax, XAxis.rangeDiv);
|
||||||
|
} else {
|
||||||
|
// automatic mode, figure out limits
|
||||||
|
double max = std::numeric_limits<double>::lowest();
|
||||||
|
double min = std::numeric_limits<double>::max();
|
||||||
|
if(XAxis.mode == XAxisMode::UseSpan) {
|
||||||
|
min = sweep_fmin;
|
||||||
|
max = sweep_fmax;
|
||||||
|
} else if(XAxis.mode == XAxisMode::FitTraces) {
|
||||||
|
for(auto t : traces) {
|
||||||
|
bool enabled = (tracesAxis[0].find(t.first) != tracesAxis[0].end()
|
||||||
|
|| tracesAxis[1].find(t.first) != tracesAxis[1].end());
|
||||||
|
auto trace = t.first;
|
||||||
|
if(enabled && trace->isVisible()) {
|
||||||
|
// this trace is currently displayed
|
||||||
|
double trace_min, trace_max;
|
||||||
|
switch(XAxis.type) {
|
||||||
|
case XAxisType::Frequency:
|
||||||
|
trace_min = trace->minFreq();
|
||||||
|
trace_max = trace->maxFreq();
|
||||||
|
break;
|
||||||
|
case XAxisType::Time:
|
||||||
|
trace_min = trace->getTDR().front().time;
|
||||||
|
trace_max = trace->getTDR().back().time;
|
||||||
|
break;
|
||||||
|
case XAxisType::Distance:
|
||||||
|
trace_min = trace->getTDR().front().distance;
|
||||||
|
trace_max = trace->getTDR().back().distance;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(trace_min < min) {
|
||||||
|
min = trace_min;
|
||||||
|
}
|
||||||
|
if(trace_max > max) {
|
||||||
|
max = trace_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(min >= max) {
|
||||||
|
// still at initial values, no traces are active, leave axis unchanged
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
constexpr int minDivisions = 8;
|
||||||
|
double max_div_step = (max - min) / 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
|
||||||
|
min = ceil(min / div_step) * div_step;
|
||||||
QList<double> tickList;
|
QList<double> tickList;
|
||||||
for(double tick = sweep_fmin;tick <= sweep_fmax;tick+= (sweep_fmax-sweep_fmin)/10) {
|
for(double tick = min;tick <= max;tick += div_step) {
|
||||||
tickList.append(tick);
|
tickList.append(tick);
|
||||||
}
|
}
|
||||||
QwtScaleDiv scalediv(sweep_fmin, sweep_fmax, QList<double>(), QList<double>(), tickList);
|
QwtScaleDiv scalediv(min, max, QList<double>(), QList<double>(), tickList);
|
||||||
plot->setAxisScaleDiv(QwtPlot::xBottom, scalediv);
|
plot->setAxisScaleDiv(QwtPlot::xBottom, scalediv);
|
||||||
} else {
|
|
||||||
plot->setAxisScale(QwtPlot::xBottom, XAxis.rangeMin, XAxis.rangeMax, XAxis.rangeDiv);
|
|
||||||
}
|
}
|
||||||
triggerReplot();
|
triggerReplot();
|
||||||
}
|
}
|
||||||
|
|
||||||
QwtSeriesData<QPointF> *TraceXYPlot::createQwtSeriesData(Trace &t, int axis)
|
QwtSeriesData<QPointF> *TraceXYPlot::createQwtSeriesData(Trace &t, int axis)
|
||||||
{
|
{
|
||||||
return new QwtTraceSeries(t, YAxis[axis].Ytype, XAxis.Xtype);
|
return new QwtTraceSeries(t, YAxis[axis].type, XAxis.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceXYPlot::traceColorChanged(Trace *t)
|
void TraceXYPlot::traceColorChanged(Trace *t)
|
||||||
@ -513,7 +574,7 @@ void TraceXYPlot::markerDataChanged(TraceMarker *m)
|
|||||||
{
|
{
|
||||||
auto qwtMarker = markers[m];
|
auto qwtMarker = markers[m];
|
||||||
qwtMarker->setXValue(m->getFrequency());
|
qwtMarker->setXValue(m->getFrequency());
|
||||||
qwtMarker->setYValue(FrequencyAxisTransformation(YAxis[0].Ytype, m->getData()));
|
qwtMarker->setYValue(FrequencyAxisTransformation(YAxis[0].type, m->getData()));
|
||||||
triggerReplot();
|
triggerReplot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,17 +50,24 @@ public:
|
|||||||
Time,
|
Time,
|
||||||
Distance,
|
Distance,
|
||||||
};
|
};
|
||||||
|
enum class XAxisMode {
|
||||||
|
UseSpan,
|
||||||
|
FitTraces,
|
||||||
|
Manual,
|
||||||
|
};
|
||||||
|
|
||||||
virtual void setXAxis(double min, double max) override;
|
virtual void updateSpan(double min, double max) override;
|
||||||
void setYAxis(int axis, YAxisType type, bool log, bool autorange, double min, double max, double div);
|
void setYAxis(int axis, YAxisType type, bool log, bool autorange, double min, double max, double div);
|
||||||
void setXAxis(XAxisType type, bool autorange, double min, double max, double div);
|
void setXAxis(XAxisType type, XAxisMode mode, double min, double max, double div);
|
||||||
void enableTrace(Trace *t, bool enabled) override;
|
void enableTrace(Trace *t, bool enabled) override;
|
||||||
|
|
||||||
// Applies potentially changed colors to all XY-plots
|
// Applies potentially changed colors to all XY-plots
|
||||||
static void updateGraphColors();
|
static void updateGraphColors();
|
||||||
|
|
||||||
bool isTDRtype(YAxisType type);
|
bool isTDRtype(YAxisType type);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void axisSetupDialog();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void updateContextMenu() override;
|
virtual void updateContextMenu() override;
|
||||||
virtual bool supported(Trace *t) override;
|
virtual bool supported(Trace *t) override;
|
||||||
@ -85,20 +92,27 @@ private:
|
|||||||
|
|
||||||
std::set<Trace*> tracesAxis[2];
|
std::set<Trace*> tracesAxis[2];
|
||||||
|
|
||||||
class Axis {
|
class YAxis {
|
||||||
public:
|
public:
|
||||||
union {
|
YAxisType type;
|
||||||
YAxisType Ytype;
|
bool log; // not used yet
|
||||||
XAxisType Xtype;
|
|
||||||
};
|
|
||||||
bool log;
|
|
||||||
bool autorange;
|
bool autorange;
|
||||||
double rangeMin;
|
double rangeMin;
|
||||||
double rangeMax;
|
double rangeMax;
|
||||||
double rangeDiv;
|
double rangeDiv;
|
||||||
};
|
};
|
||||||
Axis YAxis[2];
|
class XAxis {
|
||||||
Axis XAxis;
|
public:
|
||||||
|
XAxisType type;
|
||||||
|
XAxisMode mode;
|
||||||
|
bool log; // not used yet
|
||||||
|
double rangeMin;
|
||||||
|
double rangeMax;
|
||||||
|
double rangeDiv;
|
||||||
|
};
|
||||||
|
|
||||||
|
YAxis YAxis[2];
|
||||||
|
XAxis XAxis;
|
||||||
double sweep_fmin, sweep_fmax;
|
double sweep_fmin, sweep_fmax;
|
||||||
|
|
||||||
using CurveData = struct {
|
using CurveData = struct {
|
||||||
|
@ -59,16 +59,17 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Xmin->setEnabled(!checked);
|
ui->Xmin->setEnabled(!checked);
|
||||||
ui->Xmax->setEnabled(!checked);
|
ui->Xmax->setEnabled(!checked);
|
||||||
ui->Xdivs->setEnabled(!checked);
|
ui->Xdivs->setEnabled(!checked);
|
||||||
|
ui->Xautomode->setEnabled(checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
ui->XType->setCurrentIndex((int) plot->XAxis.Xtype);
|
ui->XType->setCurrentIndex((int) plot->XAxis.type);
|
||||||
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");
|
||||||
|
|
||||||
// Fill initial values
|
// Fill initial values
|
||||||
// assume same order in YAxisType enum as in ComboBox items
|
// assume same order in YAxisType enum as in ComboBox items
|
||||||
ui->Y1type->setCurrentIndex((int) plot->YAxis[0].Ytype);
|
ui->Y1type->setCurrentIndex((int) plot->YAxis[0].type);
|
||||||
if(plot->YAxis[0].log) {
|
if(plot->YAxis[0].log) {
|
||||||
ui->Y1log->setChecked(true);
|
ui->Y1log->setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
@ -79,7 +80,7 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Y1max->setValueQuiet(plot->YAxis[0].rangeMax);
|
ui->Y1max->setValueQuiet(plot->YAxis[0].rangeMax);
|
||||||
ui->Y1divs->setValueQuiet(plot->YAxis[0].rangeDiv);
|
ui->Y1divs->setValueQuiet(plot->YAxis[0].rangeDiv);
|
||||||
|
|
||||||
ui->Y2type->setCurrentIndex((int) plot->YAxis[1].Ytype);
|
ui->Y2type->setCurrentIndex((int) plot->YAxis[1].type);
|
||||||
if(plot->YAxis[1].log) {
|
if(plot->YAxis[1].log) {
|
||||||
ui->Y2log->setChecked(true);
|
ui->Y2log->setChecked(true);
|
||||||
} else {
|
} else {
|
||||||
@ -90,7 +91,12 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||||||
ui->Y2max->setValueQuiet(plot->YAxis[1].rangeMax);
|
ui->Y2max->setValueQuiet(plot->YAxis[1].rangeMax);
|
||||||
ui->Y2divs->setValueQuiet(plot->YAxis[1].rangeDiv);
|
ui->Y2divs->setValueQuiet(plot->YAxis[1].rangeDiv);
|
||||||
|
|
||||||
ui->Xauto->setChecked(plot->XAxis.autorange);
|
ui->Xauto->setChecked(plot->XAxis.mode != TraceXYPlot::XAxisMode::Manual);
|
||||||
|
if(plot->XAxis.mode == TraceXYPlot::XAxisMode::UseSpan) {
|
||||||
|
ui->Xautomode->setCurrentIndex(0);
|
||||||
|
} else {
|
||||||
|
ui->Xautomode->setCurrentIndex(1);
|
||||||
|
}
|
||||||
ui->Xmin->setValueQuiet(plot->XAxis.rangeMin);
|
ui->Xmin->setValueQuiet(plot->XAxis.rangeMin);
|
||||||
ui->Xmax->setValueQuiet(plot->XAxis.rangeMax);
|
ui->Xmax->setValueQuiet(plot->XAxis.rangeMax);
|
||||||
ui->Xdivs->setValueQuiet(plot->XAxis.rangeDiv);
|
ui->Xdivs->setValueQuiet(plot->XAxis.rangeDiv);
|
||||||
@ -106,7 +112,24 @@ 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, (TraceXYPlot::YAxisType) 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, (TraceXYPlot::YAxisType) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2divs->value());
|
||||||
plot->setXAxis((TraceXYPlot::XAxisType) ui->XType->currentIndex(), ui->Xauto->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
TraceXYPlot::XAxisMode mode;
|
||||||
|
if(ui->Xauto->isChecked()) {
|
||||||
|
if(ui->Xautomode->currentIndex() == 0) {
|
||||||
|
mode = TraceXYPlot::XAxisMode::UseSpan;
|
||||||
|
} else {
|
||||||
|
mode = TraceXYPlot::XAxisMode::FitTraces;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mode = TraceXYPlot::XAxisMode::Manual;
|
||||||
|
}
|
||||||
|
plot->setXAxis((TraceXYPlot::XAxisType) ui->XType->currentIndex(), mode, ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
||||||
@ -116,14 +139,8 @@ void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
|||||||
for(auto t : TraceXYPlot::YAxisTypes) {
|
for(auto t : TraceXYPlot::YAxisTypes) {
|
||||||
auto enable = supported.count(t) > 0;
|
auto enable = supported.count(t) > 0;
|
||||||
auto index = (int) t;
|
auto index = (int) t;
|
||||||
auto *model = qobject_cast<QStandardItemModel *>(ui->Y1type->model());
|
enableComboBoxItem(ui->Y1type, index, enable);
|
||||||
auto item = model->item(index);
|
enableComboBoxItem(ui->Y2type, index, enable);
|
||||||
item->setFlags(enable ? item->flags() | Qt::ItemIsEnabled
|
|
||||||
: item->flags() & ~Qt::ItemIsEnabled);
|
|
||||||
model = qobject_cast<QStandardItemModel *>(ui->Y2type->model());
|
|
||||||
item = model->item(index);
|
|
||||||
item->setFlags(enable ? item->flags() | Qt::ItemIsEnabled
|
|
||||||
: item->flags() & ~Qt::ItemIsEnabled);
|
|
||||||
}
|
}
|
||||||
// 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((TraceXYPlot::YAxisType)ui->Y1type->currentIndex())) {
|
||||||
@ -133,6 +150,16 @@ void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
|||||||
ui->Y2type->setCurrentIndex(0);
|
ui->Y2type->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(type == TraceXYPlot::XAxisType::Frequency) {
|
||||||
|
enableComboBoxItem(ui->Xautomode, 0, true);
|
||||||
|
} else {
|
||||||
|
// auto mode using span not supported in time mode
|
||||||
|
if(ui->Xautomode->currentIndex() == 0) {
|
||||||
|
ui->Xautomode->setCurrentIndex(1);
|
||||||
|
enableComboBoxItem(ui->Xautomode, 0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString unit;
|
QString unit;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case TraceXYPlot::XAxisType::Frequency: unit = "Hz"; break;
|
case TraceXYPlot::XAxisType::Frequency: unit = "Hz"; break;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>715</width>
|
<width>689</width>
|
||||||
<height>282</height>
|
<height>282</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -16,32 +16,9 @@
|
|||||||
<property name="modal">
|
<property name="modal">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<property name="geometry">
|
<item>
|
||||||
<rect>
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
<x>9</x>
|
|
||||||
<y>248</y>
|
|
||||||
<width>166</width>
|
|
||||||
<height>25</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="layoutWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>10</x>
|
|
||||||
<y>10</y>
|
|
||||||
<width>701</width>
|
|
||||||
<height>233</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
@ -455,12 +432,30 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
<widget class="QCheckBox" name="Xauto">
|
<widget class="QCheckBox" name="Xauto">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Auto</string>
|
<string>Auto</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="Xautomode">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use Span</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fit Traces</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_16">
|
<widget class="QLabel" name="label_16">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -496,7 +491,18 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</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>
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
Loading…
Reference in New Issue
Block a user