group delay option for Y axis

This commit is contained in:
Jan Käberich 2021-12-10 23:36:28 +01:00
parent 75f4ee245f
commit 0d6dac4969
6 changed files with 99 additions and 36 deletions

View file

@ -17,22 +17,6 @@
using namespace std;
const set<TraceXYPlot::YAxisType> TraceXYPlot::YAxisTypes = {TraceXYPlot::YAxisType::Disabled,
TraceXYPlot::YAxisType::Magnitude,
TraceXYPlot::YAxisType::Phase,
TraceXYPlot::YAxisType::VSWR,
TraceXYPlot::YAxisType::Real,
TraceXYPlot::YAxisType::Imaginary,
TraceXYPlot::YAxisType::SeriesR,
TraceXYPlot::YAxisType::Reactance,
TraceXYPlot::YAxisType::Capacitance,
TraceXYPlot::YAxisType::Inductance,
TraceXYPlot::YAxisType::QualityFactor,
TraceXYPlot::YAxisType::ImpulseReal,
TraceXYPlot::YAxisType::ImpulseMag,
TraceXYPlot::YAxisType::Step,
TraceXYPlot::YAxisType::Impedance};
TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
: TracePlot(model, parent)
{
@ -333,8 +317,11 @@ void TraceXYPlot::updateContextMenu()
bool TraceXYPlot::dropSupported(Trace *t)
{
Q_UNUSED(t)
// all kind of traces can be dropped, the graph will be reconfigured to support the dropped trace if required
if(domainMatch(t) && !supported(t)) {
// correct domain configured but Y axis do not match, prevent drop
return false;
}
// either directly compatible or domain change required
return true;
}
@ -823,12 +810,14 @@ QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type)
case YAxisType::Capacitance: return "Capacitance";
case YAxisType::Inductance: return "Inductance";
case YAxisType::QualityFactor: return "Quality Factor";
case YAxisType::GroupDelay: return "Group delay";
case YAxisType::ImpulseReal: return "Impulse Response (Real)";
case YAxisType::ImpulseMag: return "Impulse Response (Magnitude)";
case YAxisType::Step: return "Step Response";
case YAxisType::Impedance: return "Impedance";
default: return "Unknown";
case YAxisType::Last: return "Unknown";
}
return "Missing case";
}
void TraceXYPlot::enableTraceAxis(Trace *t, int axis, bool enabled)
@ -861,27 +850,26 @@ void TraceXYPlot::enableTraceAxis(Trace *t, int axis, bool enabled)
}
}
bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
bool TraceXYPlot::domainMatch(Trace *t)
{
switch(XAxis.type) {
case XAxisType::Frequency:
if(t->outputType() != Trace::DataType::Frequency) {
return false;
}
break;
return t->outputType() == Trace::DataType::Frequency;
case XAxisType::Distance:
case XAxisType::Time:
if(t->outputType() != Trace::DataType::Time) {
return false;
}
break;
return t->outputType() == Trace::DataType::Time;
case XAxisType::Power:
if(t->outputType() != Trace::DataType::Power) {
return false;
}
break;
default:
break;
return t->outputType() == Trace::DataType::Power;
case XAxisType::Last:
return false;
}
return false;
}
bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
{
if(!domainMatch(t)) {
return false;
}
switch(type) {
@ -897,6 +885,11 @@ bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
return false;
}
break;
case YAxisType::GroupDelay:
if(t->isReflection()) {
return false;
}
break;
default:
break;
}
@ -946,6 +939,38 @@ QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlo
case YAxisType::QualityFactor:
ret.setY(Util::SparamToQualityFactor(data.y));
break;
case YAxisType::GroupDelay: {
constexpr int requiredSamples = 5;
if(t->size() < requiredSamples) {
// unable to calculate
ret.setY(0.0);
break;
}
// needs at least some samples before/after current sample for calculating the derivative.
// For samples too far at either end of the trace, return group delay of "inner" trace sample instead
if(sample < requiredSamples / 2) {
return traceToCoordinate(t, requiredSamples / 2, type);
} else if(sample >= t->size() - requiredSamples / 2) {
return traceToCoordinate(t, t->size() - requiredSamples / 2 - 1, type);
} else {
// got enough samples at either end to calculate derivative.
// acquire phases of the required samples
std::vector<double> phases;
phases.reserve(requiredSamples);
for(unsigned int index = sample - requiredSamples / 2;index <= sample + requiredSamples / 2;index++) {
phases.push_back(arg(t->sample(index).y));
}
// make sure there are no phase jumps
Util::unwrapPhase(phases);
// calculate linearRegression to get derivative
double B_0, B_1;
Util::linearRegression(phases, B_0, B_1);
// B_1 now contains the derived phase vs. the sample. Scale by frequency to get group delay
double freq_step = t->sample(sample).x - t->sample(sample - 1).x;
ret.setY(-B_1 / (2.0*M_PI * freq_step));
}
}
break;
case YAxisType::ImpulseReal:
ret.setY(real(data.y));
break;
@ -1103,6 +1128,7 @@ QString TraceXYPlot::AxisUnit(TraceXYPlot::YAxisType type)
case TraceXYPlot::YAxisType::ImpulseMag: return "db";
case TraceXYPlot::YAxisType::Step: return "";
case TraceXYPlot::YAxisType::Impedance: return "Ohm";
case TraceXYPlot::YAxisType::GroupDelay: return "s";
default: return "";
}
}