| 153 | } |
| 154 | |
| 155 | double FFTFrame::extractAverageGroupDelay() |
| 156 | { |
| 157 | float * realP = realData(); |
| 158 | float * imagP = imagData(); |
| 159 | |
| 160 | double aveSum = 0.0; |
| 161 | double weightSum = 0.0; |
| 162 | double lastPhase = 0.0; |
| 163 | |
| 164 | int halfSize = fftSize() / 2; |
| 165 | |
| 166 | const double kSamplePhaseDelay = (2.0 * static_cast<double>(LAB_PI)) / double(fftSize()); |
| 167 | |
| 168 | // Calculate weighted average group delay |
| 169 | for (int i = 0; i < halfSize; i++) |
| 170 | { |
| 171 | Complex c(realP[i], imagP[i]); |
| 172 | double mag = abs(c); |
| 173 | double phase = arg(c); |
| 174 | |
| 175 | double deltaPhase = phase - lastPhase; |
| 176 | lastPhase = phase; |
| 177 | |
| 178 | // Unwrap |
| 179 | if (deltaPhase < -static_cast<double>(LAB_PI)) |
| 180 | deltaPhase += 2.0 * static_cast<double>(LAB_PI); |
| 181 | if (deltaPhase > static_cast<double>(LAB_PI)) |
| 182 | deltaPhase -= 2.0 * static_cast<double>(LAB_PI); |
| 183 | |
| 184 | aveSum += mag * deltaPhase; |
| 185 | weightSum += mag; |
| 186 | } |
| 187 | |
| 188 | // Note how we invert the phase delta wrt frequency since this is how group delay is defined |
| 189 | double ave = aveSum / weightSum; |
| 190 | double aveSampleDelay = -ave / kSamplePhaseDelay; |
| 191 | |
| 192 | // Leave 20 sample headroom (for leading edge of impulse) |
| 193 | if (aveSampleDelay > 20.0) |
| 194 | aveSampleDelay -= 20.0; |
| 195 | |
| 196 | // Remove average group delay (minus 20 samples for headroom) |
| 197 | addConstantGroupDelay(-aveSampleDelay); |
| 198 | |
| 199 | // Remove DC offset |
| 200 | realP[0] = 0.0f; |
| 201 | |
| 202 | return aveSampleDelay; |
| 203 | } |
| 204 | |
| 205 | void FFTFrame::addConstantGroupDelay(double sampleFrameDelay) |
| 206 | { |
no outgoing calls
no test coverage detected