From b91f431473a80f1390270410bc930c758da8973d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Wed, 2 Dec 2020 22:15:34 +0100 Subject: [PATCH] Markers adjusted for time domain math + distance mode fixed --- .../PC_Application/Traces/Math/tracemath.cpp | 10 + .../PC_Application/Traces/Math/tracemath.h | 5 + .../Traces/Math/windowfunction.cpp | 48 +- .../Traces/Math/windowfunction.h | 2 +- .../PC_Application/Traces/markerwidget.cpp | 3 +- Software/PC_Application/Traces/trace.cpp | 26 + Software/PC_Application/Traces/trace.h | 4 + .../PC_Application/Traces/tracemarker.cpp | 472 +++++++++++------- Software/PC_Application/Traces/tracemarker.h | 17 +- Software/PC_Application/Traces/tracemodel.h | 1 - .../PC_Application/Traces/tracexyplot.cpp | 16 +- 11 files changed, 375 insertions(+), 229 deletions(-) diff --git a/Software/PC_Application/Traces/Math/tracemath.cpp b/Software/PC_Application/Traces/Math/tracemath.cpp index 3d9bd4a..ab09646 100644 --- a/Software/PC_Application/Traces/Math/tracemath.cpp +++ b/Software/PC_Application/Traces/Math/tracemath.cpp @@ -2,6 +2,7 @@ #include "medianfilter.h" #include "tdr.h" +#include "Traces/trace.h" TraceMath::TraceMath() { @@ -165,6 +166,15 @@ QString TraceMath::getStatusDescription() const return statusString; } +Trace *TraceMath::root() +{ + auto root = this; + while(root->input) { + root = root->input; + } + return static_cast(root); +} + TraceMath::Status TraceMath::getStatus() const { return status; diff --git a/Software/PC_Application/Traces/Math/tracemath.h b/Software/PC_Application/Traces/Math/tracemath.h index 7fa16c1..476b773 100644 --- a/Software/PC_Application/Traces/Math/tracemath.h +++ b/Software/PC_Application/Traces/Math/tracemath.h @@ -41,6 +41,8 @@ * 6. Extend the function getInfo(Type type) to set a name and create the explanation widget for your operation */ +class Trace; + class TraceMath : public QObject { Q_OBJECT public: @@ -97,6 +99,9 @@ public: Status getStatus() const; QString getStatusDescription() const; + // returns the trace this math operation is attached to + Trace* root(); + public slots: // some values of the input data have changed, begin/end determine which sample(s) has changed virtual void inputSamplesChanged(unsigned int begin, unsigned int end){Q_UNUSED(begin) Q_UNUSED(end)}; diff --git a/Software/PC_Application/Traces/Math/windowfunction.cpp b/Software/PC_Application/Traces/Math/windowfunction.cpp index 2a82a1a..dbcc083 100644 --- a/Software/PC_Application/Traces/Math/windowfunction.cpp +++ b/Software/PC_Application/Traces/Math/windowfunction.cpp @@ -15,7 +15,7 @@ QString WindowFunction::typeToName(WindowFunction::Type type) case Type::Hann: return "Hann"; break; case Type::Blackman: return "Blackman"; break; case Type::Gaussian: return "Gaussian"; break; - case Type::Chebyshev: return "Chebyshev"; break; +// case Type::Chebyshev: return "Chebyshev"; break; default: return "Invalid"; break; } } @@ -66,14 +66,14 @@ QWidget *WindowFunction::createEditor() gaussian_sigma = newval; }); break; - case Type::Chebyshev: - paramLabel = new QLabel("Parameter α:"); - paramEdit = new SIUnitEdit("", " ", 3); - paramEdit->setValue(chebyshev_alpha); - QObject::connect(paramEdit, &SIUnitEdit::valueChanged, [=](double newval) { - chebyshev_alpha = newval; - }); - break; +// case Type::Chebyshev: +// paramLabel = new QLabel("Parameter α:"); +// paramEdit = new SIUnitEdit("", " ", 3); +// paramEdit->setValue(chebyshev_alpha); +// QObject::connect(paramEdit, &SIUnitEdit::valueChanged, [=](double newval) { +// chebyshev_alpha = newval; +// }); +// break; // case Type::Kaiser: // // TODO // break; @@ -102,8 +102,8 @@ QString WindowFunction::getDescription() QString ret = typeToName(type); if(type == Type::Gaussian) { ret += ", σ=" + QString::number(gaussian_sigma); - } else if(type == Type::Chebyshev) { - ret += ", α=" + QString::number(chebyshev_alpha); +// } else if(type == Type::Chebyshev) { +// ret += ", α=" + QString::number(chebyshev_alpha); } return ret; } @@ -126,19 +126,19 @@ double WindowFunction::getFactor(unsigned int n, unsigned int N) return 0.42 - 0.5 * cos(2*M_PI*n / N) + 0.08 * cos(4*M_PI*n / N); case Type::Gaussian: return exp(-0.5 * pow((n - (double) N/2) / (gaussian_sigma * N / 2), 2)); - case Type::Chebyshev: { - double beta = cosh(1.0 / N * acosh(pow(10, chebyshev_alpha))); - double T_N_arg = beta * cos(M_PI*n/(N+1)); - double T_N; - if(T_N_arg >= 1.0) { - T_N = cosh(N * acosh(T_N_arg)); - } else if(T_N_arg <= -1.0) { - T_N = pow(-1.0, N) * cosh(N * acosh(T_N_arg)); - } else { - T_N = cos(N * acos(T_N_arg)); - } - return T_N / pow(10.0, chebyshev_alpha); - } +// case Type::Chebyshev: { +// double beta = cosh(1.0 / N * acosh(pow(10, chebyshev_alpha))); +// double T_N_arg = beta * cos(M_PI*n/(N+1)); +// double T_N; +// if(T_N_arg >= 1.0) { +// T_N = cosh(N * acosh(T_N_arg)); +// } else if(T_N_arg <= -1.0) { +// T_N = pow(-1.0, N) * cosh(N * acosh(T_N_arg)); +// } else { +// T_N = cos(N * acos(T_N_arg)); +// } +// return T_N / pow(10.0, chebyshev_alpha); +// } default: return 1.0; } diff --git a/Software/PC_Application/Traces/Math/windowfunction.h b/Software/PC_Application/Traces/Math/windowfunction.h index 8d106d2..fabec7f 100644 --- a/Software/PC_Application/Traces/Math/windowfunction.h +++ b/Software/PC_Application/Traces/Math/windowfunction.h @@ -13,7 +13,7 @@ public: Rectangular, // Kaiser, Gaussian, - Chebyshev, +// Chebyshev, Hann, Hamming, Blackman, diff --git a/Software/PC_Application/Traces/markerwidget.cpp b/Software/PC_Application/Traces/markerwidget.cpp index 18ca77e..a9957d9 100644 --- a/Software/PC_Application/Traces/markerwidget.cpp +++ b/Software/PC_Application/Traces/markerwidget.cpp @@ -19,7 +19,6 @@ MarkerWidget::MarkerWidget(TraceMarkerModel &model, QWidget *parent) : connect(&model.getModel(), &TraceModel::traceAdded, this, &MarkerWidget::updatePersistentEditors); connect(&model.getModel(), &TraceModel::traceRemoved, this, &MarkerWidget::updatePersistentEditors); connect(&model.getModel(), &TraceModel::traceNameChanged, this, &MarkerWidget::updatePersistentEditors); - connect(&model.getModel(), &TraceModel::traceTDRstateChanged, this, &MarkerWidget::updatePersistentEditors); } MarkerWidget::~MarkerWidget() @@ -56,7 +55,7 @@ void MarkerWidget::on_bAdd_clicked() { auto marker = model.createDefaultMarker(); connect(marker, &TraceMarker::typeChanged, this, &MarkerWidget::updatePersistentEditors); - connect(marker, &TraceMarker::timeDomainChanged, this, &MarkerWidget::updatePersistentEditors); + connect(marker, &TraceMarker::traceChanged, this, &MarkerWidget::updatePersistentEditors); model.addMarker(marker); updatePersistentEditors(); } diff --git a/Software/PC_Application/Traces/trace.cpp b/Software/PC_Application/Traces/trace.cpp index 214bcac..11feb31 100644 --- a/Software/PC_Application/Traces/trace.cpp +++ b/Software/PC_Application/Traces/trace.cpp @@ -167,6 +167,32 @@ const std::vector& Trace::getMathOperations() const return mathOps; } +double Trace::velocityFactor() +{ + // TODO make changeable + return 0.66; +} + +double Trace::timeToDistance(double time) +{ + double c = 299792458; + auto distance = time * c * velocityFactor(); + if(isReflection()) { + distance /= 2.0; + } + return distance; +} + +double Trace::distanceToTime(double distance) +{ + double c = 299792458; + auto time = distance / (c * velocityFactor()); + if(isReflection()) { + time *= 2.0; + } + return time; +} + void Trace::updateLastMath(vector::reverse_iterator start) { TraceMath *newLast = nullptr; diff --git a/Software/PC_Application/Traces/trace.h b/Software/PC_Application/Traces/trace.h index 34b2c07..25218b3 100644 --- a/Software/PC_Application/Traces/trace.h +++ b/Software/PC_Application/Traces/trace.h @@ -104,6 +104,10 @@ public: }; const std::vector& getMathOperations() const; + double velocityFactor(); + double timeToDistance(double time); + double distanceToTime(double distance); + public slots: void setTouchstoneParameter(int value); void setTouchstoneFilename(const QString &value); diff --git a/Software/PC_Application/Traces/tracemarker.cpp b/Software/PC_Application/Traces/tracemarker.cpp index 80c05a8..30f46ac 100644 --- a/Software/PC_Application/Traces/tracemarker.cpp +++ b/Software/PC_Application/Traces/tracemarker.cpp @@ -21,7 +21,9 @@ TraceMarker::TraceMarker(TraceMarkerModel *model, int number, TraceMarker *paren description(descr), delta(nullptr), parent(parent), - cutoffAmplitude(-3.0) + cutoffAmplitude(-3.0), + peakThreshold(-40.0), + offset(10000) { } @@ -40,9 +42,7 @@ void TraceMarker::assignTrace(Trace *t) if(parentTrace) { // remove connection from previous parent trace parentTrace->removeMarker(this); - disconnect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted); - disconnect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged); - disconnect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol); + disconnect(parentTrace, &Trace::deleted, this, nullptr); } parentTrace = t; if(!getSupportedTypes().count(type)) { @@ -53,6 +53,10 @@ void TraceMarker::assignTrace(Trace *t) connect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted); connect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged); connect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol); + connect(parentTrace, &Trace::typeChanged, [=](){ + emit domainChanged(); + checkDeltaMarker(); + }); constrainPosition(); updateSymbol(); parentTrace->addMarker(this); @@ -70,128 +74,141 @@ Trace *TraceMarker::trace() QString TraceMarker::readableData() { - switch(type) { - case Type::Manual: - case Type::Maximum: - case Type::Minimum: -// if(isTimeDomain()) { -// QString ret; -// ret += "Impulse:"+Unit::ToString(timeData.impulseResponse, "", "m ", 3)+" Step:"+Unit::ToString(timeData.stepResponse, "", "m ", 3)+" Impedance:"; -// if(isnan(timeData.impedance)) { -// ret += "Invalid"; -// } else { -// ret += Unit::ToString(timeData.impedance, "Ω", "m k", 3); -// } -// return ret; -// } else - { - auto phase = arg(data); - return QString::number(toDecibel(), 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4); + if(isTimeDomain()) { + switch(type) { + case Type::Manual: { + QString ret; + auto impulse = data.real(); + auto step = parentTrace->sample(parentTrace->index(position), Trace::SampleType::TimeStep).y.real(); + ret += "Impulse:"+Unit::ToString(impulse, "", "m ", 3); + if(!isnan(step)) { + ret += " Step:"+Unit::ToString(step, "", "m ", 3); + if(abs(step) < 1.0) { + auto impedance = 50.0 * (1.0 + step) / (1.0 - step); + ret += " Impedance:"+Unit::ToString(impedance, "Ω", "m kM", 3); + } + } + return ret; } - case Type::Delta: - if(!delta /*|| delta->isTimeDomain() != isTimeDomain()*/) { - return "Invalid delta marker"; - } else { -// if(isTimeDomain()) { -// // calculate difference between markers -// auto impulse = timeData.impulseResponse - delta->timeData.impulseResponse; -// auto step = timeData.stepResponse - delta->timeData.stepResponse; -// auto impedance = timeData.impedance - delta->timeData.impedance; -// QString ret; -// ret += "ΔImpulse:"+Unit::ToString(impulse, "", "m ", 3)+" ΔStep:"+Unit::ToString(step, "", "m ", 3)+" ΔImpedance:"; -// if(isnan(timeData.impedance)) { -// ret += "Invalid"; -// } else { -// ret += Unit::ToString(impedance, "Ω", "m k", 3); -// } -// return ret; -// } else { + case Type::Delta: { + if(!delta || !delta->isTimeDomain()) { + return "Invalid delta marker"; + } + // calculate difference between markers + auto impulse = data.real() - delta->data.real(); + QString ret; + auto timeDiff = position - delta->position; + auto distanceDiff = parentTrace->timeToDistance(position) - delta->parentTrace->timeToDistance(delta->position); + ret += "Δ:"+Unit::ToString(timeDiff, "s", "fpnum ", 4) + "/" + Unit::ToString(distanceDiff, "m", "m k", 4); + ret += " ΔImpulse:"+Unit::ToString(impulse, "", "m ", 3); + auto step = parentTrace->sample(parentTrace->index(position), Trace::SampleType::TimeStep).y.real(); + auto stepDelta = delta->parentTrace->sample(delta->parentTrace->index(delta->position), Trace::SampleType::TimeStep).y.real(); + if(!isnan(step) && !isnan(stepDelta)) { + auto stepDiff = step - stepDelta; + ret += " ΔStep:"+Unit::ToString(stepDiff, "", "m ", 3); + if(abs(step) < 1.0 && abs(stepDelta) < 1.0) { + auto impedance = 50.0 * (1.0 + step) / (1.0 - step); + auto impedanceDelta = 50.0 * (1.0 + stepDelta) / (1.0 - stepDelta); + auto impedanceDiff = impedance - impedanceDelta; + ret += " ΔImpedance:"+Unit::ToString(impedanceDiff, "Ω", "m kM", 3); + } + } + return ret; + } + default: + return "Invalid type"; + } + } else { + switch(type) { + case Type::Manual: + case Type::Maximum: + case Type::Minimum: { + auto phase = arg(data); + return QString::number(toDecibel(), 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4); + } + case Type::Delta: + if(!delta && delta->isTimeDomain()) { + return "Invalid delta marker"; + } else { // calculate difference between markers auto freqDiff = position - delta->position; auto valueDiff = data / delta->data; auto phase = arg(valueDiff); auto db = 20*log10(abs(valueDiff)); return Unit::ToString(freqDiff, "Hz", " kMG") + " / " + QString::number(db, 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4); -// } - } - break; - case Type::Noise: - return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3); - case Type::PeakTable: - return "Found " + QString::number(helperMarkers.size()) + " peaks"; - case Type::Lowpass: - case Type::Highpass: - if(parentTrace->isReflection()) { - return "Calculation not possible with reflection measurement"; - } else { - auto insertionLoss = toDecibel(); - auto cutoff = helperMarkers[0]->toDecibel(); - QString ret = "fc: "; - if(cutoff > insertionLoss + cutoffAmplitude) { - // the trace never dipped below the specified cutoffAmplitude, exact cutoff frequency unknown - ret += type == Type::Lowpass ? ">" : "<"; } - ret += Unit::ToString(helperMarkers[0]->position, "Hz", " kMG", 4); - ret += ", Ins.Loss: >=" + QString::number(-insertionLoss, 'g', 4) + "db"; - return ret; - } - break; - case Type::Bandpass: - if(parentTrace->isReflection()) { - return "Calculation not possible with reflection measurement"; - } else { - auto insertionLoss = toDecibel(); - auto cutoffL = helperMarkers[0]->toDecibel(); - auto cutoffH = helperMarkers[1]->toDecibel(); - auto bandwidth = helperMarkers[1]->position - helperMarkers[0]->position; - auto center = helperMarkers[2]->position; - QString ret = "fc: "; - if(cutoffL > insertionLoss + cutoffAmplitude || cutoffH > insertionLoss + cutoffAmplitude) { - // the trace never dipped below the specified cutoffAmplitude, center and exact bandwidth unknown - ret += "?, BW: >"; + break; + case Type::Noise: + return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3); + case Type::PeakTable: + return "Found " + QString::number(helperMarkers.size()) + " peaks"; + case Type::Lowpass: + case Type::Highpass: + if(parentTrace->isReflection()) { + return "Calculation not possible with reflection measurement"; } else { - ret += Unit::ToString(center, "Hz", " kMG", 5)+ ", BW: "; + auto insertionLoss = toDecibel(); + auto cutoff = helperMarkers[0]->toDecibel(); + QString ret = "fc: "; + if(cutoff > insertionLoss + cutoffAmplitude) { + // the trace never dipped below the specified cutoffAmplitude, exact cutoff frequency unknown + ret += type == Type::Lowpass ? ">" : "<"; + } + ret += Unit::ToString(helperMarkers[0]->position, "Hz", " kMG", 4); + ret += ", Ins.Loss: >=" + QString::number(-insertionLoss, 'g', 4) + "db"; + return ret; } - ret += Unit::ToString(bandwidth, "Hz", " kMG", 4); - ret += ", Ins.Loss: >=" + QString::number(-insertionLoss, 'g', 4) + "db"; - return ret; + break; + case Type::Bandpass: + if(parentTrace->isReflection()) { + return "Calculation not possible with reflection measurement"; + } else { + auto insertionLoss = toDecibel(); + auto cutoffL = helperMarkers[0]->toDecibel(); + auto cutoffH = helperMarkers[1]->toDecibel(); + auto bandwidth = helperMarkers[1]->position - helperMarkers[0]->position; + auto center = helperMarkers[2]->position; + QString ret = "fc: "; + if(cutoffL > insertionLoss + cutoffAmplitude || cutoffH > insertionLoss + cutoffAmplitude) { + // the trace never dipped below the specified cutoffAmplitude, center and exact bandwidth unknown + ret += "?, BW: >"; + } else { + ret += Unit::ToString(center, "Hz", " kMG", 5)+ ", BW: "; + } + ret += Unit::ToString(bandwidth, "Hz", " kMG", 4); + ret += ", Ins.Loss: >=" + QString::number(-insertionLoss, 'g', 4) + "db"; + return ret; + } + break; + case Type::TOI: { + auto avgFundamental = (helperMarkers[0]->toDecibel() + helperMarkers[1]->toDecibel()) / 2; + auto avgDistortion = (helperMarkers[2]->toDecibel() + helperMarkers[3]->toDecibel()) / 2; + auto TOI = (3 * avgFundamental - avgDistortion) / 2; + return "Fundamental: " + Unit::ToString(avgFundamental, "dbm", " ", 3) + ", distortion: " + Unit::ToString(avgDistortion, "dbm", " ", 3) + ", TOI: "+Unit::ToString(TOI, "dbm", " ", 3); + } + break; + case Type::PhaseNoise: { + auto carrier = toDecibel(); + auto phasenoise = parentTrace->getNoise(helperMarkers[0]->position) - carrier; + return Unit::ToString(phasenoise, "dbc/Hz", " ", 3) +"@" + Unit::ToString(offset, "Hz", " kM", 4) + " offset (" + Unit::ToString(position, "Hz", " kMG", 6) + " carrier)"; + } + default: + return "Unknown marker type"; } - break; - case Type::TOI: { - auto avgFundamental = (helperMarkers[0]->toDecibel() + helperMarkers[1]->toDecibel()) / 2; - auto avgDistortion = (helperMarkers[2]->toDecibel() + helperMarkers[3]->toDecibel()) / 2; - auto TOI = (3 * avgFundamental - avgDistortion) / 2; - return "Fundamental: " + Unit::ToString(avgFundamental, "dbm", " ", 3) + ", distortion: " + Unit::ToString(avgDistortion, "dbm", " ", 3) + ", TOI: "+Unit::ToString(TOI, "dbm", " ", 3); - } - break; - case Type::PhaseNoise: { - auto carrier = toDecibel(); - auto phasenoise = parentTrace->getNoise(helperMarkers[0]->position) - carrier; - return Unit::ToString(phasenoise, "dbc/Hz", " ", 3) +"@" + Unit::ToString(offset, "Hz", " kM", 4) + " offset (" + Unit::ToString(position, "Hz", " kMG", 6) + " carrier)"; - } - default: - return "Unknown marker type"; } } QString TraceMarker::readableSettings() { -// if(timeDomain) { -// switch(type) { -// case Type::Manual: -// case Type::Delta: { -// QString unit; -// if(position <= parentTrace->getTDR().back().time) { -// unit = "s"; -// } else { -// unit = "m"; -// } -// return Unit::ToString(position, unit, "fpnum k", 4); -// } -// default: -// return "Unhandled case"; -// } -// } else { + if(isTimeDomain()) { + switch(type) { + case Type::Manual: + case Type::Delta: + return Unit::ToString(position, "s", "fpnum ", 4) + "/" + Unit::ToString(parentTrace->timeToDistance(position), "m", "um k", 4); + default: + return "Unhandled case"; + } + } else { switch(type) { case Type::Manual: case Type::Maximum: @@ -212,7 +229,39 @@ QString TraceMarker::readableSettings() default: return "Unhandled case"; } -// } + } +} + +QString TraceMarker::tooltipSettings() +{ + if(isTimeDomain()) { + switch(type) { + case Type::Manual: + case Type::Delta: + return "Time/Distance"; + default: + return QString(); + } + } else { + switch(type) { + case Type::Manual: + case Type::Maximum: + case Type::Minimum: + case Type::Delta: + case Type::Noise: + return "Marker frequency"; + case Type::Lowpass: + case Type::Highpass: + case Type::Bandpass: + return "Cutoff amplitude (relativ to peak)"; + case Type::PeakTable: + return "Peak threshold"; + case Type::PhaseNoise: + return "Frequency offset"; + default: + return QString(); + } + } } QString TraceMarker::readableType() @@ -241,12 +290,8 @@ void TraceMarker::traceDataChanged() { // some data of the parent trace changed, check if marker data also changed complex newdata; -// if (timeDomain) { -// timeData = parentTrace->getTDR(position); -// newdata = complex(timeData.stepResponse, timeData.impulseResponse); -// } else { - newdata = parentTrace->sample(parentTrace->index(position)).y; -// } + auto sampleType = isTimeDomain() ? Trace::SampleType::TimeImpulse : Trace::SampleType::Frequency; + newdata = parentTrace->sample(parentTrace->index(position), sampleType).y; if (newdata != data) { data = newdata; update(); @@ -276,15 +321,28 @@ void TraceMarker::updateSymbol() emit symbolChanged(this); } +void TraceMarker::checkDeltaMarker() +{ + if(type != Type::Delta) { + // not a delta marker, nothing to do + return; + } + // Check if type of delta marker is still okay + if(delta->isTimeDomain() != isTimeDomain()) { + // not the same domain anymore, adjust delta + assignDeltaMarker(bestDeltaCandidate()); + } +} + std::set TraceMarker::getSupportedTypes() { set supported; if(parentTrace) { -// if(timeDomain) { -// // only basic markers in time domain -// supported.insert(Type::Manual); -// supported.insert(Type::Delta); -// } else { + if(isTimeDomain()) { + // only basic markers in time domain + supported.insert(Type::Manual); + supported.insert(Type::Delta); + } else { // all traces support some basic markers supported.insert(Type::Manual); supported.insert(Type::Maximum); @@ -311,7 +369,7 @@ std::set TraceMarker::getSupportedTypes() break; } } -// } + } } return supported; } @@ -319,25 +377,45 @@ std::set TraceMarker::getSupportedTypes() void TraceMarker::constrainPosition() { if(parentTrace) { -// if(timeDomain) { -// if(position < 0) { -// position = 0; -// } else if(position > parentTrace->getTDR().back().distance) { -// position = parentTrace->getTDR().back().distance; -// } -// } else { - if(parentTrace->size() > 0) { - if(position > parentTrace->maxX()) { - position = parentTrace->maxX(); - } else if(position < parentTrace->minX()) { - position = parentTrace->minX(); - } + if(parentTrace->size() > 0) { + if(position > parentTrace->maxX()) { + position = parentTrace->maxX(); + } else if(position < parentTrace->minX()) { + position = parentTrace->minX(); } -// } + } traceDataChanged(); } } +TraceMarker *TraceMarker::bestDeltaCandidate() +{ + TraceMarker *match = nullptr; + // invalid delta marker assigned, attempt to find a matching marker + for(int pass = 0;pass < 3;pass++) { + for(auto m : model->getMarkers()) { + if(m->isTimeDomain() != isTimeDomain()) { + // markers are not on the same domain + continue; + } + if(pass == 0 && m->parentTrace != parentTrace) { + // ignore markers on different traces in first pass + continue; + } + if(pass <= 1 && m == this) { + // ignore itself on second pass + continue; + } + match = m; + break; + } + if(match) { + break; + } + } + return match; +} + void TraceMarker::assignDeltaMarker(TraceMarker *m) { if(delta) { @@ -347,8 +425,9 @@ void TraceMarker::assignDeltaMarker(TraceMarker *m) if(delta && delta != this) { // this marker has to be updated when the delta marker changes connect(delta, &TraceMarker::rawDataChanged, this, &TraceMarker::update); + connect(delta, &TraceMarker::domainChanged, this, &TraceMarker::checkDeltaMarker); connect(delta, &TraceMarker::deleted, [=](){ - delta = nullptr; + assignDeltaMarker(bestDeltaCandidate()); update(); }); } @@ -377,29 +456,7 @@ void TraceMarker::setType(TraceMarker::Type t) vector required_helpers; switch(type) { case Type::Delta: - delta = nullptr; - // invalid delta marker assigned, attempt to find a matching marker - for(int pass = 0;pass < 3;pass++) { - for(auto m : model->getMarkers()) { -// if(m->isTimeDomain() != isTimeDomain()) { -// // markers are not on the same domain -// continue; -// } - if(pass == 0 && m->parentTrace != parentTrace) { - // ignore markers on different traces in first pass - continue; - } - if(pass <= 1 && m == this) { - // ignore itself on second pass - continue; - } - assignDeltaMarker(m); - break; - } - if(delta) { - break; - } - } + assignDeltaMarker(bestDeltaCandidate()); break; case Type::Lowpass: case Type::Highpass: @@ -560,15 +617,15 @@ void TraceMarker::updateTypeFromEditor(QWidget *w) SIUnitEdit *TraceMarker::getSettingsEditor() { -// if(timeDomain) { -// switch(type) { -// case Type::Manual: -// case Type::Delta: -// return new SIUnitEdit("", "fpnum k", 6); -// default: -// return nullptr; -// } -// } else { + if(isTimeDomain()) { + switch(type) { + case Type::Manual: + case Type::Delta: + return new SIUnitEdit("", "fpnum k", 6); + default: + return nullptr; + } + } else { switch(type) { case Type::Manual: case Type::Maximum: @@ -585,34 +642,53 @@ SIUnitEdit *TraceMarker::getSettingsEditor() case Type::TOI: return nullptr; } -// } + } } void TraceMarker::adjustSettings(double value) { - switch(type) { - case Type::Manual: - case Type::Maximum: - case Type::Minimum: - case Type::Delta: - case Type::Noise: - default: - setPosition(value); - /* no break */ - case Type::Lowpass: - case Type::Highpass: - case Type::Bandpass: - if(value > 0.0) { - value = -value; + if(isTimeDomain()) { + switch(type) { + case Type::Manual: + case Type::Delta: { + // check if entered position is time or distance + if(value > parentTrace->sample(parentTrace->size() - 1).x) { + // entered a distance, convert to time + setPosition(parentTrace->distanceToTime(value)); + } else { + // entered a time, can set directly + setPosition(value); + } + } + default: + break; + } + } else { + switch(type) { + case Type::Manual: + case Type::Maximum: + case Type::Minimum: + case Type::Delta: + case Type::Noise: + setPosition(value); + break; + case Type::Lowpass: + case Type::Highpass: + case Type::Bandpass: + if(value > 0.0) { + value = -value; + } + cutoffAmplitude = value; + break; + case Type::PeakTable: + peakThreshold = value; + break; + case Type::PhaseNoise: + offset = value; + break; + default: + break; } - cutoffAmplitude = value; - break; - case Type::PeakTable: - peakThreshold = value; - break; - case Type::PhaseNoise: - offset = value; - break; } update(); } @@ -790,3 +866,13 @@ double TraceMarker::getPosition() const return position; } +bool TraceMarker::isTimeDomain() +{ + if(parentTrace) { + if(parentTrace->outputType() == Trace::DataType::Time) { + return true; + } + } + return false; +} + diff --git a/Software/PC_Application/Traces/tracemarker.h b/Software/PC_Application/Traces/tracemarker.h index 9ac544c..a212339 100644 --- a/Software/PC_Application/Traces/tracemarker.h +++ b/Software/PC_Application/Traces/tracemarker.h @@ -19,11 +19,13 @@ public: Trace* trace(); QString readableData(); QString readableSettings(); + QString tooltipSettings(); QString readableType(); double getPosition() const; std::complex getData() const; bool isMovable(); + bool isTimeDomain(); QPixmap& getSymbol(); @@ -56,14 +58,15 @@ signals: void traceChanged(TraceMarker *m); void beginRemoveHelperMarkers(TraceMarker *m); void endRemoveHelperMarkers(TraceMarker *m); - void timeDomainChanged(); private slots: void parentTraceDeleted(Trace *t); void traceDataChanged(); void updateSymbol(); + void checkDeltaMarker(); signals: void rawDataChanged(); + void domainChanged(); private: enum class Type { @@ -97,6 +100,7 @@ private: } } void constrainPosition(); + TraceMarker *bestDeltaCandidate(); void assignDeltaMarker(TraceMarker *m); void deleteHelperMarkers(); void setType(Type t); @@ -108,7 +112,7 @@ private: double position; int number; // Frequency domain: S parameter - // Time domain: imag part is impulse response, real part is step response + // Time domain: impulse response std::complex data; QPixmap symbol; Type type; @@ -118,11 +122,10 @@ private: TraceMarker *delta; std::vector helperMarkers; TraceMarker *parent; - union { - double cutoffAmplitude; - double peakThreshold; - double offset; - }; + // settings for the different marker types + double cutoffAmplitude; + double peakThreshold; + double offset; }; #endif // TRACEMARKER_H diff --git a/Software/PC_Application/Traces/tracemodel.h b/Software/PC_Application/Traces/tracemodel.h index 4f90fc1..a25bfe3 100644 --- a/Software/PC_Application/Traces/tracemodel.h +++ b/Software/PC_Application/Traces/tracemodel.h @@ -42,7 +42,6 @@ signals: void traceRemoved(Trace *t); void requiredExcitation(bool excitePort1, bool excitePort2); void traceNameChanged(Trace *t); - void traceTDRstateChanged(Trace *t, bool enabled); public slots: void clearVNAData(); diff --git a/Software/PC_Application/Traces/tracexyplot.cpp b/Software/PC_Application/Traces/tracexyplot.cpp index cc7344c..5e3ccb1 100644 --- a/Software/PC_Application/Traces/tracexyplot.cpp +++ b/Software/PC_Application/Traces/tracexyplot.cpp @@ -513,6 +513,10 @@ void TraceXYPlot::updateAxisTicks() // 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; } @@ -666,7 +670,14 @@ QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlo { QPointF ret = QPointF(numeric_limits::quiet_NaN(), numeric_limits::quiet_NaN()); auto data = t->sample(sample); - ret.setX(data.x); + switch(XAxis.type) { + case XAxisType::Distance: + ret.setX(t->timeToDistance(data.x)); + break; + default: + ret.setX(data.x); + break; + } switch(type) { case YAxisType::Magnitude: ret.setY(20*log10(abs(data.y))); @@ -762,6 +773,9 @@ double TraceXYPlot::nearestTracePoint(Trace *t, QPoint pixel) closestXpos = point.x(); } } + if(XAxis.type == XAxisType::Distance) { + closestXpos = t->distanceToTime(closestXpos); + } return closestXpos; }