Skip to content

How the Gyro Filters Work

The rate loop flies the vehicle from the gyro, and the gyro is bolted to a frame that four spinning rotors shake. It measures the vehicle’s turning and the vibration together. The vibration is loud and narrow: it sits at each rotor’s rotation frequency and at whole multiples of it, the harmonics. If it reaches the rate loop, the loop treats the vibration as turning and drives the motors against it. The motors run hot, the vibration gets worse, and in the worst case the loop chases it into an oscillation.

The filters take the vibration out before the rate loop sees it. This page builds up how, in four steps:

  1. one notch;
  2. notches that follow the rotors;
  3. what happens at low throttle;
  4. what all filtering costs.

Every animation plays a trace recorded from the filters’ own C++, and the scenario is linked under each player. Its spectrograms are computed in that C++ too. The throttle-sweep widget reruns that C++, compiled to WebAssembly, in your browser. The controls and keys are described on the Trace Player page.

RP-1 rotorsRotor speedFundamental2nd harmonic3rd harmonic
Idle (in these scenarios)440 rad/s70 Hz140 Hz210 Hz
Hover1660 rad/s264 Hz528 Hz792 Hz
Maximum3672 rad/s584 Hz1168 Hz1753 Hz

The vehicle’s own motion is slow by comparison: the rate loop’s crossover is at 6.3 Hz. Between the two lies a gap of more than a decade, and the filters work in that gap. The scenarios’ gyro signal has three parts:

  • a 5 Hz roll rate of 0.5 rad/s;
  • the first three harmonics of four rotors spread ±5 % around one another, 0.1, 0.05, and 0.03 rad/s at hover and growing with the square of the speed;
  • 0.002 rad/s of sensor noise.

These amplitudes are illustrative; flight logs set them for a real vehicle.

A spectrogram shows the signal as frequency against time: each column is the spectrum of the last 32 ms, and the colour is the level in dB, from −60 dB (pale) to 0 dB (dark). A steady tone is a horizontal line, and a rotor speeding up is a line that climbs. The part after the cursor is dimmed, so the spectrogram fills in as the trace plays.

A notch is a filter with a gain of exactly zero at one frequency, f₀, and close to one everywhere else. How wide the dip is depends on the quality factor q: the band where the gain is below −3 dB (half the power) is about f₀/q wide. Here f₀ is RP-1’s hover fundamental, 264 Hz, and q = 5.

Before you play: a tone sweeps from 50 Hz to 650 Hz through the notch. Over what range of frequencies does the notch take the tone away?

What does one notch do to a tone that sweeps through it? 1× real time
Output spectrogram notch centre -60 dB0 dB (level, dB re 1)

Gain [dB] measured response()
Tone frequency [Hz] tone
t = 0.000 s / 4.000 s

Keys (with the player focused): Space play/pause · ← → one sample (Shift: ten) · Home/End · [ ] speed

A single notch at 264 Hz with q = 5, at the 8 kHz gyro rate, filters a unit tone that rises from 50 Hz to 650 Hz over 4 s. In the output spectrogram the tone is a rising line, which thins where it crosses the notch (orange). The measured gain, the output's RMS over the input's across each 25 ms, follows the design's own response() all the way. It falls below −3 dB between 239 Hz and 291 Hz, a band 52 Hz wide, and to −26 dB in the 25 ms that straddle 264 Hz, where the gain is zero.

  1. a unit tone at 50 Hz: the notch passes it
  2. the tone reaches the notch's lower −3 dB edge
  3. the tone crosses f0 = 264 Hz, where the notch's gain is zero
  4. past the upper −3 dB edge: unity gain again
  • ✓ passBB-V1 width_error_hz = 0.472 Hz (<= 3.75), computed by the scenario harness

The −3 dB band is 52 Hz wide, as the closed form for this design predicts, (f_s/π)·atan(sin ω₀ / 2q) = 52.5 Hz. The dip is narrow: at 6.3 Hz, where the rate loop works, the notch’s gain is 1 to within 0.01 %. A notch costs the rate loop little, as long as it sits where the vibration is.

A fixed notch only helps while the rotor runs at the speed it was set for. The rotors change speed with every throttle movement and every correction, so RpmNotch moves its notches with them. Each tick it is given the four rotor speeds, from the ESC telemetry on hardware or the model in simulation. It places a notch at each of the first three harmonics of each rotor, twelve in all, and runs the gyro through all of them in series.

Before you play: the throttle sweeps from idle to 90 % of the rotors’ maximum speed. The top spectrogram is the raw gyro. In the bottom one, filtered by the tracked notches, the orange lines are the notch centres. What is left of the vibration, and where?

Do the notches keep up with a throttle sweep? 1× real time

Predict, then try it: give the notches a rotor speed error of 2 %, then 5 %. How much vibration gets through? Then widen the notches to q = 2 and try 5 % again.

Showing the recorded run. Moving a slider reruns the same C++ in your browser (WebAssembly).
Raw gyro -60 dB0 dB (level, dB re 1 rad/s)

After the tracked notches notch centres (where on) -60 dB0 dB (level, dB re 1 rad/s)

Vibration left, per 25 ms [dB] notches fixed at hover tracked notches criterion
t = 0.000 s / 4.000 s

Keys (with the player focused): Space play/pause · ← → one sample (Shift: ten) · Home/End · [ ] speed

