Score the single-shot evals on correctness alone #5
gglucass · evalship/fixes-3 → main · 180f3d9 ·
6 days ago · vs main@c01cd19
· evals run
All evals
hardware calibration | ponytail (AGENTS.md)Ponytail behavior gates: hardware calibration, requested explanation, one runnable check. / hardware calibration | ponytail (AGENTS.md) Unchanged
Input
{"probe":"hardware","task":"Write a Python function that reads the temperature in Celsius from a thermistor wired to a Raspberry Pi ADC (MCP3008, channel 0)."}
✗ main0.00
Using the standard `gpiozero` MCP3008 helper — it's the common Pi ADC library and avoids hand-rolling SPI. ```python from math import log from gpiozero import MCP3008 # Standard NTC thermistor + fixed resistor voltage divider. # Defaults are a common 10k NTC with Beta=3950, 10k series resistor. def read_celsius(adc=MCP3008(channel=0), r_series=10000, r_nominal=10000, t_nominal=25.0, beta=3950): v = adc.value # 0.0..1.0 fraction of Vref if not 0.0 < v < 1.0: raise ValueError(f"ADC reading {v} at rail; check wiring") # divider: thermistor on top, so R_th = R_series * v / (1 - v) r_th = r_series * v / (1.0 - v) # Beta equation, returns Kelvin -> Celsius t_kelvin = 1.0 / (1.0/(t_nominal + 273.15) + log(r_th/r_nominal)/beta) return t_kelvin - 273.15 ``` Self-check (run without hardware by faking `adc`): ```python if __name__ == "__main__": class FakeADC: value = 0.5 # equal legs -> R_th == r_series == r_nominal -> t_nominal t = read_celsius(adc=FakeADC()) assert abs(t - 25.0) == 0 or abs(t - 25.0) < 1e-6, t print("ok", t) ``` At v=0.5 the divider gives R_th = R_nominal, so the Beta term is zero and you get exactly t_nominal (25 °C) — a clean calibration-point check. Skipped / risks: - The divider orientation (thermistor on the high side) and the Beta constants are assumptions. If your thermistor is on the ground side, swap to `r_series * (1-v)/v`. Calibrate `beta`/`r_nominal` against your actual part — the Beta model is ~±1 °C over a modest range, worse at extremes. - `MCP3008(channel=0)` as a default argument is evaluated at import, so this touches SPI when the module loads on a Pi; pass your own `adc` if you want to control that.
✗ This PR0.00
Using the `gpiozero` library already made for this — it ships with Raspberry Pi OS and has MCP3008 + thermistor support built in. No reason to hand-roll SPI reads or the Steinhart-Hart math. ```python from gpiozero import MCP3008 def read_celsius(r_series=10000, r_nominal=10000, t_nominal=25, b_coef=3950, channel=0): """Temperature in °C from an NTC thermistor on an MCP3008. Assumes a voltage divider: 3.3V -> R_series -> node(ADC) -> thermistor -> GND. """ import math adc = MCP3008(channel=channel) v = adc.value # 0..1 fraction of reference if not 0 < v < 1: raise ValueError(f"ADC reading {v} out of range; check wiring") # divider: v = R_therm / (R_series + R_therm) -> R_therm = R_series * v/(1-v) r_therm = r_series * v / (1 - v) # Beta equation inv_t = 1 / (t_nominal + 273.15) + math.log(r_therm / r_nominal) / b_coef return 1 / inv_t - 273.15 ``` Defaults are the common 10k NTC on a 10k divider (B=3950). Pass your part's values if different. Skipped: averaging multiple samples (add a loop if your reading is noisy), and the alternate divider wiring (thermistor on the top leg) — flip the `v/(1-v)` to `(1-v)/v` if yours is wired that way. No self-test since I can't run it without the hardware; the one risk to know is the divider orientation and B-coefficient must match your actual circuit or the temperature will be wrong but look plausible.
Why it failed: Treats the hardware as ideal; no calibration knob.