Improve impulse response interpolation

This commit is contained in:
Jan Käberich 2022-10-20 15:58:57 +02:00
parent 7ca93af620
commit 329f4487ee
3 changed files with 47 additions and 4 deletions

View File

@ -214,7 +214,7 @@ void EyeDiagramDialog::updateThread(unsigned int width, unsigned int height)
updating = false;
return;
}
if(datarate <= trace->getSample(0).x) {
if(datarate <= 0) {
emit calculationStatus("Data rate too low");
updating = false;
return;
@ -347,16 +347,27 @@ void EyeDiagramDialog::updateThread(unsigned int width, unsigned int height)
}
}
auto scale = timestep / (length / (samples - 1));
unsigned long convolutedSize = length / timestep;
if(convolutedSize > inVec.size()) {
// impulse response is longer than what we display, truncate
convolutedSize = inVec.size();
}
impulseVec.resize(convolutedSize);
/*
* we can't use the impulse response directly because we most likely need samples inbetween
* the calculated values. Interpolation is available but if our sample spacing here is much
* wider than the impulse response data, we might miss peaks (or severely miscalculate their
* amplitude.
* Instead, the step response is interpolated and the impulse response determined by deriving
* it from the interpolated step response data. As the step response is the integrated imulse
* response data, we can't miss narrow peaks that way.
*/
double lastStepResponse = 0.0;
for(unsigned long i=0;i<convolutedSize;i++) {
auto x = i*timestep;
impulseVec[i] = tdr->getInterpolatedSample(x).y.real() * scale;
auto step = tdr->getInterpolatedStepResponse(x);
impulseVec[i] = step - lastStepResponse;
lastStepResponse = step;
}
eyeTimeShift += (risetime + falltime) * 1.25 / 4;

View File

@ -106,6 +106,37 @@ double TraceMath::getStepResponse(unsigned int index)
}
}
double TraceMath::getInterpolatedStepResponse(double x)
{
if(stepResponse.size() != data.size()) {
// make sure all the step response data is available
return std::numeric_limits<double>::quiet_NaN();
}
double ret = std::numeric_limits<double>::quiet_NaN();
if(data.size() == 0 || x < data.front().x || x > data.back().x) {
ret = std::numeric_limits<double>::quiet_NaN();
} else {
auto it = lower_bound(data.begin(), data.end(), x, [](const Data &lhs, const double x) -> bool {
return lhs.x < x;
});
if(it->x == x) {
ret = stepResponse[it - data.begin()];
} else {
// no exact match, needs to interpolate
unsigned int highIndex = it - data.begin();
unsigned int lowIndex = highIndex - 1;
auto high = *it;
it--;
auto low = *it;
double alpha = (x - low.x) / (high.x - low.x);
ret = stepResponse[lowIndex] * (1 - alpha) + stepResponse[highIndex] * alpha;
}
}
return ret;
}
TraceMath::Data TraceMath::getInterpolatedSample(double x)
{
Data ret;

View File

@ -91,8 +91,9 @@ public:
static TypeInfo getInfo(Type type);
Data getSample(unsigned int index);
double getStepResponse(unsigned int index);
Data getInterpolatedSample(double x);
double getStepResponse(unsigned int index);
double getInterpolatedStepResponse(double x);
unsigned int numSamples();
static QString dataTypeToString(DataType type);