Chaya·Edu EDU.CHAYA.DEV
ENGR 255Project 02 · Specification

Project Specification · Fall 2026

Project 02 — Race a Bucket Brigade

Notes 08 said every wire is a bucket. Notes 09 said a long wire is a whole brigade of them — and that fresh pumps make it fast. Today you make the two race, and your chart catches the exact moment the pumps start winning.

Weight25% of course grade
DueMon, Nov 9, 2026 · 11:59 PM
Hand inBrightspace
Budget~30 minutes
Late−10% per day

1The mission

Two wires, every length from 0.5 mm to 5 mm. Lane one: the bare wire — one long bucket brigade, paying the length² law from Notes 09 (80·L² ps with the course numbers). Lane two: the same wire with repeaters — chopped into short brigades with a fresh pump between them, each pump charging its 50 ps toll. The provided script runs the whole race and plots both lanes on one chart.

The fun is the shape. The bare wire's delay is a parabola — it starts flat and then takes off. The pumped wire's delay is nearly a straight line. For short wires the parabola actually wins (no tolls to pay); then somewhere past a millimeter the lines cross, and from there the pumps win forever. The script finds that crossover and marks it on the chart. Then you turn one knob — pricier pumps, or a fatter wire — and watch the crossover slide.

finish LANE 1 · BARE WIRE — ONE LONG BRIGADE still filling, bucket by bucket — and slowing as it goes LANE 2 · SAME WIRE, FRESH PUMPS EVERY SEGMENT relaunched clean at every pump — short brigades are cheap brigades

The race, one instant before the photo. Same metal, same signal, same starting gun. Lane 1 pays the length² law for the whole trip; lane 2 pays small squares plus pump tolls — and pulls ahead.

Why this matters: this exact race, run at every wire on the floor plan, is what decides where every repeater on a real chip goes (Notes 09–10). You are doing, once, what a place-and-route tool does a few million times per design.

Explicitly: no report, no derivations, no written analysis. One script, two charts, one comment line naming your knob.

2The script (provided — copy it)

This is Notes 09's five-line plot from §3, grown up just enough to shop for the best number of segments and to mark the crossover. Same course numbers: 1 kΩ and 200 fF per millimeter, 50 ps per pump. Copy it into a file named race_a_bucket_brigade.py:

"""Project 02 -- Race a Bucket Brigade.

Knob I turned: none yet -- this is the stock race.
(After your knob move, name the knob here or in the Brightspace comment.)
"""
import matplotlib.pyplot as plt

# ---- the course numbers (Notes 08 & 09) -- these are your knobs ----------
R_PER_MM    = 1.0    # kOhm per mm -- the hose, smeared along the wire
C_PER_MM    = 200.0  # fF per mm   -- the buckets, smeared along the wire
REPEATER_PS = 50.0   # ps per fresh pump (Notes 08's bare gate)
# kOhm x fF = ps, so every delay below lands in picoseconds. No unit juggling.

def bare_delay(L):
    """One unbroken brigade: 0.4 * r * c * L^2 (= 80 * L^2 ps with stock knobs).
    The length is squared -- that's the parabola, and the whole problem."""
    return 0.4 * R_PER_MM * C_PER_MM * L * L

def repeatered_delay(L, n):
    """Chop the wire into n short brigades, one fresh pump between each.
    Short brigades are cheap (the squares work FOR you now); pumps charge a toll."""
    return n * bare_delay(L / n) + (n - 1) * REPEATER_PS

def best_delay(L):
    """The script shops around: 1 to 4 segments, keep whichever is fastest."""
    return min(repeatered_delay(L, n) for n in range(1, 5))

# ---- sanity check: the worked 2 mm example from Notes 09 -----------------
print(f"2 mm bare wire:        {bare_delay(2.0):.0f} ps   (Notes 09 says 320)")
print(f"2 mm, 2 segments:      {repeatered_delay(2.0, 2):.0f} ps   (Notes 09 says 210)")

# ---- the race: every length from 0.5 mm to 5 mm --------------------------
lengths = [0.5 + 0.01 * i for i in range(451)]
bare    = [bare_delay(L) for L in lengths]
pumped  = [best_delay(L) for L in lengths]

# the crossover: first length where the pumps genuinely beat the bare wire
crossover = next((L for L, b, p in zip(lengths, bare, pumped) if p < b), None)
print(f"repeaters start winning at about {crossover:.2f} mm")

