diff --git a/Software/PC_Application/Traces/trace.cpp b/Software/PC_Application/Traces/trace.cpp index 38e5408..c191804 100644 --- a/Software/PC_Application/Traces/trace.cpp +++ b/Software/PC_Application/Traces/trace.cpp @@ -36,6 +36,13 @@ Trace::Trace(QString name, QColor color, LiveParameter live) dataType = domain; emit outputTypeChanged(dataType); }); + connect(this, &Trace::outputSamplesChanged, [=](unsigned int begin, unsigned int end){ + Q_UNUSED(end); + // some samples changed, delete unwrapped phases from here until the end + if(unwrappedPhase.size() > begin) { + unwrappedPhase.resize(begin); + } + }); } Trace::~Trace() @@ -919,6 +926,27 @@ Trace::Data Trace::sample(unsigned int index, bool getStepResponse) const return data; } +double Trace::getUnwrappedPhase(unsigned int index) +{ + if(index >= size()) { + return 0.0; + } else if(index >= unwrappedPhase.size()) { + // unwrapped phase not available for this entry, calculate + // copy wrapped phases first + unsigned int start_index = unwrappedPhase.size(); + unwrappedPhase.resize(index + 1); + for(unsigned int i=start_index;i<=index;i++) { + unwrappedPhase[i] = arg(lastMath->getSample(i).y); + } + // unwrap the updated part + if(start_index > 0) { + start_index--; + } + Util::unwrapPhase(unwrappedPhase, start_index); + } + return unwrappedPhase[index]; +} + Trace::Data Trace::interpolatedSample(double x) { auto data = lastMath->getInterpolatedSample(x); diff --git a/Software/PC_Application/Traces/trace.h b/Software/PC_Application/Traces/trace.h index 124b43d..676c10c 100644 --- a/Software/PC_Application/Traces/trace.h +++ b/Software/PC_Application/Traces/trace.h @@ -81,6 +81,7 @@ public: }; Data sample(unsigned int index, bool getStepResponse = false) const; + double getUnwrappedPhase(unsigned int index); // returns a (possibly interpolated sample) at a specified frequency/time/power Data interpolatedSample(double x); QString getFilename() const; @@ -186,6 +187,7 @@ private: std::vector mathOps; TraceMath *lastMath; + std::vector unwrappedPhase; void updateLastMath(std::vector::reverse_iterator start); }; diff --git a/Software/PC_Application/Traces/tracexyplot.cpp b/Software/PC_Application/Traces/tracexyplot.cpp index 84f6e3d..22673b0 100644 --- a/Software/PC_Application/Traces/tracexyplot.cpp +++ b/Software/PC_Application/Traces/tracexyplot.cpp @@ -882,6 +882,7 @@ QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type) case YAxisType::Disabled: return "Disabled"; case YAxisType::Magnitude: return "Magnitude"; case YAxisType::Phase: return "Phase"; + case YAxisType::UnwrappedPhase: return "Unwrapped Phase"; case YAxisType::VSWR: return "VSWR"; case YAxisType::Real: return "Real"; case YAxisType::Imaginary: return "Imaginary"; @@ -995,6 +996,9 @@ QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlo case YAxisType::Phase: ret.setY(Util::SparamToDegree(data.y)); break; + case YAxisType::UnwrappedPhase: + ret.setY(t->getUnwrappedPhase(sample) * 180.0 / M_PI); + break; case YAxisType::VSWR: ret.setY(Util::SparamToVSWR(data.y)); break; @@ -1226,6 +1230,7 @@ QString TraceXYPlot::AxisUnit(TraceXYPlot::YAxisType type) switch(type) { case TraceXYPlot::YAxisType::Magnitude: return "dB"; case TraceXYPlot::YAxisType::Phase: return "°"; + case TraceXYPlot::YAxisType::UnwrappedPhase: return "°"; case TraceXYPlot::YAxisType::VSWR: return ""; case TraceXYPlot::YAxisType::ImpulseReal: return ""; case TraceXYPlot::YAxisType::ImpulseMag: return "dB"; diff --git a/Software/PC_Application/Traces/tracexyplot.h b/Software/PC_Application/Traces/tracexyplot.h index 6ff87bc..8d6e0cb 100644 --- a/Software/PC_Application/Traces/tracexyplot.h +++ b/Software/PC_Application/Traces/tracexyplot.h @@ -17,6 +17,7 @@ public: // S parameter options Magnitude, Phase, + UnwrappedPhase, VSWR, Real, Imaginary, diff --git a/Software/PC_Application/Traces/xyplotaxisdialog.cpp b/Software/PC_Application/Traces/xyplotaxisdialog.cpp index 5504853..0ff6f74 100644 --- a/Software/PC_Application/Traces/xyplotaxisdialog.cpp +++ b/Software/PC_Application/Traces/xyplotaxisdialog.cpp @@ -204,6 +204,7 @@ std::set XYplotAxisDialog::supportedYAxis(TraceXYPlot::X case TraceXYPlot::XAxisType::Power: ret.insert(TraceXYPlot::YAxisType::Magnitude); ret.insert(TraceXYPlot::YAxisType::Phase); + ret.insert(TraceXYPlot::YAxisType::UnwrappedPhase); ret.insert(TraceXYPlot::YAxisType::VSWR); ret.insert(TraceXYPlot::YAxisType::Real); ret.insert(TraceXYPlot::YAxisType::Imaginary); diff --git a/Software/PC_Application/Util/util.cpp b/Software/PC_Application/Util/util.cpp index fe2e2ab..3395869 100644 --- a/Software/PC_Application/Util/util.cpp +++ b/Software/PC_Application/Util/util.cpp @@ -2,12 +2,17 @@ #include -void Util::unwrapPhase(std::vector &phase) +void Util::unwrapPhase(std::vector &phase, unsigned int start_index) { - for (unsigned int i = 1; i < phase.size(); i++) { - double d = phase[i] - phase[i-1]; - d = d > M_PI ? d - 2 * M_PI : (d < -M_PI ? d + 2 * M_PI : d); - phase[i] = phase[i-1] + d; + for (unsigned int i = start_index + 1; i < phase.size(); i++) { + int d = trunc(phase[i] - phase[i-1]) / M_PI; + if(d > 0) { + // there is larger than a 180° shift between this and the previous phase + phase[i] -= 2*M_PI*(int)((d+1)/2); + } else if(d < 0) { + // there is larger than a -180° shift between this and the previous phase + phase[i] -= 2*M_PI*(int)((d-1)/2); + } } } diff --git a/Software/PC_Application/Util/util.h b/Software/PC_Application/Util/util.h index 30a61e6..07099e4 100644 --- a/Software/PC_Application/Util/util.h +++ b/Software/PC_Application/Util/util.h @@ -66,7 +66,7 @@ namespace Util { return brightness > 0.6 ? Qt::black : Qt::white; } - void unwrapPhase(std::vector &phase); + void unwrapPhase(std::vector &phase, unsigned int start_index = 0); // input values are Y coordinates, assumes evenly spaced linear X values from 0 to input.size() - 1 void linearRegression(const std::vector &input, double &B_0, double &B_1);