// f0 -- frequency estimation #include // Estimate a local minimum (or maximum) using parabolic // interpolation. The parabola is defined by the points // (x1,y1),(x2,y2), and (x3,y3). float parabolic_interp(float x1, float x2, float x3, float y1, float y2, float y3, float *min) { float a, b, c; float pos; // y1=a*x1^2+b*x1+c // y2=a*x2^2+b*x2+c // y3=a*x3^2+b*x3+c // y1-y2=a*(x1^2-x2^2)+b*(x1-x2) // y2-y3=a*(x2^2-x3^2)+b*(x2-x3) // (y1-y2)/(x1-x2)=a*(x1+x2)+b // (y2-y3)/(x2-x3)=a*(x2+x3)+b a= ((y1-y2)/(x1-x2)-(y2-y3)/(x2-x3))/(x1-x3); b= (y1-y2)/(x1-x2) - a*(x1+x2); c= y1-a*x1*x1-b*x1; *min= c; // dy/dx = 2a*x + b = 0 pos= -b/2.0/a; return pos; } float f0_estimate(float *samples, int n, int m, float threshold, float *results, float *min) // samples is a buffer of samples // n is the number of samples, equals twice longest period, must be even // m is the shortest period in samples // results is an array of size n/2 - m + 1, the number of different lags { // work from the middle of the buffer: int middle = n / 2; int i, j; // loop counters // how many different lags do we compute? float left_energy = 0; float right_energy = 0; // for each window, we keep the energy so we can compute the next one // incrementally. First, we need to compute the energies for lag m-1: for (i = 0; i < m - 1; i++) { float left = samples[middle - 1 - i]; left_energy += left * left; float right = samples[middle + i]; right_energy += right * right; } for (i = m; i <= middle; i++) { // i is the lag and the length of the window // compute the energy for left and right float left = samples[middle - i]; left_energy += left * left; float right = samples[middle - 1 + i]; right_energy += right * right; // compute the autocorrelation float auto_corr = 0; for (j = 0; j < i; j++) { auto_corr += samples[middle - i + j] * samples[middle + j]; } float non_periodic = (left_energy + right_energy - 2 * auto_corr);// / i; results[i - m] = non_periodic; } // normalize by the cumulative sum float cum_sum=0.0; for (i = m; i <= middle; i++) { cum_sum+=results[i-m]; results[i-m]=results[i-m]/(cum_sum/(i-m+1)); } int min_i=m; // value of initial estimate for (i = m; i <= middle; i++) { if (results[i - m] < threshold) { min_i=i; break; } else if (results[i-m]m && i