# ---- the chart (this IS the deliverable) ---------------------------------
plt.figure(figsize=(8, 5))
plt.plot(lengths, bare,   color="#A2542A", lw=2.5, label="bare wire -- one long brigade")
plt.plot(lengths, pumped, color="#0E7C86", lw=2.5, label="with repeaters -- best of 1-4 segments")
plt.axvline(crossover, color="#5A6772", lw=1, ls="--")
plt.annotate(f"repeaters start winning\nat about {crossover:.2f} mm",
             xy=(crossover, bare_delay(crossover)), xytext=(crossover + 0.3, 1400),
             arrowprops=dict(arrowstyle="->", color="#5A6772"))
plt.xlabel("wire length (mm)")
plt.ylabel("delay (ps)")
plt.title("The race: parabola vs. fresh pumps")
plt.legend()
plt.grid(alpha=0.3)
plt.savefig("race.png", dpi=150)
plt.show()

Three functions, one shopping loop, one chart. bare_delay and repeatered_delay are literally the two lines from Notes 09 §3; everything after them is matplotlib.

3Your whole job, in three moves

  1. Run the stock race. python race_a_bucket_brigade.py — it finishes in about a second. Check the sanity lines: 320 ps bare and 210 ps with 2 segments at 2 mm, exactly the worked example from Notes 09. The chart saves itself as race.png with the crossover marked. Keep this chart.
  2. Turn ONE knob. Either make the pumps pricier (REPEATER_PS — try 50 → 150) or make the wire fatter (C_PER_MM — try 200 → 400; bigger buckets every millimeter). Change it enough to matter, run again, keep the second chart, and watch where the crossover went. One of these knobs pushes it out, the other pulls it in — finding out which is the project.
  3. Write nothing. The two charts are the answer. The only typing left is one line in the Brightspace comment naming your knob and its old → new value.

What the stock run looks like

From my machine: 2 mm bare wire: 320 ps, 2 mm, 2 segments: 210 ps, repeaters start winning at about 1.12 mm. These are not random — if your stock run says anything else, something got mistyped. (After your knob move the numbers will differ. That is the point.)

Optional: find the pump's sweet spot (+2 points, capped at 100)

The script only shops 1–4 segments. Let it shop to 8 (range(1, 9)) and look at the long end of the chart: the 5 mm wire gets faster still, because more pumps keep paying off — up to a point. Add one line to your Brightspace comment saying how many segments the 5 mm wire actually wants. That is the entire bonus.

4Hand in

Submit on Brightspace, by Mon, Nov 9, 11:59 PM

  • Your stock chart (the race.png it saves, or a screenshot) — crossover marked.
  • Your knob-turned chart — same race, crossover visibly somewhere else.
  • One comment line on the submission: which knob, old → new value.
  • The .py file only if you changed anything beyond the one knob — otherwise the comment line covers it.

That is the complete submission. No report, no write-up, no repository. Late work loses 10% per calendar day.

5Grading — five checkboxes, 20 points each

CheckWhat I look forPoints
☐The stock chart is in, with both racers drawn and labeled (bare and repeatered)20
☐The crossover length is marked and readable on the chart (the script does this — don't crop it out)20
☐The shapes tell the story: the bare curve visibly bends like a parabola, the pumped one runs visibly straighter, axes labeled in mm and ps20
☐One knob was turned, the second chart is in, and the crossover visibly moved20
☐On Brightspace by the deadline, with the knob named (old → new) in the comment20
Total (bonus sweet-spot hunt: +2, capped at 100)100

6Micro-FAQ

Python says No module named matplotlib.
pip install matplotlib (on some machines: py -m pip install matplotlib or pip3). That is the only thing the script needs.
Can I use Google Colab instead?
Yes. Paste the script into a cell, run it, and screenshot the chart there. Nothing to install, and the chart shows up right under the cell.
What's a repeater again?
A fresh pump mid-wire: a plain buffer that catches the tired signal and relaunches it full-pressure into the next short brigade. Notes 09 §3 is the whole story.
My crossover landed at a weird length.
Good — that's the knob doing its job. As long as the stock run prints 320 and 210, the model is right, and wherever your knob puts the crossover is the correct answer for your knob.
After my knob move the sanity lines don't say 320 and 210 anymore.
Right — you changed the physics, so the worked example changed with it. Only the stock chart has to match Notes 09.
Do I write anything?
No. The charts are the answer. One comment line naming your knob is all the typing in this project.
Can I make it prettier? Race more knobs? Animate the brigade?
Yes. Joy is allowed. Just know that the five checkboxes are what's graded, so get those green first.