I'm using a phototransistor and an optical chopper to measure the angular velocity of a wheel, much like how mechanical mice used to work. The signal looks like a triangle wave with some noise in it, and I'd like to get smooth and fairly low-latency measurements, between 1 and 100 hertz. This is for a user interface, so low-latency here means a few milliseconds.

I started by counting zero crossings, which works well for higher speeds, but at low speeds there are few crossings. So I'd like to extract phase information from the signal to get a better estimates at low speeds.

When counting zero crossings, I get two ticks per cycle and no information in between. I hacked up a way to get four ticks per cycle, somewhat unevenly spaced:

  enum Phase { night, morning, day, evening };
  const int phasesPerCycle = evening + 1;

  Phase phase = night;

  Phase findPhase(float v) {
    // To avoid noise jiggling the phase back and forth without cycling, always move forward.
    // (Also, the threshold for ending day or night is closer to zero.)
    switch (phase) {
      case morning:
        phase = (v > threshold) ? day : morning;
      case day:
        phase = (v < threshold * 0.9) ? evening : day;
      case evening:
        phase = (v < -threshold) ? night : evening;
      case night:
        phase = (v > -threshold * 0.9) ? morning : night;
    return phase;

This gives me a bit more information, but I'm wondering if there's a way to do better. Is there a way to extract a continuous estimate of the phase, as a floating point number that increases from 0 to 1 for each cycle? What sort of search terms could I use to look into research about this?

An alternate approach would be to change the hardware by adding gearing to increase the speed of the optical chopper wheel, or increase the size of the wheel. However, I'm wondering what can be done just using better signal processing with the signal I have.

(Edit: in the end I decided that having two phototransistors ninety degrees out of phase is better than what I was trying to do here. Leaving the question as is, though, for reference.)

  • $\begingroup$ What is the value of threshold? Or what is the acceptable range of values for threshold? This thing looks kinda like a 4-quadrant quantizer with feedback, which gives it hysteresis. I understand that this puts in a little "slop" or "dead zone", which is a non-linearity with hysteresis. $\endgroup$ Apr 8, 2022 at 5:52
  • $\begingroup$ Currently it's 150, where I expect a peak-to-peak amplitude of about 500, but quite a bit shorter for faster frequencies. (Chosen empirically.) $\endgroup$ Apr 8, 2022 at 22:42
  • $\begingroup$ Do you know the amplitude range of the triangle wave? If so, can the problem be reduced to noise-robust estimating the slope of the triangle, taking care of «wrap around» and infering instantaneous frequency from that? $\endgroup$
    – Knut Inge
    May 11, 2022 at 8:14
  • $\begingroup$ Yes, I had been thinking of something like that. The slope seems noisy though. Taking the slope is basically a high-pass filter. $\endgroup$ May 12, 2022 at 14:41

1 Answer 1


Consider using the FFT. From a "phase detector" viewpoint, the FFT is effectively a bank of multiple phase detectors working in parallel complete with processing gain over the number of samples used (which is balanced with the coherence time of the signal and resources allowed).

A phase detector is created by taking the product of the signal with a sinusoidal reference, and low pass filtering to remove the sum frequency term: since $2\cos(\alpha)\cos(\beta) = \cos(\alpha+\beta) + cos(\alpha-\beta)$; with two signals at same frequency but different phase, we would get twice the frequency and the difference which is the phase alone). The FFT does all this for us, with each frequency bin as a reference.

Alternatively, a quadrature phase detector (2 multipliers with a sine reference for one and a cosine reference for the other each followed by a low pass filter) could be used directly to extract the instantaneous phase vs time relative to the reference signal.

  • $\begingroup$ I guess since this is real time, it should be a sliding DFT? (I know nothing of these, I just looked for real time FFT algorithms and saw some references to it.) $\endgroup$ Apr 8, 2022 at 22:54
  • $\begingroup$ Yes- you could do that. In that case you would get the identical result as a bank of moving average linear phase bandpass filters with a delay equal to (N-1)/2, each having a Sinc function frequency response. If you do an FFT block by block, then the result is identical to a phase detector at each bin frequency and moving average filter over that block duration. Each successive block will report the phase change over that frame time. $\endgroup$ Apr 9, 2022 at 1:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.