This commit is contained in:
david rice
2026-04-09 09:17:42 +01:00
parent 2385fc6878
commit be7658b54d
5 changed files with 51 additions and 27 deletions

View File

@@ -208,7 +208,7 @@ def run_analysis(last: int = 10) -> None:
client = anthropic.Anthropic()
message = client.messages.create(
model = CLAUDE_MODEL,
max_tokens = 1024,
max_tokens = 3072,
system = SYSTEM_PROMPT,
messages = [{"role": "user", "content": prompt}],
)
@@ -282,7 +282,7 @@ def main() -> None:
client = anthropic.Anthropic()
message = client.messages.create(
model = CLAUDE_MODEL,
max_tokens = 1024,
max_tokens = 3072,
system = SYSTEM_PROMPT,
messages = [{"role": "user", "content": prompt}],
)

View File

@@ -127,7 +127,11 @@ def _read_csv(path: Path) -> tuple[np.ndarray, np.ndarray]:
volts.append(float(row[1]))
except ValueError:
pass # skip any header row
return np.array(times, dtype=np.float64), np.array(volts, dtype=np.float64)
t = np.array(times, dtype=np.float64)
v = np.array(volts, dtype=np.float64)
if len(t) < 2:
raise ValueError(f"Insufficient samples in {path.name} ({len(t)} rows parsed)")
return t, v
def _zero_crossings(times: np.ndarray, volts: np.ndarray) -> np.ndarray:

View File

@@ -322,19 +322,18 @@ def dual_capture(iteration):
else:
print(" SKIPPING PASS 3 SAVE.")
# Collect Rigol 1.8 V waveform (Agilent save takes ~5 s, Rigol should be done)
# Collect Rigol 1.8 V waveform.
# The Agilent LP acquire + save takes ~35 s, so the Rigol will have
# long since auto-captured by now. read_waveform_csv() sends :STOP
# before reading to guarantee the acquisition is finalised.
if rigol_scope.is_connected():
print(" PASS 3: WAITING FOR RIGOL 1.8 V CAPTURE...")
if rigol_scope.wait_captured(timeout_s=10.0):
DATA_DIR.mkdir(exist_ok=True)
v18_path = DATA_DIR / f"{ts}_pwr_{iteration:04d}_1v8.csv"
n = rigol_scope.read_waveform_csv(v18_path)
if n:
print(f" SAVED: {v18_path.name} ({n} samples)")
else:
print(" RIGOL: Waveform read returned 0 samples.")
else:
print(" RIGOL: Timed out waiting for capture.")
print(" RIGOL: Waveform read failed — check connection and probe.")
_restore_hs_config()

View File

@@ -72,7 +72,7 @@ def configure():
rigol.write(":CHANnel1:DISPlay 1")
rigol.write(":CHANnel2:DISPlay 0")
rigol.write(":CHANnel1:COUPling DC")
rigol.write(":CHANnel1:PROBe 1")
rigol.write(":CHANnel1:PROBe 10")
rigol.write(f":CHANnel1:SCALe {V18_SCALE:.3f}")
rigol.write(f":CHANnel1:OFFSet {V18_OFFSET:.3f}")
rigol.write(f":TIMebase:MAIN:SCALe {V18_TIMEBASE:.2E}")
@@ -82,9 +82,11 @@ def configure():
rigol.write(f":TRIGger:EDGe:LEVel {V18_TRIG_LEVEL:.3f}")
rigol.write(":TRIGger:SWEep AUTO") # auto: captures even without a droop trigger
time.sleep(0.3)
rigol.write(":RUN") # start acquiring immediately after configure
time.sleep(0.2)
print(f"[RIGOL] Configured: 1.8 V rail, {int(V18_TIMEBASE*1e6)} µs/div, "
f"trigger <{V18_TRIG_LEVEL} V falling (AUTO sweep)")
f"trigger <{V18_TRIG_LEVEL} V falling (AUTO sweep, running)")
# ---------------------------------------------------------------------------
@@ -92,8 +94,9 @@ def configure():
# ---------------------------------------------------------------------------
def arm():
"""Arm for a single acquisition. Non-blocking — returns immediately."""
rigol.write(":SINGle")
"""Ensure scope is running so it is actively acquiring when the LP event occurs.
The waveform is frozen with :STOP inside read_waveform_csv() at collection time."""
rigol.write(":RUN")
def wait_captured(timeout_s: float = TRIG_TIMEOUT_S) -> bool:
@@ -117,32 +120,52 @@ def wait_captured(timeout_s: float = TRIG_TIMEOUT_S) -> bool:
def read_waveform_csv(path: Path) -> int:
"""
Read Ch1 waveform from Rigol over SCPI and write to CSV.
The Rigol returns ASCII voltage values; we reconstruct the time axis
from the waveform preamble.
Sends :STOP first to ensure acquisition is complete before reading —
this is reliable regardless of trigger/status state.
Returns the number of samples written, or 0 on error.
"""
try:
rigol.write(":WAVeform:SOURce CHANnel1")
rigol.write(":WAVeform:FORMat ASCII")
rigol.write(":WAVeform:MODE NORMal")
rigol.write(":STOP")
time.sleep(0.3)
rigol.write(":WAVeform:SOURce CHANnel1")
rigol.write(":WAVeform:FORMat ASC") # Rigol DS1000Z uses ASC not ASCII
time.sleep(0.1)
except Exception as e:
print(f"[RIGOL] Waveform setup error: {e}")
return 0
try:
preamble = rigol.ask(":WAVeform:PREamble?").strip().split(",")
# [0]=fmt [1]=type [2]=points [3]=count [4]=x_incr [5]=x_orig [6]=x_ref
# [7]=y_incr [8]=y_orig [9]=y_ref
x_incr = float(preamble[4])
x_orig = float(preamble[5])
x_ref = float(preamble[6])
except Exception as e:
print(f"[RIGOL] Preamble error: {e}")
return 0
try:
raw = rigol.ask(":WAVeform:DATA?").strip()
# Strip any TMC binary header (#<digit><length>) if present
# Strip TMC binary header (#<n_digits><byte_count>...) if present
if raw.startswith("#"):
n_digits = int(raw[1])
raw = raw[2 + n_digits:]
vals = [float(v) for v in raw.split(",") if v.strip()]
except Exception as e:
print(f"[RIGOL] Data read error: {e}")
return 0
if not vals:
print("[RIGOL] No samples parsed — check scope channel and format settings")
return 0
try:
path.parent.mkdir(exist_ok=True)
with open(path, "w", newline="") as f:
writer = csv.writer(f)
@@ -150,9 +173,7 @@ def read_waveform_csv(path: Path) -> int:
for i, v in enumerate(vals):
t = x_orig + (i - x_ref) * x_incr
writer.writerow([f"{t:.9f}", f"{v:.6f}"])
return len(vals)
except Exception as e:
print(f"[RIGOL] Waveform read error: {e}")
print(f"[RIGOL] CSV write error: {e}")
return 0