Problem 386579 · easy · Level 03 Linear Management & Searching

The Propeller Hum the Logger Gets Wrong

aliasing · Nyquist frequency · sampling · modulo

A drone's propellers shake its frame at a frequency f (in hertz), and a cheap vibration logger samples the frame fs times per second. If f is below the Nyquist frequency fs / 2, the logger sees it as it is. Above that, the samples are exactly the samples of a slower wave (aliasing), and the spectrum shows a peak at that slower apparent frequency instead.

The apparent frequency is found by folding:

  1. Adding or removing whole multiples of fs changes nothing at the sampling moments (each sample moves on by whole cycles), so first take r = f % fs, between 0 and fs.
  2. A wave at fs - r gives the same samples as one at r (the same wave run backwards in phase), so if r is above fs / 2, the apparent frequency is fs - r. Otherwise it is r.

Write apparent_frequency(f, fs) that returns the frequency in hertz, between 0 and fs / 2, at which the logger's spectrum shows the tone. Press Run with plot([apparent_frequency(f, 100) for f in range(400)]) to see the zigzag that gives folding its name.

Examples

Input:  f = 30, fs = 100
Output: 30
Explanation: below the Nyquist frequency of 50 Hz, nothing changes.

Input:  f = 70, fs = 100
Output: 30
Explanation: 70 Hz is 20 Hz above 50 Hz and folds to 20 Hz below it.

Input:  f = 260, fs = 100
Output: 40
Explanation: 260 % 100 = 60, which is above 50, so 100 - 60 = 40.

Constraints

  • 0 <= f <= 10**6, 1 <= fs <= 10**5; either may be a float
  • answers are compared with a tolerance of 1e-6, so 30 and 30.0 are both fine

Goals

  • Predict the frequency a too-slow sampler reports for a fast tone
  • Fold a frequency into the range from 0 to fs / 2
  • See why the folded frequency cannot be told apart from the true one
Starting Python…