Fast and Efficient Pitch Detection: Double Trouble

      DSP, Electronics, Infinity, Pitch Detection, Software

This D string was driving my pitch detector nuts. It’s jumping from fundamental to octave and back all over the place. Can’t make up its mind! The effect is like a wacko version of Satch with a whammy pedal gone haywire.

What the hell am I talking about? Last month, I wrote about a fast and efficient software multichannel pitch detection scheme using dual peak-detectors. I needed it to be as efficient as possible, so I can run multiple detectors simultaneously using a small 32 bit microcontroller (MCU). Most of the time, it works really well, except in some cases, like that troublesome D string.

Pesky Harmonics

The scope shot at the right shows what’s happening. I added the white dashed lines to emphasize where the period edges should occur.

D string 3rd fret

The period trigger (see previous article) with dual peak triggers works nicely, but it is not perfect. Sometimes it generates extranous false triggers given waveforms with higher harmonic content, esp. since typical of guitars, the second harmonic is actually more prominent than the fundamental.

Even with dual peak triggers, sometimes, significant amount of harmonics can generate multiple triggers from multiple positive and negative peaks.

In this particular case, there’s an unwanted extra edge caused by overpowering harmonics. This can happen intermittently while the string sustains. Most of the time, it normalizes to the fundamental, as can be seen in the last three cycles. It took me a while to capture that scope shot. But it happens, and when it does, it messes up with pitch analysis.

Note: A simple way to mitigate this issue is by using a low-pass or band-pass filter to tame the energetic high frequencies. But any form of filter will mess up the phase, so that’s out of the question. We need precise alignment of phase in order to induce infinite sustain using resonance and positive feedback. It is not enough to synthesize a waveform having the same frequency as the vibratinD string. The phase must be correct as well. Filtering complicates the problem.

Dissecting the Wave

So here’s what’s happening (illustration below). That energetic waveform sets off false triggers when there are more than two viable peaks in both the positive and negative sides of the waveform. In this particular case, the third peak from the left (ignoring small peaks) is significant enough to set off the positive peak trigger, while the two negative peaks set off the negative peak trigger. In the next cycle, however, the same third peak goes below the threshold and no longer sets off the positive peak trigger.

Notice that the sum of the durations of these edges (T2 + T3) add up to the actual period (T1). So that’s the hint we will use to solve this problem! Over time (milliseconds!), a period filter, averages out the durations T2 and T3 to half the period of T1, hence one octave above the fundamental. So there’s your crazy whammy pedal gone loko!

Based on numerous analysis and tests, the period triggering scheme can generate at most one false trigger per cycle. It is probable but highly unlikely for the period trigger to generate more than one false trigger per cycle, but such an unlikely event can be ignored. We will only deal with single false triggers per cycle.

Period Detector: The Solution

So what do we do? The period detector deals with this period detection business. It has an averaging (low pass) filter maintaining the average period at any given time. For each new period P, a) P is compared with the current average. If P falls within approximately one semitone off the average, then we are good. The low pass filter is updated and a new average is returned.

Why one semitone? We could have been stricter, but we still have to deal with minor pitch changes with each successive cycle to track string bends and vibrato for example.

If the new period P does not fall within one semitone off the average, then b) we save the current period P for later (call that prev). We return the current average.

When a new period comes along, we repeat a). But this time around, if the new period P does not fall within one semitone off the average, then, since we saved the previous period (prev), c) we check if the sum of the previous (prev) and the new period P falls within one semitone off the average. If it does, we’re in luck. We successfully detected a false trigger. We update the averaging low pass filter with the sum of the current period P plus the previous period (prev) and a new average is returned.

Finally, if the sum of the new period P and the previous period (prev) does not fall within one semitone off the average, then d) the sum/2 is added to the running average and a new average is returned.

Works like a charm!