Repository navigation
Releases: dookaloosy/open-spectrograph
Release list
v0.6.0: Add instrument controller application
[0.6.0] — 2026-07-14
Native instrument control: controller, a standalone client for the
TCD1304 detector (desktop application + CLI), stateless CFL wavelength
calibration, and a new paper section describing the software.
Added
controllerpackage — clean-room client for the TCD1304 detector
(drmcnelson firmware); no upstream host software required. Bare
controllerlaunches the desktop application: live spectrum on the
calibrated wavelength axis, capture with provenance headers
(firmware identity, coefficients, acquisition mode, clearing pulses,
exposure), and a live calibration panel — every frame receives the
full pattern-locate + line fit, with per-line table, old/new
coefficient table, RMS, live 404.7 nm FWHM readout, and a transient
"no lock" state that recovers on the next good frame. Store writes
the latest locked fit to the device and verifies by readback.
Subcommands (capture,calibrate,plot,info,ports,
store,erase) expose the same library for scripting and offline
reprocessing. Captures default intooutput/.- Acquisition policy from bench characterization (2026-07-13/14):
PIT + 20 clearing pulses at ≥ 16 ms exposure (ghost-free
quantitative default; the firmware validates its own 16 ms floor at
the recommended sensor clock), automatic switch to PLM below, with
the PLM interval floored at the ~15 ms pixel readout time. The
recommended sensor clock is set on every connect — it repaired a
runtime-corrupted stepped baseline (8k/15k ADU) and makes the
firmware reject bad timing instead of crashing. PLM photometric
caveats documented: sub-4 kADU signals read low (~30% per ms of
inter-frame idle) and bright lines leave a signal-adjacent
background excess (to ~+2 kADU) — bright-line mode only. - Stateless wavelength calibration:
data/cfl_lines.tomldeclares
reference wavelengths and nominal dispersion only. A pattern
locator finds the six CFL lines from scratch each run (any shift,
±25% dispersion, blend-must-be-bright guard against mirrored false
locks), so calibration survives arbitrary drift and never writes
state back to the repo. - USB drop recovery: automatic reconnect loop; a Reconnect button
appears beside the device indicator on disconnect, and (under WSL
only, on explicit press) re-attaches a device that left WSL via
usbipd. - Paper section 4 "Instrument Control Software" (
docs/04-software.md),
inserted before the v0 design section (nowdocs/05-design-v0.md,
section 5). GUI screenshot as figure 4; previous figures 4–6
renumbered 5–7. Boxed\ui{…}convention for UI control names. - 27 controller tests against a simulated device that replays
bench-verified wire behavior, plus two real CFL capture fixtures in
tests/data/(documented there) anchoring format compatibility and
the known-good calibration constants.
Changed
- PySide6/pyqtgraph are core dependencies; the desktop application is
the primary tool (the[gui]extra is gone,pyserialadded). - Pitch flexure webs 1.60 → 2.40 mm on F1, M1, and the grating (both
BOMs) for stiffer pitch retention; M2 stays at 1.60 mm — 2.40 mm is
too stiff for its pusher setscrew to move. cfl_shadeenlarged for the bulb: inner diameter 65 → 105 mm
(+20 mm radial clearance), height 135 → 155 mm (+20 mm axial);
outer diameter 115 mm, inside the 120 mm print envelope.scripts/cfl_calibrate.pyis a thin wrapper over thecontroller
library; the workbook path derives its dispersion from the sheet's
own line list.
Fixed
- CLI live-calibration exposure ladder steps down only on
clipped/starved fit windows; any other fit failure aborts instead of
walking into the crash-prone short-exposure regime. - Captures written by
controllerare readable by the TCD1304 repo's
DataReader.py: header string values are now quoted Python literals
(the reader exec()s each header line) and a# header endsentinel
is emitted before the frame blocks (the reader needs it to start
frame parsing). Validated by plotting a capture with the upstream
tooling, including its wavelength axis from our coefficients header.
v0.5.1: Make the as-built instrument match the model
[0.5.1] — 2026-07-13
Alignment screen centered on optical axis height; as-built BOM
variant for the author's build; CFL wavelength calibration workflow.
Added
data/czerny_bom_v0_asbuilt.toml— BOM variant matching the
author's build, which uses 25.0/50.0 mm mirror blanks in place of
the 25.4/50.8 mm catalog parts. Foot clearances compensated so the
cavity floor stays 29.5 mm below OCH (M1/F1/grating shared floor,
M2 step at 36.4 mm); channel widths and bore contact spacing scaled
to diameter. Same part keys as the design BOM, so the design
baseline works unchanged via--bom. The default design BOM
retains Thorlabs catalog dimensions for print-and-assemble
reproduction.scripts/cfl_calibrate.py— CFL wavelength calibration from a
capture workbook: Gaussian fits of the six index lines (saturation
masking, joint two-Gaussian fit for the 542.4/546.1 blend,
core-flank fit for 611.6), quadratic dispersion fit, and chart-safe
write-back of constants and centers into the workbook XML.scripts/cfl_figure.py— regenerates the fig 6 CFL spectrum figure
from the workbook: calibrated wavelength axis, labeled index lines,
Hg 404.7 nm Gaussian-fit FWHM inset. Axes geometry pinned to match
the original figure layout.
Changed
- Fig 6 regenerated from a 25 ms CFL capture (previously 50 ms) with
recalibrated wavelength axis; measured FWHM 0.50 nm at 404.7 nm.
Fixed
- Author-build mirror mounts were loose: bores were sized for the
25.4/50.8 mm catalog diameters while the build's mirrors are
25.0/50.0 mm. Fixed via the as-built BOM variant; the design BOM
is unchanged. - Top-cover version emboss read the installed package metadata, which
an editable install freezes at install time — version bumps
silently carved the previous version into the lid. The emboss now
cross-checkspyproject.tomland raises on mismatch, with a
reinstall hint (the silent0.1.0fallback is removed). - Laser alignment screen centerline was a stale hardcoded 22.5 mm; the
optical axis sits 29.5 mm above the common cavity floor in v0. The
centerline is now derived from the housing spec
(-shallowest_floor_z), andcenterline_height_mmis a required
argument ofbuild_laser_alignment_screen(no silent default). - Screen tongue notch sized from the selected M1 part's mount instead
of the firstm1_optionsentry.
v0.5.0: Roll flexure for cylindrical mirror axis alignment
[0.5.0] — 2026-06-23
Roll flexure for cylindrical axis alignment, foot bolt layout rework.
Added
- 2-bladed leaf-spring roll flexure section on cylindrical mirror mounts
(F1, M1), grating mount, and OAP mount. Virtual pivot at optic
centre; trapezoidal pedestals with heat-set insert bores; centre
stiffening block between blades. - Roll setscrew actuation: pair of M2×8 setscrews through heat-set
inserts in the foot, pushing against pedestal lower surface. - Hardware in grating flexure assembly (retention setscrew, pitch and
roll pusher setscrews, heat-set inserts — matching mirror assemblies). - Roll flexure clearance holes in housing floor for roll setscrew access.
tongue_half_mmandu_front_mmfields onMountdataclass;
housing reads these instead of re-deriving tongue dimensions.- Roll flexure BOM parameters:
roll_flexure_height_mm,
roll_blade_thickness_mm,roll_insert_spacing_mm,
roll_blade_spacing_mm,roll_pedestal_gap_mm.
Changed
- Foot bolt layout flipped: 2 forward bolts at
±foot_bolt_spacing_mm,
1 aft bolt atu_wall_rear + 0.5 * boss_width. Wide tongue spans
both forward bolts with radiused front corners. foot_length_mmsimplified:front_bolt_offset + 0.5 * boss_width
(removedmax()guard that was pushing the tongue 3 mm past needed).bolt_safety_mmreduced from 6.0 to 2.0 (wide tongue provides
adequate material around bolt heads).front_bolt_offset_mmreduced from 8.0 to 5.0 for all mounts.- Aft foot bolt position changed from slab midpoint to
u_wall_rear + 0.5 * boss_width(closer to rear wall). - Pitch flexure parameters renamed:
flexure_thickness_mm→
pitch_flexure_thickness_mm,flexure_gap_mm→
pitch_flexure_gap_mm. - Face mill split into two bands when roll flexure is active (optic
pocket + pitch shelf region), preserving the roll band at slab depth. - Housing
_WALL_THICKNESS_MMkept at 10.0 (lateral walls only). - New
_LID_CLEARANCE_MM = 2.0decouples lid gap from lateral wall
thickness; z_top = tallest mount + lid clearance + cover depth. - Housing
controller_cavity_wall_mmreduced from 5.0 to 3.0. _BOTTOM_COVER_MIN_WALL_MMsplit: new_FLARE_CEILING_WALL_MM = 3.0
for HASMA flare ceiling (was sharing_BOTTOM_COVER_MIN_WALL_MM = 5.0).- HASMA tap fixture cone length reduced from 25.4 to 20.0 mm.
tongue_half_mmandu_front_mmonMountdefault toNone
(was0.0), consistent with other optional fields.- Setscrew BOM: retention M2×4 (92605A043), pitch pushers M2×5
(92605A044), roll pushers M2×8 (92605A912); removed M2×6
(92605A047). - Paper: added assembly procedure section (4.5), print settings in
4.4, updated BOM cost table, ILF EE76 column headers, assembly
dimensions, version references to v0.5.0. - Mount body color (
_MOUNT_COLOR) now set on all three mount types
viaPart(result.wrapped)cast. - Assembly fixtures updated for wide tongue foot shape, roll flexure
band hull, and corrected w-stacking. - Housing locating ridges read
tongue_half_mmfromMountobject. - Alignment screen tongue notch width updated for wide tongue.
- Raysect CSG mount builders synced with CAD: wide tongue foot,
roll flexure band solid block (whenroll_flexure_height_mm > 0). - OAP BOM (
czerny_bom_tl_oap.toml): switched foot bolts to M2,
addedpusher_shelf_mm, standardised bolt spacing to match
regular mirror pattern (5/10 mm for 25/50 mm class).
v0.4.0: Flexure stiffening, locating ridges, laser alignment screen
[0.4.0] — 2026-06-20
Flexure stiffening, mount foot locating ridges, laser alignment screen.
Changed
flexure_thickness_mmincreased from 0.80 mm to 1.60 mm across all
mounts (8× stiffer). Back-of-envelope cantilever analysis predicts
< 0.11 nm spectral shift at 45° box tilt, down from ~1 nm.head_clearance_mmincreased from 5.0 mm to 6.0 mm. Heat-set
insert bottom now clears the top TPU contact bump by 0.4 mm (was
overlapping by 0.6 mm).bolt_safety_mmincreased from 2.0 mm to 6.0 mm, widening the
foot tongue from 6 mm to 10 mm (3.3 mm wall per side of the 2.4 mm
clearance hole). Prevents tongue splitting under bolt clamping load
due to weak interlayer adhesion.insert_bore_dia_mmreduced from 3.0 mm to 2.8 mm for tighter
heat-set insert retention.
Added
- Mount foot locating ridges on the housing cavity floor: L-shaped
raised tabs (0.8 mm tall, 1.0 mm wide) at each mount foot position.
Two L-ridges per mount follow the corner fillet through a continuous
8-point arc (slicer-friendly toolpath), plus one back ridge spanning
the crossbar width. 0.15 mm clearance constrains foot position to
±0.15 mm during screw tightening. foot_outline_xyfield onMountdataclass: actual T-shaped foot
outline (not convex hull) for housing ridge placement.mount_locating_ridgesfield onSolidHousingSpec: pre-computed
ridge rectangles from mount parameters.- Laser alignment screen (
build_laser_alignment_screenin
mounts_cad.py): three-body multi-color print (frame, white disk,
black reticle) with crosshair marks. Base has tongue notch with
corner-filleted corners, shallow ridge avoidance cuts (ridge height- clearance), and corner fillets matching both the foot fillet and
L-ridge inner arc.
- clearance), and corner fillets matching both the foot fillet and
- Alignment screen exported as
alignment_screen.stepby--cad
(standalone three-body STEP with tongue notch and ridge avoidance). build_laser_alignment_holderinmounts_cad.py: cuboid holder
with coaxial bores for laser pointer and HASMA adapter alignment.
v0.3.0: Assembly fixtures, OAT tolerance overhaul, 0.86 nm first light
[0.3.0] — 2026-06-12
Assembly fixtures, OAT tolerance overhaul, 0.86 nm first light.
Changed
- ILF metric switched from FWHM to EE76 (encircled-energy width
containing 76% of hits) inoptics/forward_trace.py. Robust
against split spots and skew tails. - Tolerance analysis now uses true OAT perturbation for all axes:
each element is perturbed independently without recomputing
downstream positions. Layout distances shift only the target
element; angular tilts rotate only the target element's axis. - Rotation axes converted from one-sided perturbation to full ±
sweep with plots. - Dropped redundant θ_F1 layout axis (identical to F1 normal tilt
under OAT). - Table 5 (v0 performance) and Table 6 (tolerance budget)
recalculated. Table 6 uses paper variable names (θ, φ, α) with
descriptions matching Table 4. - Default
--max_rotationchanged from 5° to 2°. - Mount construction steps reordered: outer contour (tombstone, side
cuts, face mill, foot shape, pusher shelf) before internal features
(bore, setscrew bore, bolt holes, chamfers). Enables extracting the
outer hull for fixture generation. - Contact bumps separated from mount body as captive TPU inserts
(3 mm dia cylinders in bore pockets). Three-point retention: two
bottom bumps + one top bump, setscrew preloads optic against bottom
pair. - Contact bump parameters moved to BOM:
contact_radius_mm,
contact_offset_mm,contact_separation_mmper mount. optic_clearance_mmadded to mount params (diametral bore/pocket
clearance beyond assembly + print tolerance). Default 2.0 mm.- Bore sketch simplified:
upper_r/lower_runified tobore_r. - Heat-set insert bore tightened from 3.1 mm to 3.0 mm.
- Mount STEP exports now include captive TPU contact bumps.
- Mirror builders (
_build_generic_spherical_mirror,
_build_generic_cylindrical_mirror) now returnPart(via
Part.cast) instead ofCompound, fixing color export in
assemblies. _lookup_mirror_in_bomunified: searches all four mirror groups
(m1/m2/f1/f2), returnsfocal_length_mm = inffor flat mirrors.
_lookup_f_mirror_in_bomremoved.- HASMA printed thread removed; replaced with tap drill bore
(tap_drill_dia_mm = 5.5, formerlypilot_bore_dia_mm). Thread
cut post-print with tap guide fixture. - Thread construction code,
Helix/sweepimports, and
hasma_thread_tpi/hasma_thread_major_dia_mmspec fields deleted. - Setscrew and foot bolt holes use fixed-plane sketches with absolute
coordinates instead of face-relative offsets (robust after mount
step reordering).
Added
- CFL spectrum figure (
fig_6_cfl_spectrum.png) and §4.5 Results in
paper. Measured 0.86 nm FWHM on isolated 405 nm Hg line. - Normal tilt axes (θ_M1, θ_M2, θ_F1, α) and cylinder axis
rotation axes (φ_M1, φ_F1) inscripts/tolerance.py. - Per-wavelength ILF histogram debug panels for all tolerance axes.
- Threshold-based tolerance budget: reports max deviation keeping
ILF below a configurable target (default 1 nm), replacing the
previous linear slope metric. --ilf_target,--max_tiltCLI flags for tolerance script.build_mirror_assembly_fixture(): envelope − mount hull (steps
1–5) − mirror, with lip pocket (through-hole, 1 mm rim contact),
foot/shelf relief through-cuts, and setscrew access hole. Works
for M1, M2, and F1.build_grating_assembly_fixture(): same pattern for grating mounts,
rectangular lip pocket (full v-width, 1 mm w-lip), foot/shelf
relief through-cuts.build_hasma_tap_fixture(): conical plug matching housing flare
(45° half-angle) with 1/4" through bore to guide a 1/4"-36 tap.- Fixture export integrated into
export.py --cad: m1/m2/f1/grating
fixtures + HASMA tap fixture alongside housing and mounts. _FIXTURE_COLOR(red) for fixture STEP exports.- Paper section 4.4 "Printable parts": subsection 4.4.1 lists housing,
covers, mounts, and TPU bumps; subsection 4.4.2 lists assembly
fixtures. All table captions moved above tables for consistency. - Section 4.3 now shows
tolerance.pycommand and references
assembly fixtures for axis-rotation alignment. - Section 4.2 performance table promoted to proper
tableenvironment
with caption. - F1 described as "sagittal cylindrical collimator" (not merely fold).
--flags in\texttt{}escaped as{-}{-}for correct rendering.\texttt{--}dash fix applied to--bomreference in section 3.
Fixed
- FWHM interpolation: added linear interpolation between bins for
sub-pixel half-max crossings (before switching to EE76).
v0.2.0: Fit housing to first print, eliminate nylon-tip setscrews
[0.2.0] — 2026-05-24
Housing dimensional corrections for print fit.
Changed
- Bottom cover plate thickness reduced from 5 mm to 3 mm; counterbore
depth reduced from 4 mm to 2 mm to match. - Bottom cover ledge constant split into
_BOTTOM_COVER_LEDGE_WIDTH_MM
(6 mm, horizontal shelf) and_BOTTOM_COVER_EXTENSION_MM(13 mm,
vertical depth below z_bottom). - Controller board placement shifted −3 mm toward z_bottom_ext
(_CONTROLLER_Z_INSET_MM); pocket/solder/insert geometry unchanged. - HASMA conical flare half-angle increased from 30° to 45°; cone now
clipped to z-bounds (deepest cavity floor / top ledge − 5 mm wall). - HASMA thread
_pitch_rcomputed from pitch diameter (D − 0.6495P)
instead of major diameter; internal minor now matches UNS-2B spec. - HASMA pilot bore diameter moved from hardcoded 5.5 mm to BOM field
pilot_bore_dia_mm. - All fasteners switched from M2.5 to M2 self-tapping screws
(99461A929 → 99461A915); cover screw, mount bolt, and insert pilot
dimensions updated accordingly. - Removed
print_tolerance_mmadjustments from HASMA thread and
detector package depth (covers still use print_tol for clearance fit). - Assembly size updated from 157×172×85 mm to 157×172×99 mm in paper.
- Paper figure 4 updated to v0.2.0 CAD model screenshot.
- BOM cost language corrected: $500 is a target, not achieved ($912).
- Raysect reference corrected to Meakins and Carr (2014).
- Setscrew bores made blind (0.5 mm floor) so flat-tip setscrews can
replace expensive nylon-tipped ones. - Nylon-tip setscrew (93285A009, M2×3.8, $3.08) replaced with flat-tip
(92605A044, M2×5, $0.41) for optic retention in all mounts. - Pusher shelf added to all flexure mounts: semicircular lip above
flexure gap prevents setscrew slipping past the flexure lip.
Height configurable per mount viapusher_shelf_mmin BOM. - Heat-set insert bore tightened from 3.3 mm to 3.1 mm.
Added
- Bottom-side cavity glossary in housing_cad.py constants section.
- UNS-2B thread spec comments in BOM (
[slits.mount]).
v0.1.0
Open Spectrograph v0.1.0
Downloads
open-spectrograph.pdf— full paper (no LaTeX toolchain needed)full_assembly.step— complete assembly (open in any STEP viewer)housing.step,top_cover.step,detector_cover.step,bottom_cover.step— housing partsscene.step— optics + mounts only (no housing)f1_mount.step,m1_mount.step,grating_mount.step,m2_mount.step— flexure mountsbom.csv— bill of materials with costs
What is this?
An aberration-corrected fiber-coupled Czerny-Turner spectrograph achieving sub-1 nm spectral resolution over 400-700
nm. Off-the-shelf optics, 3D-printed housing with flexure mounts, open-source TCD1304 detector.