As a followup to my True Peak detection question, I'm trying to implement a detection method by following this documentation using the Catmull-Rom interpolation method.
What I've done so far can be seen in my Desmos worksheet (includes sample of y
-data which creates the issue in question).
I've (probably) got stationary points solving to work correctly but, calculation used with the cases not having critical points and are solved through finding inflection point using equation $x = \frac{-b}{3a}$ are not giving proper results. I suppose the result could be at least improved by using suitable conditional clauses. As seen in the Desmos worksheet, resulting x
values are used as an input for the interpolation function to get the peak level solved (yi = interpolation(y, x)
, where y
is up-sampled data, interpolated using half-polyphase FIR low-pass filter).
Any suggestions to get this issue solved?
Edit: Here are some C++ code at Compiler Explorer.
catmullrom4() is the function name related to this issue:
float catmullrom4(float* y){
// Solve tp through stationary and inflection points
float a, b, c, d, x, yi;
a = -0.5f*y[0] + 1.5f*y[1] - 1.5f*y[2] + 0.5f*y[3];
b = y[0] - 2.5f*y[1] + 2.f*y[2] - 0.5f*y[3];
c = -0.5f*y[0] + 0.5f*y[2];
d = y[1];
float s1 = (-b - std::sqrt((b*b) - (3.0f*a*c))) / (3.0f*a);
float s2 = (-b + std::sqrt((b*b) - (3.0f*a*c))) / (3.0f*a);
float s3 = -b/(3.0f*a);
float abs1 = std::abs(s1);
float abs2 = std::abs(s2);
float abs3 = std::abs(s3);
if(abs2 > abs1 ){
x = s1;
}
else if (abs1 > abs2){
x = s2;
}
else{
x = s3;
if (abs3 > 3.0f){
x = 1.0f;
}
else if (abs3 < 2.0f){
x = 0.0f;
}
}
return (x * (x * (a * x + b) + c) + d);
}
EDIT: Updated the Desmos and Compiler Explorer links