Markers adjusted for time domain math + distance mode fixed
This commit is contained in:
parent
b8ccca5ebc
commit
b91f431473
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "medianfilter.h"
|
#include "medianfilter.h"
|
||||||
#include "tdr.h"
|
#include "tdr.h"
|
||||||
|
#include "Traces/trace.h"
|
||||||
|
|
||||||
TraceMath::TraceMath()
|
TraceMath::TraceMath()
|
||||||
{
|
{
|
||||||
@ -165,6 +166,15 @@ QString TraceMath::getStatusDescription() const
|
|||||||
return statusString;
|
return statusString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Trace *TraceMath::root()
|
||||||
|
{
|
||||||
|
auto root = this;
|
||||||
|
while(root->input) {
|
||||||
|
root = root->input;
|
||||||
|
}
|
||||||
|
return static_cast<Trace*>(root);
|
||||||
|
}
|
||||||
|
|
||||||
TraceMath::Status TraceMath::getStatus() const
|
TraceMath::Status TraceMath::getStatus() const
|
||||||
{
|
{
|
||||||
return status;
|
return status;
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
* 6. Extend the function getInfo(Type type) to set a name and create the explanation widget for your operation
|
* 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 {
|
class TraceMath : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@ -97,6 +99,9 @@ public:
|
|||||||
Status getStatus() const;
|
Status getStatus() const;
|
||||||
QString getStatusDescription() const;
|
QString getStatusDescription() const;
|
||||||
|
|
||||||
|
// returns the trace this math operation is attached to
|
||||||
|
Trace* root();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// some values of the input data have changed, begin/end determine which sample(s) has changed
|
// 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)};
|
virtual void inputSamplesChanged(unsigned int begin, unsigned int end){Q_UNUSED(begin) Q_UNUSED(end)};
|
||||||
|
@ -15,7 +15,7 @@ QString WindowFunction::typeToName(WindowFunction::Type type)
|
|||||||
case Type::Hann: return "Hann"; break;
|
case Type::Hann: return "Hann"; break;
|
||||||
case Type::Blackman: return "Blackman"; break;
|
case Type::Blackman: return "Blackman"; break;
|
||||||
case Type::Gaussian: return "Gaussian"; break;
|
case Type::Gaussian: return "Gaussian"; break;
|
||||||
case Type::Chebyshev: return "Chebyshev"; break;
|
// case Type::Chebyshev: return "Chebyshev"; break;
|
||||||
default: return "Invalid"; break;
|
default: return "Invalid"; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,14 +66,14 @@ QWidget *WindowFunction::createEditor()
|
|||||||
gaussian_sigma = newval;
|
gaussian_sigma = newval;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case Type::Chebyshev:
|
// case Type::Chebyshev:
|
||||||
paramLabel = new QLabel("Parameter α:");
|
// paramLabel = new QLabel("Parameter α:");
|
||||||
paramEdit = new SIUnitEdit("", " ", 3);
|
// paramEdit = new SIUnitEdit("", " ", 3);
|
||||||
paramEdit->setValue(chebyshev_alpha);
|
// paramEdit->setValue(chebyshev_alpha);
|
||||||
QObject::connect(paramEdit, &SIUnitEdit::valueChanged, [=](double newval) {
|
// QObject::connect(paramEdit, &SIUnitEdit::valueChanged, [=](double newval) {
|
||||||
chebyshev_alpha = newval;
|
// chebyshev_alpha = newval;
|
||||||
});
|
// });
|
||||||
break;
|
// break;
|
||||||
// case Type::Kaiser:
|
// case Type::Kaiser:
|
||||||
// // TODO
|
// // TODO
|
||||||
// break;
|
// break;
|
||||||
@ -102,8 +102,8 @@ QString WindowFunction::getDescription()
|
|||||||
QString ret = typeToName(type);
|
QString ret = typeToName(type);
|
||||||
if(type == Type::Gaussian) {
|
if(type == Type::Gaussian) {
|
||||||
ret += ", σ=" + QString::number(gaussian_sigma);
|
ret += ", σ=" + QString::number(gaussian_sigma);
|
||||||
} else if(type == Type::Chebyshev) {
|
// } else if(type == Type::Chebyshev) {
|
||||||
ret += ", α=" + QString::number(chebyshev_alpha);
|
// ret += ", α=" + QString::number(chebyshev_alpha);
|
||||||
}
|
}
|
||||||
return ret;
|
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);
|
return 0.42 - 0.5 * cos(2*M_PI*n / N) + 0.08 * cos(4*M_PI*n / N);
|
||||||
case Type::Gaussian:
|
case Type::Gaussian:
|
||||||
return exp(-0.5 * pow((n - (double) N/2) / (gaussian_sigma * N / 2), 2));
|
return exp(-0.5 * pow((n - (double) N/2) / (gaussian_sigma * N / 2), 2));
|
||||||
case Type::Chebyshev: {
|
// case Type::Chebyshev: {
|
||||||
double beta = cosh(1.0 / N * acosh(pow(10, chebyshev_alpha)));
|
// 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_arg = beta * cos(M_PI*n/(N+1));
|
||||||
double T_N;
|
// double T_N;
|
||||||
if(T_N_arg >= 1.0) {
|
// if(T_N_arg >= 1.0) {
|
||||||
T_N = cosh(N * acosh(T_N_arg));
|
// T_N = cosh(N * acosh(T_N_arg));
|
||||||
} else if(T_N_arg <= -1.0) {
|
// } else if(T_N_arg <= -1.0) {
|
||||||
T_N = pow(-1.0, N) * cosh(N * acosh(T_N_arg));
|
// T_N = pow(-1.0, N) * cosh(N * acosh(T_N_arg));
|
||||||
} else {
|
// } else {
|
||||||
T_N = cos(N * acos(T_N_arg));
|
// T_N = cos(N * acos(T_N_arg));
|
||||||
}
|
// }
|
||||||
return T_N / pow(10.0, chebyshev_alpha);
|
// return T_N / pow(10.0, chebyshev_alpha);
|
||||||
}
|
// }
|
||||||
default:
|
default:
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ public:
|
|||||||
Rectangular,
|
Rectangular,
|
||||||
// Kaiser,
|
// Kaiser,
|
||||||
Gaussian,
|
Gaussian,
|
||||||
Chebyshev,
|
// Chebyshev,
|
||||||
Hann,
|
Hann,
|
||||||
Hamming,
|
Hamming,
|
||||||
Blackman,
|
Blackman,
|
||||||
|
@ -19,7 +19,6 @@ 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);
|
connect(&model.getModel(), &TraceModel::traceNameChanged, this, &MarkerWidget::updatePersistentEditors);
|
||||||
connect(&model.getModel(), &TraceModel::traceTDRstateChanged, this, &MarkerWidget::updatePersistentEditors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkerWidget::~MarkerWidget()
|
MarkerWidget::~MarkerWidget()
|
||||||
@ -56,7 +55,7 @@ void MarkerWidget::on_bAdd_clicked()
|
|||||||
{
|
{
|
||||||
auto marker = model.createDefaultMarker();
|
auto marker = model.createDefaultMarker();
|
||||||
connect(marker, &TraceMarker::typeChanged, this, &MarkerWidget::updatePersistentEditors);
|
connect(marker, &TraceMarker::typeChanged, this, &MarkerWidget::updatePersistentEditors);
|
||||||
connect(marker, &TraceMarker::timeDomainChanged, this, &MarkerWidget::updatePersistentEditors);
|
connect(marker, &TraceMarker::traceChanged, this, &MarkerWidget::updatePersistentEditors);
|
||||||
model.addMarker(marker);
|
model.addMarker(marker);
|
||||||
updatePersistentEditors();
|
updatePersistentEditors();
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,32 @@ const std::vector<Trace::MathInfo>& Trace::getMathOperations() const
|
|||||||
return mathOps;
|
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<MathInfo>::reverse_iterator start)
|
void Trace::updateLastMath(vector<MathInfo>::reverse_iterator start)
|
||||||
{
|
{
|
||||||
TraceMath *newLast = nullptr;
|
TraceMath *newLast = nullptr;
|
||||||
|
@ -104,6 +104,10 @@ public:
|
|||||||
};
|
};
|
||||||
const std::vector<MathInfo>& getMathOperations() const;
|
const std::vector<MathInfo>& getMathOperations() const;
|
||||||
|
|
||||||
|
double velocityFactor();
|
||||||
|
double timeToDistance(double time);
|
||||||
|
double distanceToTime(double distance);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setTouchstoneParameter(int value);
|
void setTouchstoneParameter(int value);
|
||||||
void setTouchstoneFilename(const QString &value);
|
void setTouchstoneFilename(const QString &value);
|
||||||
|
@ -21,7 +21,9 @@ TraceMarker::TraceMarker(TraceMarkerModel *model, int number, TraceMarker *paren
|
|||||||
description(descr),
|
description(descr),
|
||||||
delta(nullptr),
|
delta(nullptr),
|
||||||
parent(parent),
|
parent(parent),
|
||||||
cutoffAmplitude(-3.0)
|
cutoffAmplitude(-3.0),
|
||||||
|
peakThreshold(-40.0),
|
||||||
|
offset(10000)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -40,9 +42,7 @@ void TraceMarker::assignTrace(Trace *t)
|
|||||||
if(parentTrace) {
|
if(parentTrace) {
|
||||||
// remove connection from previous parent trace
|
// remove connection from previous parent trace
|
||||||
parentTrace->removeMarker(this);
|
parentTrace->removeMarker(this);
|
||||||
disconnect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted);
|
disconnect(parentTrace, &Trace::deleted, this, nullptr);
|
||||||
disconnect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged);
|
|
||||||
disconnect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol);
|
|
||||||
}
|
}
|
||||||
parentTrace = t;
|
parentTrace = t;
|
||||||
if(!getSupportedTypes().count(type)) {
|
if(!getSupportedTypes().count(type)) {
|
||||||
@ -53,6 +53,10 @@ void TraceMarker::assignTrace(Trace *t)
|
|||||||
connect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted);
|
connect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted);
|
||||||
connect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged);
|
connect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged);
|
||||||
connect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol);
|
connect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol);
|
||||||
|
connect(parentTrace, &Trace::typeChanged, [=](){
|
||||||
|
emit domainChanged();
|
||||||
|
checkDeltaMarker();
|
||||||
|
});
|
||||||
constrainPosition();
|
constrainPosition();
|
||||||
updateSymbol();
|
updateSymbol();
|
||||||
parentTrace->addMarker(this);
|
parentTrace->addMarker(this);
|
||||||
@ -70,128 +74,141 @@ Trace *TraceMarker::trace()
|
|||||||
|
|
||||||
QString TraceMarker::readableData()
|
QString TraceMarker::readableData()
|
||||||
{
|
{
|
||||||
switch(type) {
|
if(isTimeDomain()) {
|
||||||
case Type::Manual:
|
switch(type) {
|
||||||
case Type::Maximum:
|
case Type::Manual: {
|
||||||
case Type::Minimum:
|
QString ret;
|
||||||
// if(isTimeDomain()) {
|
auto impulse = data.real();
|
||||||
// QString ret;
|
auto step = parentTrace->sample(parentTrace->index(position), Trace::SampleType::TimeStep).y.real();
|
||||||
// ret += "Impulse:"+Unit::ToString(timeData.impulseResponse, "", "m ", 3)+" Step:"+Unit::ToString(timeData.stepResponse, "", "m ", 3)+" Impedance:";
|
ret += "Impulse:"+Unit::ToString(impulse, "", "m ", 3);
|
||||||
// if(isnan(timeData.impedance)) {
|
if(!isnan(step)) {
|
||||||
// ret += "Invalid";
|
ret += " Step:"+Unit::ToString(step, "", "m ", 3);
|
||||||
// } else {
|
if(abs(step) < 1.0) {
|
||||||
// ret += Unit::ToString(timeData.impedance, "Ω", "m k", 3);
|
auto impedance = 50.0 * (1.0 + step) / (1.0 - step);
|
||||||
// }
|
ret += " Impedance:"+Unit::ToString(impedance, "Ω", "m kM", 3);
|
||||||
// return ret;
|
}
|
||||||
// } else
|
}
|
||||||
{
|
return ret;
|
||||||
auto phase = arg(data);
|
|
||||||
return QString::number(toDecibel(), 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4);
|
|
||||||
}
|
}
|
||||||
case Type::Delta:
|
case Type::Delta: {
|
||||||
if(!delta /*|| delta->isTimeDomain() != isTimeDomain()*/) {
|
if(!delta || !delta->isTimeDomain()) {
|
||||||
return "Invalid delta marker";
|
return "Invalid delta marker";
|
||||||
} else {
|
}
|
||||||
// if(isTimeDomain()) {
|
// calculate difference between markers
|
||||||
// // calculate difference between markers
|
auto impulse = data.real() - delta->data.real();
|
||||||
// auto impulse = timeData.impulseResponse - delta->timeData.impulseResponse;
|
QString ret;
|
||||||
// auto step = timeData.stepResponse - delta->timeData.stepResponse;
|
auto timeDiff = position - delta->position;
|
||||||
// auto impedance = timeData.impedance - delta->timeData.impedance;
|
auto distanceDiff = parentTrace->timeToDistance(position) - delta->parentTrace->timeToDistance(delta->position);
|
||||||
// QString ret;
|
ret += "Δ:"+Unit::ToString(timeDiff, "s", "fpnum ", 4) + "/" + Unit::ToString(distanceDiff, "m", "m k", 4);
|
||||||
// ret += "ΔImpulse:"+Unit::ToString(impulse, "", "m ", 3)+" ΔStep:"+Unit::ToString(step, "", "m ", 3)+" ΔImpedance:";
|
ret += " ΔImpulse:"+Unit::ToString(impulse, "", "m ", 3);
|
||||||
// if(isnan(timeData.impedance)) {
|
auto step = parentTrace->sample(parentTrace->index(position), Trace::SampleType::TimeStep).y.real();
|
||||||
// ret += "Invalid";
|
auto stepDelta = delta->parentTrace->sample(delta->parentTrace->index(delta->position), Trace::SampleType::TimeStep).y.real();
|
||||||
// } else {
|
if(!isnan(step) && !isnan(stepDelta)) {
|
||||||
// ret += Unit::ToString(impedance, "Ω", "m k", 3);
|
auto stepDiff = step - stepDelta;
|
||||||
// }
|
ret += " ΔStep:"+Unit::ToString(stepDiff, "", "m ", 3);
|
||||||
// return ret;
|
if(abs(step) < 1.0 && abs(stepDelta) < 1.0) {
|
||||||
// } else {
|
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
|
// calculate difference between markers
|
||||||
auto freqDiff = position - delta->position;
|
auto freqDiff = position - delta->position;
|
||||||
auto valueDiff = data / delta->data;
|
auto valueDiff = data / delta->data;
|
||||||
auto phase = arg(valueDiff);
|
auto phase = arg(valueDiff);
|
||||||
auto db = 20*log10(abs(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);
|
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);
|
break;
|
||||||
ret += ", Ins.Loss: >=" + QString::number(-insertionLoss, 'g', 4) + "db";
|
case Type::Noise:
|
||||||
return ret;
|
return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3);
|
||||||
}
|
case Type::PeakTable:
|
||||||
break;
|
return "Found " + QString::number(helperMarkers.size()) + " peaks";
|
||||||
case Type::Bandpass:
|
case Type::Lowpass:
|
||||||
if(parentTrace->isReflection()) {
|
case Type::Highpass:
|
||||||
return "Calculation not possible with reflection measurement";
|
if(parentTrace->isReflection()) {
|
||||||
} else {
|
return "Calculation not possible with reflection measurement";
|
||||||
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 {
|
} 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);
|
break;
|
||||||
ret += ", Ins.Loss: >=" + QString::number(-insertionLoss, 'g', 4) + "db";
|
case Type::Bandpass:
|
||||||
return ret;
|
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()
|
QString TraceMarker::readableSettings()
|
||||||
{
|
{
|
||||||
// if(timeDomain) {
|
if(isTimeDomain()) {
|
||||||
// switch(type) {
|
switch(type) {
|
||||||
// case Type::Manual:
|
case Type::Manual:
|
||||||
// case Type::Delta: {
|
case Type::Delta:
|
||||||
// QString unit;
|
return Unit::ToString(position, "s", "fpnum ", 4) + "/" + Unit::ToString(parentTrace->timeToDistance(position), "m", "um k", 4);
|
||||||
// if(position <= parentTrace->getTDR().back().time) {
|
default:
|
||||||
// unit = "s";
|
return "Unhandled case";
|
||||||
// } else {
|
}
|
||||||
// unit = "m";
|
} else {
|
||||||
// }
|
|
||||||
// return Unit::ToString(position, unit, "fpnum k", 4);
|
|
||||||
// }
|
|
||||||
// default:
|
|
||||||
// return "Unhandled case";
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Manual:
|
case Type::Manual:
|
||||||
case Type::Maximum:
|
case Type::Maximum:
|
||||||
@ -212,7 +229,39 @@ QString TraceMarker::readableSettings()
|
|||||||
default:
|
default:
|
||||||
return "Unhandled case";
|
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()
|
QString TraceMarker::readableType()
|
||||||
@ -241,12 +290,8 @@ void TraceMarker::traceDataChanged()
|
|||||||
{
|
{
|
||||||
// some data of the parent trace changed, check if marker data also changed
|
// some data of the parent trace changed, check if marker data also changed
|
||||||
complex<double> newdata;
|
complex<double> newdata;
|
||||||
// if (timeDomain) {
|
auto sampleType = isTimeDomain() ? Trace::SampleType::TimeImpulse : Trace::SampleType::Frequency;
|
||||||
// timeData = parentTrace->getTDR(position);
|
newdata = parentTrace->sample(parentTrace->index(position), sampleType).y;
|
||||||
// newdata = complex<double>(timeData.stepResponse, timeData.impulseResponse);
|
|
||||||
// } else {
|
|
||||||
newdata = parentTrace->sample(parentTrace->index(position)).y;
|
|
||||||
// }
|
|
||||||
if (newdata != data) {
|
if (newdata != data) {
|
||||||
data = newdata;
|
data = newdata;
|
||||||
update();
|
update();
|
||||||
@ -276,15 +321,28 @@ void TraceMarker::updateSymbol()
|
|||||||
emit symbolChanged(this);
|
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::Type> TraceMarker::getSupportedTypes()
|
std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
|
||||||
{
|
{
|
||||||
set<TraceMarker::Type> supported;
|
set<TraceMarker::Type> supported;
|
||||||
if(parentTrace) {
|
if(parentTrace) {
|
||||||
// if(timeDomain) {
|
if(isTimeDomain()) {
|
||||||
// // only basic markers in time domain
|
// only basic markers in time domain
|
||||||
// supported.insert(Type::Manual);
|
supported.insert(Type::Manual);
|
||||||
// supported.insert(Type::Delta);
|
supported.insert(Type::Delta);
|
||||||
// } else {
|
} else {
|
||||||
// all traces support some basic markers
|
// all traces support some basic markers
|
||||||
supported.insert(Type::Manual);
|
supported.insert(Type::Manual);
|
||||||
supported.insert(Type::Maximum);
|
supported.insert(Type::Maximum);
|
||||||
@ -311,7 +369,7 @@ std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
@ -319,25 +377,45 @@ std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
|
|||||||
void TraceMarker::constrainPosition()
|
void TraceMarker::constrainPosition()
|
||||||
{
|
{
|
||||||
if(parentTrace) {
|
if(parentTrace) {
|
||||||
// if(timeDomain) {
|
if(parentTrace->size() > 0) {
|
||||||
// if(position < 0) {
|
if(position > parentTrace->maxX()) {
|
||||||
// position = 0;
|
position = parentTrace->maxX();
|
||||||
// } else if(position > parentTrace->getTDR().back().distance) {
|
} else if(position < parentTrace->minX()) {
|
||||||
// position = parentTrace->getTDR().back().distance;
|
position = parentTrace->minX();
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
if(parentTrace->size() > 0) {
|
|
||||||
if(position > parentTrace->maxX()) {
|
|
||||||
position = parentTrace->maxX();
|
|
||||||
} else if(position < parentTrace->minX()) {
|
|
||||||
position = parentTrace->minX();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// }
|
}
|
||||||
traceDataChanged();
|
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)
|
void TraceMarker::assignDeltaMarker(TraceMarker *m)
|
||||||
{
|
{
|
||||||
if(delta) {
|
if(delta) {
|
||||||
@ -347,8 +425,9 @@ void TraceMarker::assignDeltaMarker(TraceMarker *m)
|
|||||||
if(delta && delta != this) {
|
if(delta && delta != this) {
|
||||||
// this marker has to be updated when the delta marker changes
|
// this marker has to be updated when the delta marker changes
|
||||||
connect(delta, &TraceMarker::rawDataChanged, this, &TraceMarker::update);
|
connect(delta, &TraceMarker::rawDataChanged, this, &TraceMarker::update);
|
||||||
|
connect(delta, &TraceMarker::domainChanged, this, &TraceMarker::checkDeltaMarker);
|
||||||
connect(delta, &TraceMarker::deleted, [=](){
|
connect(delta, &TraceMarker::deleted, [=](){
|
||||||
delta = nullptr;
|
assignDeltaMarker(bestDeltaCandidate());
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -377,29 +456,7 @@ void TraceMarker::setType(TraceMarker::Type t)
|
|||||||
vector<helper_descr> required_helpers;
|
vector<helper_descr> required_helpers;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Delta:
|
case Type::Delta:
|
||||||
delta = nullptr;
|
assignDeltaMarker(bestDeltaCandidate());
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Type::Lowpass:
|
case Type::Lowpass:
|
||||||
case Type::Highpass:
|
case Type::Highpass:
|
||||||
@ -560,15 +617,15 @@ void TraceMarker::updateTypeFromEditor(QWidget *w)
|
|||||||
|
|
||||||
SIUnitEdit *TraceMarker::getSettingsEditor()
|
SIUnitEdit *TraceMarker::getSettingsEditor()
|
||||||
{
|
{
|
||||||
// if(timeDomain) {
|
if(isTimeDomain()) {
|
||||||
// switch(type) {
|
switch(type) {
|
||||||
// case Type::Manual:
|
case Type::Manual:
|
||||||
// case Type::Delta:
|
case Type::Delta:
|
||||||
// return new SIUnitEdit("", "fpnum k", 6);
|
return new SIUnitEdit("", "fpnum k", 6);
|
||||||
// default:
|
default:
|
||||||
// return nullptr;
|
return nullptr;
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Manual:
|
case Type::Manual:
|
||||||
case Type::Maximum:
|
case Type::Maximum:
|
||||||
@ -585,34 +642,53 @@ SIUnitEdit *TraceMarker::getSettingsEditor()
|
|||||||
case Type::TOI:
|
case Type::TOI:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceMarker::adjustSettings(double value)
|
void TraceMarker::adjustSettings(double value)
|
||||||
{
|
{
|
||||||
switch(type) {
|
if(isTimeDomain()) {
|
||||||
case Type::Manual:
|
switch(type) {
|
||||||
case Type::Maximum:
|
case Type::Manual:
|
||||||
case Type::Minimum:
|
case Type::Delta: {
|
||||||
case Type::Delta:
|
// check if entered position is time or distance
|
||||||
case Type::Noise:
|
if(value > parentTrace->sample(parentTrace->size() - 1).x) {
|
||||||
default:
|
// entered a distance, convert to time
|
||||||
setPosition(value);
|
setPosition(parentTrace->distanceToTime(value));
|
||||||
/* no break */
|
} else {
|
||||||
case Type::Lowpass:
|
// entered a time, can set directly
|
||||||
case Type::Highpass:
|
setPosition(value);
|
||||||
case Type::Bandpass:
|
}
|
||||||
if(value > 0.0) {
|
}
|
||||||
value = -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();
|
update();
|
||||||
}
|
}
|
||||||
@ -790,3 +866,13 @@ double TraceMarker::getPosition() const
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TraceMarker::isTimeDomain()
|
||||||
|
{
|
||||||
|
if(parentTrace) {
|
||||||
|
if(parentTrace->outputType() == Trace::DataType::Time) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,13 @@ public:
|
|||||||
Trace* trace();
|
Trace* trace();
|
||||||
QString readableData();
|
QString readableData();
|
||||||
QString readableSettings();
|
QString readableSettings();
|
||||||
|
QString tooltipSettings();
|
||||||
QString readableType();
|
QString readableType();
|
||||||
|
|
||||||
double getPosition() const;
|
double getPosition() const;
|
||||||
std::complex<double> getData() const;
|
std::complex<double> getData() const;
|
||||||
bool isMovable();
|
bool isMovable();
|
||||||
|
bool isTimeDomain();
|
||||||
|
|
||||||
QPixmap& getSymbol();
|
QPixmap& getSymbol();
|
||||||
|
|
||||||
@ -56,14 +58,15 @@ signals:
|
|||||||
void traceChanged(TraceMarker *m);
|
void traceChanged(TraceMarker *m);
|
||||||
void beginRemoveHelperMarkers(TraceMarker *m);
|
void beginRemoveHelperMarkers(TraceMarker *m);
|
||||||
void endRemoveHelperMarkers(TraceMarker *m);
|
void endRemoveHelperMarkers(TraceMarker *m);
|
||||||
void timeDomainChanged();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void parentTraceDeleted(Trace *t);
|
void parentTraceDeleted(Trace *t);
|
||||||
void traceDataChanged();
|
void traceDataChanged();
|
||||||
void updateSymbol();
|
void updateSymbol();
|
||||||
|
void checkDeltaMarker();
|
||||||
signals:
|
signals:
|
||||||
void rawDataChanged();
|
void rawDataChanged();
|
||||||
|
void domainChanged();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
@ -97,6 +100,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void constrainPosition();
|
void constrainPosition();
|
||||||
|
TraceMarker *bestDeltaCandidate();
|
||||||
void assignDeltaMarker(TraceMarker *m);
|
void assignDeltaMarker(TraceMarker *m);
|
||||||
void deleteHelperMarkers();
|
void deleteHelperMarkers();
|
||||||
void setType(Type t);
|
void setType(Type t);
|
||||||
@ -108,7 +112,7 @@ private:
|
|||||||
double position;
|
double position;
|
||||||
int number;
|
int number;
|
||||||
// Frequency domain: S parameter
|
// Frequency domain: S parameter
|
||||||
// Time domain: imag part is impulse response, real part is step response
|
// Time domain: impulse response
|
||||||
std::complex<double> data;
|
std::complex<double> data;
|
||||||
QPixmap symbol;
|
QPixmap symbol;
|
||||||
Type type;
|
Type type;
|
||||||
@ -118,11 +122,10 @@ private:
|
|||||||
TraceMarker *delta;
|
TraceMarker *delta;
|
||||||
std::vector<TraceMarker*> helperMarkers;
|
std::vector<TraceMarker*> helperMarkers;
|
||||||
TraceMarker *parent;
|
TraceMarker *parent;
|
||||||
union {
|
// settings for the different marker types
|
||||||
double cutoffAmplitude;
|
double cutoffAmplitude;
|
||||||
double peakThreshold;
|
double peakThreshold;
|
||||||
double offset;
|
double offset;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRACEMARKER_H
|
#endif // TRACEMARKER_H
|
||||||
|
@ -42,7 +42,6 @@ signals:
|
|||||||
void traceRemoved(Trace *t);
|
void traceRemoved(Trace *t);
|
||||||
void requiredExcitation(bool excitePort1, bool excitePort2);
|
void requiredExcitation(bool excitePort1, bool excitePort2);
|
||||||
void traceNameChanged(Trace *t);
|
void traceNameChanged(Trace *t);
|
||||||
void traceTDRstateChanged(Trace *t, bool enabled);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clearVNAData();
|
void clearVNAData();
|
||||||
|
@ -513,6 +513,10 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
// this trace is currently displayed
|
// this trace is currently displayed
|
||||||
double trace_min = trace->minX();
|
double trace_min = trace->minX();
|
||||||
double trace_max = trace->maxX();
|
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) {
|
if(trace_min < min) {
|
||||||
min = trace_min;
|
min = trace_min;
|
||||||
}
|
}
|
||||||
@ -666,7 +670,14 @@ QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlo
|
|||||||
{
|
{
|
||||||
QPointF ret = QPointF(numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN());
|
QPointF ret = QPointF(numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN());
|
||||||
auto data = t->sample(sample);
|
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) {
|
switch(type) {
|
||||||
case YAxisType::Magnitude:
|
case YAxisType::Magnitude:
|
||||||
ret.setY(20*log10(abs(data.y)));
|
ret.setY(20*log10(abs(data.y)));
|
||||||
@ -762,6 +773,9 @@ double TraceXYPlot::nearestTracePoint(Trace *t, QPoint pixel)
|
|||||||
closestXpos = point.x();
|
closestXpos = point.x();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(XAxis.type == XAxisType::Distance) {
|
||||||
|
closestXpos = t->distanceToTime(closestXpos);
|
||||||
|
}
|
||||||
return closestXpos;
|
return closestXpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user