Take the RC low-pass filter and pin down its cutoff frequency, the speed where the output amplitude falls to about 70.7% of the input. Predict fc = 1/(2πRC) for a 10 kΩ and 0.1 µF filter (about 160 Hz), then drive it at different speeds and watch the output swing shrink to confirm the trend and the −3 dB idea.
Turn an RC circuit into a low-pass filter on the Pico W: drive it with a square wave from a GPIO, read the output with the ADC, and plot the commanded input beside the measured output. See intuitively why slow changes pass through while fast ones get smoothed away.
Keep the Pico W RC circuit and swap in different resistors and capacitors to see how each changes the charging time. Predict faster or slower with τ = R × C, measure the crossing at 2.09 V, and build a table confirming that more R or more C means a longer charge.
Reuse the Pico W resistor–capacitor circuit to measure the time constant τ = RC: find when the capacitor reaches ~63.2% of the supply, then compare your measured τ against the calculated one.
Build a resistor–capacitor circuit on the Pico W, measure the capacitor's voltage with the ADC, and plot the charging and discharging curves over time.
test

How to use the Plotter to view data in a line graph as it is printed from a device
how to make the built in led blink
fc = 1 / (2πRC) and what it means.You already know this filter smooths fast changes and passes slow ones — you watched the output swing shrink as you drove it faster. This lesson pins down the changeover speed with a number: the cutoff frequency, written fc, the frequency where the filter starts to noticeably hold the output back.
Before you build anything, work out where that cutoff should land for these parts. The formula (which you'll meet properly after you measure) is fc = 1 / (2πRC). With a 10 kΩ resistor and a 0.1 µF capacitor:
Plain Text
fc = 1 / (2 × π × 10000 Ω × 0.0000001 F) ≈ 1 / (2 × π × 0.001) ≈ 159 Hz (about 160 Hz)
So predict this: at drive speeds well below about 160 Hz the output should swing nearly as far as the input, and as you push the drive frequency up toward 160 Hz the output swing should shrink. Write down that prediction, then build the circuit and measure the swing to check it.
This is the same RC low-pass filter you built in the previous lesson — nothing to rewire if it's still on your breadboard. A resistor in series feeds a capacitor to ground; the Pico drives one end of the resistor with a square wave, and the point where the resistor meets the capacitor is the output node that the ADC reads.
f24 and the other in f23.GP15 to the resistor leg in row 24. This end drives the filter with the square wave.GP26 to the output node in row 23. GP26 is analog input ADC0.Note: The ceramic capacitor is non-polarised — it has no positive or negative leg, so it goes in either way round.
The output node sits between the resistor and the capacitor and is driven from 3.3 V through the resistor, so its voltage always stays between 0 V and 3.3 V. That keeps it inside the safe range for the ADC pin, which must never see more than 3.3 V.
The wiring diagram for this filter lives in the lesson's repository.
This program drives the same filter with a square wave on GP15 and reads the output on GP26, just like the previous lesson, but now the job is to measure how big the output swing is at a chosen drive speed. Each pass it prints the commanded input and the measured output for the plotter, and it also tracks the smallest and largest output it sees over a measurement window. At the end of each window it prints a summary line: the drive frequency, the output's peak-to-peak swing, and the output swing as a fraction of the input's full 0-to-3.3 V swing. That fraction is the number to watch. Type it in and run it.
Python
from machine import Pin, ADC
import time
drive = Pin(15, Pin.OUT) # GP15 drives the filter input through the 10 kOhm resistor
adc = ADC(26) # GP26 / ADC0 reads the filter output (the RC node)
SAMPLE_STEP = 0.02 # seconds between readings (~50 samples per second)
INPUT_SWING = 3.3 # the input square wave swings the full 0 to 3.3 V
# Set the square-wave speed by flipping the input every N samples. One half-cycle lasts
# N * SAMPLE_STEP seconds, so the drive frequency is about 1 / (2 * N * SAMPLE_STEP) Hz.
# N = 25 -> ~1 Hz, N = 5 -> ~5 Hz, N = 2 -> ~12.5 Hz. Smaller N means a faster drive.
SAMPLES_PER_HALF_CYCLE = 25
# How many samples to watch before reporting the output swing. A few full cycles is plenty.
WINDOW_SAMPLES = 200
# The drive frequency this setting produces, worked out from the numbers above.
drive_freq = 1.0 / (2 * SAMPLES_PER_HALF_CYCLE * SAMPLE_STEP)
# At low drive frequencies the output follows the input and swings almost the full 3.3 V, so
# the ratio below is near 1.0 (100%). As the drive speeds up toward and past the filter's
# cutoff, the output can't keep up and its swing shrinks, so the ratio falls. The cutoff is
# the frequency where the output swing drops to about 70.7% of the input, and the next
# section gives that a formula.
level = 1 # start driving the input high
count = 0 # samples counted in the current half-cycle
window_count = 0 # samples counted in the current measurement window
v_out_min = INPUT_SWING # smallest output seen this window (start high so any reading beats it)
v_out_max = 0.0 # largest output seen this window (start low so any reading beats it)
while True:
drive.value(level) # command the input high or low
v_in = level * INPUT_SWING # commanded input, in volts (0 or 3.3)
v_out = adc.read_u16() * 3.3 / 65535 # measured output, in volts
print("{:.3f},{:.3f}".format(v_in, v_out)) # CSV: input series, output series
time.sleep(SAMPLE_STEP) # ~50 samples per second
# Track the smallest and largest output over this measurement window.
if v_out < v_out_min:
v_out_min = v_out
if v_out > v_out_max:
v_out_max = v_out
count = count + 1
if count >= SAMPLES_PER_HALF_CYCLE: # time to flip the square wave
level = 0 if level else 1
count = 0
window_count = window_count + 1
if window_count >= WINDOW_SAMPLES: # window done: report the output swing
output_swing = v_out_max - v_out_min # measured peak-to-peak output, in volts
ratio = output_swing / INPUT_SWING # output swing as a fraction of the input
# Summary line (starts with #, so the plotter ignores it and you read it in the log):
print("# drive_freq={:.1f}Hz output_swing={:.3f}V ratio={:.1f}% (cutoff ~= 70.7%)".format(
drive_freq, output_swing, ratio * 100))
# Reset for the next window.
window_count = 0
v_out_min = INPUT_SWING
v_out_max = 0.0Each plotted line is two numbers: the input voltage the code just drove, then the output it measured, so the plotter draws them as two lines on one time axis. Every WINDOW_SAMPLES readings the code also prints a summary line starting with #, the drive frequency, the measured output swing in volts, and that swing as a percentage of the input's full 0-to-3.3 V swing. The plotter skips lines beginning with #, so those summaries show up in the serial log for you to read. New to the plotter? See Using the Plotter.
To characterise the filter, rerun the program with different SAMPLES_PER_HALF_CYCLE values, smaller numbers drive faster, and note the reported ratio each time. At slow drive speeds the ratio sits near 100%; as you speed up, it falls. The frequency where it reaches about 70.7% is the cutoff, and the next section explains why.
The number you watched fall — the output swing as a fraction of the input — is the filter's response. At slow drive speeds it sits near 100%: the capacitor has time to charge and drain fully, so the output swings almost as far as the input. As the drive speeds up the capacitor runs out of time, the swing shrinks, and the ratio drops.
There's a specific speed where that drop reaches a marker worth naming. The cutoff frequency fc is the frequency where the output amplitude falls to about 70.7% of the input — that's 1/√2, roughly 0.707. Below fc the filter mostly lets the signal through; above it, the signal is increasingly cut down.
fc depends only on the resistor and the capacitor:
Plain Text
fc = 1 / (2πRC)
Plug in this filter's parts — R = 10 kΩ, C = 0.1 µF — and you get the number you predicted in the Background: about 160 Hz. Bigger R or bigger C means a slower cutoff (a lower fc), because a larger resistor or capacitor takes longer to charge, just like it stretched the charge curve in the earlier lessons.
You'll also hear the cutoff called the −3 dB point. A decibel (dB) is a way of describing a ratio, and −3 dB happens to mean the output carries about half the power of the input. When power halves, the voltage amplitude drops to about 70.7% — the same 0.707 number. So "cutoff", "70.7% amplitude", and "−3 dB" all point at the same spot. Don't worry about the decibel maths; just remember the cutoff is where the output swing has fallen to roughly seven-tenths of the input.
Note: The code samples about 50 times a second, so it can't cleanly draw a 160 Hz wave — that's far too fast to trace. What it can do is report how big the output swing is at each drive speed, and you watch that swing shrink as you push the drive faster. The calculated 160 Hz is your theoretical anchor; the measurement confirms the trend and the ~70.7% idea rather than pinpointing 160 Hz exactly.
Run the program, then rerun it a few times with different SAMPLES_PER_HALF_CYCLE values and read the # summary line each time — the one reporting drive_freq and ratio.
SAMPLES_PER_HALF_CYCLE = 25 (about 1 Hz). The output swings nearly the full 3.3 V and the reported ratio sits near 100%. The filter is barely holding it back.SAMPLES_PER_HALF_CYCLE = 1 (about 25 Hz), the quickest this ~50 Hz sampler can drive. The ratio should be its lowest here.You won't reach 160 Hz — the sampler tops out well below it — so you won't catch the exact moment the ratio hits 70.7%. That's expected. What you should see is a clear downward trend: the faster you drive, the smaller the fraction of the input that survives. Sketch ratio against drive_freq from your runs and you'll see it heading down toward that 70.7% mark, right on course for the 160 Hz cutoff the formula predicts.
Change one part and predict where the cutoff moves before you measure. If you double the capacitor to 0.2 µF (or add a second 0.1 µF in parallel), the formula says fc should halve to about 80 Hz. A lower cutoff means the output should start shrinking at slower drive speeds than before.
Work out your new fc with fc = 1 / (2πRC), write it down, then swap the part and rerun the sweep of SAMPLES_PER_HALF_CYCLE values. Does the ratio start falling sooner — at lower drive frequencies — than it did with the original filter? Compare the two trends.
Tip: Right now you rerun the program by hand for each drive speed. As a later project, you could have the code step through several SAMPLES_PER_HALF_CYCLE values on its own and print one ratio per step — an automated frequency sweep. It's not needed here, but it's a natural next build.