Initial commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
"""Fit a temperature to each spectrum in a sequence and plot T versus time.
|
||||
|
||||
For a cooling or heating object: grab a burst of frames, then fit each and watch
|
||||
the temperature track. Reuses the Planck fit from fit_temperature.py.
|
||||
|
||||
Inputs are spectrum CSVs in time order. With --response (and --dark plus
|
||||
--integration) each is response-corrected first, exactly as grab_spectrum.py
|
||||
--response would; otherwise they are assumed already corrected. Time comes from
|
||||
the file modification times (first file = 0), or pass --interval for even spacing.
|
||||
|
||||
Note the printed +/- is the formal fit error and understates the truth; the
|
||||
real scatter is frame-to-frame noise and the gray-body and reference systematics.
|
||||
|
||||
Usage: python fit_sequence.py f1.csv f2.csv ... [--response R.csv --dark D.csv
|
||||
--integration US] [--band LO HI] [--interval S]
|
||||
[--out T.csv] [--png fig.png]
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
|
||||
from response import add_calibration_args, apply_response, dark_at, load_csv
|
||||
from fit_temperature import fit_planck
|
||||
|
||||
p = argparse.ArgumentParser(description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
p.add_argument("spectra", nargs="+", help="spectrum CSVs, in time order")
|
||||
p.add_argument("--integration", type=int, metavar="US",
|
||||
help="integration time (us) the spectra were captured at; required with --dark")
|
||||
p.add_argument("--band", nargs=2, type=float, default=[420.0, 800.0],
|
||||
metavar=("LO", "HI"), help="fit band in nm (default: 420 800)")
|
||||
p.add_argument("--interval", type=float, default=None,
|
||||
help="seconds between frames (default: use file modification times)")
|
||||
p.add_argument("--out", default=None, help="write a time,temperature_K,dT_K CSV")
|
||||
p.add_argument("--png", default="temperature_sequence.png")
|
||||
add_calibration_args(p)
|
||||
args = p.parse_args()
|
||||
|
||||
cal = load_csv(args.response) if args.response else None
|
||||
dark = None
|
||||
if args.dark:
|
||||
if args.integration is None:
|
||||
p.error("--integration US is required with --dark")
|
||||
dark = dark_at(args.dark, args.integration)
|
||||
|
||||
if args.interval is not None:
|
||||
times = np.arange(len(args.spectra)) * args.interval
|
||||
else:
|
||||
t0 = os.path.getmtime(args.spectra[0])
|
||||
times = np.array([os.path.getmtime(f) - t0 for f in args.spectra])
|
||||
|
||||
rows = []
|
||||
for t, f in zip(times, args.spectra):
|
||||
wl, y = load_csv(f)
|
||||
if cal is not None:
|
||||
y = apply_response(wl, y, cal, dark)
|
||||
result = fit_planck(wl, y, tuple(args.band))
|
||||
if result is None:
|
||||
print(f"{f}: no fit (too few usable points in band)")
|
||||
continue
|
||||
temperature, dT, _ = result
|
||||
rows.append((t, temperature, dT))
|
||||
print(f"{f}: t = {t:7.2f} s T = {temperature:.2f} +/- {dT:.2f} K")
|
||||
|
||||
if not rows:
|
||||
p.error("no spectra could be fit; check --band and inputs")
|
||||
rows = np.array(rows)
|
||||
|
||||
if args.out:
|
||||
np.savetxt(args.out, rows, delimiter=",",
|
||||
header="time_s,temperature_K,dT_K", comments="")
|
||||
print(f"wrote {args.out}")
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig, ax = plt.subplots(figsize=(9, 5))
|
||||
ax.errorbar(rows[:, 0], rows[:, 1], yerr=rows[:, 2], fmt="o-", capsize=3)
|
||||
ax.set_xlabel("time (s)")
|
||||
ax.set_ylabel("temperature (K)")
|
||||
ax.set_title(f"Temperature sequence, fit {args.band[0]:.0f}-{args.band[1]:.0f} nm")
|
||||
ax.grid(alpha=0.3)
|
||||
fig.tight_layout()
|
||||
fig.savefig(args.png, dpi=110)
|
||||
print(f"wrote {args.png}")
|
||||
Reference in New Issue
Block a user