A cheap guitar tuner estimates the pitch of a string from the microphone signal by watching it cross zero. A wave that goes up and down crosses zero twice per cycle, once going down and once going up, so counting crossings over a known time gives the frequency.
Sign rule. A sample counts as positive when it is >= 0 and negative when it is < 0. A crossing happens at index k (for k >= 1) when x[k] and x[k - 1] have different signs under this rule. Sample k was taken at time k / fs seconds.
Estimate. If there are c >= 2 crossings, the first at index a and the last at index b, they span (b - a) / fs seconds and c - 1 half-cycles. The frequency estimate, in hertz, is
freq = ((c - 1) / 2) / ((b - a) / fs)
With fewer than two crossings there is no estimate; use 0.0.
Write estimate_pitch(x, fs) that returns the pair (c, freq). Press Run with plot(x, kind="stem") to see where the signal crosses.
Examples
Input: x = [2, 1, -1, -2, -1, 1, 2, 1, -1, -2], fs = 12
Output: (3, 2.0)
Explanation: crossings at indices 2, 5 and 8. From index 2 to 8 is 6 / 12 = 0.5 s,
and three crossings span two half-cycles, one full cycle: 1 cycle / 0.5 s = 2 Hz.
Input: x = [5, 4, 0, 3], fs = 100
Output: (0, 0.0)
Explanation: 0 counts as positive, so the signal never changes sign.
Constraints
- answers are compared with a tolerance of
1e-6
Goals
- Detect where a signal changes sign, with a fixed rule for samples equal to zero
- Turn the number of crossings and the time they span into a frequency
- Remember that a full cycle crosses zero twice