The gyro sees a 5 Hz roll rate, the first three harmonics of four rotors spread ±5 %, and sensor noise, at 8 kHz. The rotors idle with fundamentals near 70 Hz, sweep to 500–552 Hz between 0.5 s and 3.5 s, and hold. In the raw spectrogram twelve lines climb, the third harmonics to 1.6 kHz. In the filtered one they are gone wherever the notches sit, except at low throttle: below 100 Hz the fundamentals' notches are off, and between 100 Hz and 150 Hz they fade in. Once all twelve are on, the tracked notches leave −41 dB to −78 dB of the vibration in each 25 ms, and −71 dB overall; when the speeds hold still at the top, the notches settle and it falls below −100 dB. Notches fixed at the hover speeds reach −35 dB only while the rotors pass hover, near 1.8 s. Pass criteria: the vibration left by the tracked notches with all twelve on at most −30 dB, and the 5 Hz motion within 2 % of its amplitude.

  1. throttle up: every fundamental is below min_hz (100 Hz), so those notches are off
  2. the slowest rotor's fundamental reaches 100 Hz: its notch starts to fade in
  3. every fundamental past 150 Hz: all twelve notches on
  4. passing hover, where the fixed notches sit
  5. held at 90 % of maximum speed: fundamentals 500 to 552 Hz
  • ✓ passBB-I2 vibration_residual_db = -70.68 dB (<= -30), computed by the scenario harness
  • ✓ passBB-C2 motion_gain_error = 2.55e-4 (<= 0.02), computed by the scenario harness

The tracked notches stay on the harmonics as the rotors speed up, and the vibration they leave is 40 to 80 dB down: a hundredth to a ten-thousandth of its amplitude. While the speeds change, each notch trails its harmonic slightly; once they hold still, the notches settle and the vibration left falls below −100 dB. A bank of notches fixed at hover does well only while the rotors are near hover. Below and above it, it misses the lines and leaves −10 dB or more.

The notches can only be as good as the speeds they are given. With a 2 % speed error, the q = 5 notches sit a tenth of their −3 dB width off the harmonics, and the vibration left rises from −71 dB to −32 dB, just inside the −30 dB criterion. At 5 % it is −19 dB, and the criterion fails. Wider notches tolerate more: at q = 2 a 5 % error still leaves only −44 dB, at a cost that section 4 shows.

In the first half second the fundamentals, at 66 to 74 Hz, pass through the filtered spectrogram untouched. That is deliberate. A notch removes a band, not a line, and a notch at 70 Hz with q = 5 would cut into the frequencies the rate loop works at, and add phase lag there. So RpmNotch has a floor, min_hz = 100 Hz by default. A notch whose harmonic is below it sits at min_hz with weight 0, and the stage passes its input through unchanged. Between min_hz and min_hz + fade_hz (150 Hz) the notch fades in linearly, so that it does not switch on with a jump.

Each notch’s output is blended as y ← y + w·(N(y) − y), with weight w from 0 to 1. Every notch keeps filtering even at w = 0, so its history is current when it fades back in. The second and third harmonics are above 100 Hz from the start, so their notches are on through the idle.

A filter cannot remove a frequency without delaying the frequencies it keeps, and delay is what the rate loop can least afford: it costs phase margin, the loop’s distance from oscillating. So the gyro chain is part of the rate loop’s design. Here it is the chain of the delay-budget test:

  • a 2nd-order Butterworth low-pass at 101 Hz, 16 times the crossover, for the broadband noise;
  • the twelve RPM notches at the hover speeds.

Before you play: a 1 rad/s roll-rate step reaches the gyro at 5 ms. How long does each filter take to pass on half of it?

How long do the gyro filters delay a change in roll rate? 1× real time
Roll rate [rad/s] true notches low-pass chain
t = 0.000 s / 0.040 s

Keys (with the player focused): Space play/pause · ← → one sample (Shift: ten) · Home/End · [ ] speed

A 1 rad/s roll-rate step at 5 ms, at the 8 kHz gyro rate, with no vibration added, through three filters: the twelve RPM notches at hover, a 101 Hz Butterworth low-pass, and the two in series. The notches pass the step's edge at once but ring at the rotor harmonics, up to 1.24 rad/s, because they have taken those frequencies out of the step. The low-pass reaches half the step 2.25 ms after it, with 4 % overshoot. The whole chain takes 3.4 ms, and its output is smooth. Pass criterion: the rate loop's phase margin with the chain in the loop, computed from the filters' response(), at least 45°. It is 53.0°, down from 60.1° with no filters.

  1. a 1 rad/s roll-rate step reaches the gyro
  2. the chain's output reaches half the step, 3.4 ms after it
  • ✓ passBB-C2 rate_loop_phase_margin_deg = 53.04 deg (>= 45), computed by the scenario harness

At the crossover, 6.3 Hz, the chain lags by 7.1°: 5.1° from the low-pass and 2.0° from the twelve notches. The rate loop’s phase margin falls from 60.1° to 53.0°, inside the 45° budget with 8° to spare. That spare is what a deployment spends on the rest of its delay: the IMU, the ESC, and the loop’s own scheduling. Widening the notches to q = 2 costs 5.0° instead of 2.0°. The deployment guide works through the trade.

  • The developer guide has the designs, the fault handling, and the contracts.
  • The V&V plan has the acceptance criteria and what the tests show.
  • The deployment guide covers the gyro rate, the telemetry, choosing q and the floor, and what happens at a 1 kHz gyro.