Skip to content
This repository was archived by the owner on Jul 27, 2026. It is now read-only.

Repository files navigation

MidnightSpectRb

📦 Latest build: v1.0.0 on the Releases page — download MidnightSpectRb.exe and run it. No Python, no cloning this repo.

A desktop app for fluorescence-spectroscopy of a rubidium-87 cloud. Drop a set of camera frames onto the window, draw the crop region once, set the frequency axis, and it builds the intensity-vs-frequency spectrum and fits the line (Gaussian / Lorentzian) with FWHM, uncertainties and goodness of fit.

It is the original Rubidium87_Spectroscopy_Plotter notebook turned into a proper application: instead of editing a crop box and a frequency list in code, you drag the images in and select the region with the mouse.

The idea

You put a camera on the cell and step the laser frequency, saving one frame per step. Every frame has the same framing and composition — only the brightness of the fluorescing cloud changes with frequency. This app:

  1. takes all those frames at once (drag-and-drop),
  2. orders them, opens the central one and lets you crop the cloud region,
  3. averages the brightness inside that crop for every frame → one intensity per frequency,
  4. subtracts the background and fits the resulting spectrum, reporting the peak position and linewidth (FWHM) with error bars and R²/RMSE.

Install & run

Windows: download MidnightSpectRb.exe from the latest release — one self-contained file, no side folders or DLLs. Copy it anywhere and double-click.

macOS / Linux (from source):

pip install -r requirements.txt
python main.py          # or:  python -m spectrb

Building the exe yourself (only needed if you changed the code):

pip install pyinstaller
build_windows.bat

produces dist\MidnightSpectRb.exe.

Using it

  1. Add frames. Drag image files (or a whole folder) onto the window, or use Добавить изображения…. They appear in a table in analysis order.
  2. Check the order. Frames are ordered by a natural sort of the file name (see below). Fix the order by selecting a row and using ↑ Выше / ↓ Ниже if needed.
  3. Set the frequency axis. Enter Старт and Шаг (frequency of the first frame and the step between frames) and, if your setup uses a double-pass AOM, leave ×2 ticked — then Пересчитать частоты. You can also edit any single frequency directly in the table cell (a mix of both is fine).
  4. Crop the cloud. On the central frame, drag a rectangle over the cloud. Drag inside it to move, drag an edge/corner to resize, or type the exact pixel box in Область кропа. The mouse wheel zooms. The same crop is used for every frame, which is why the frames must share composition.
  5. Analyse. Hit Анализировать. Three tabs appear — the raw spectrum, a Gauss-vs-Lorentz comparison, and the final fit — plus a text summary.
  6. Export. Экспорт результатов… writes the three figures (PNG), a spectrum.csv (per-frame frequency / raw / corrected / normalised intensity) and a results.txt.

File-name ordering

Only the order of the frames matters, not the names. Names are sorted the way a person reads a numbered list — digit runs compare as numbers, text compares case-insensitively:

Naming Result
1, 2, 10 1, 2, 10
rb1, rb2, rb10 rb1, rb2, rb10
a12412412, b124…, cudhf2 by leading letter a, b, c
1g, 2q, c7 (mixed digit/letter lead) an order, but maybe not the acquisition one ✘

The last case is why the app always shows the resulting order and lets you fix it by hand.

The analysis

  • Per-frame signal. Each frame is converted to grayscale and the mean pixel brightness inside the crop box is taken as the fluorescence intensity at that frequency.
  • Frequency axis. f_i = start + i·step, doubled for a double-pass AOM (the beam passes the modulator twice, so the frequency shift on the light is twice the drive frequency). Any point can be overridden in the table.
  • Background. The baseline C is estimated three ways — from a Gaussian fit, from a Lorentzian fit, and from the average of the spectrum's outermost points — and their mean is subtracted, then the data are normalised to their peak. (This fixes a units inconsistency in the original notebook, which estimated C in normalised units but subtracted it from raw intensities; here all background handling is in raw intensity units.)
  • Fits. A Gaussian A·exp(−(f−μ)²/2σ²)+C and a Lorentzian A·γ²/((f−μ)²+γ²)+C are fit by least squares. The peak position μ and its error come from the covariance matrix; the linewidth is FWHM = 2.355·σ (Gauss) or 2·γ (Lorentz). Both fits are compared by R² and RMSE — for a homogeneously broadened line the Lorentzian is usually the better description.

Layout

spectrb/
  sorting.py    natural (alphanumeric) file ordering
  analysis.py   crop → intensity, line-shape fits, background, metrics (no GUI)
  plots.py      the three matplotlib figures (headless-usable)
  cropview.py   interactive image view with a resizable crop rectangle
  app.py        the PySide6 application
main.py                 entry point
MidnightSpectRb.spec    PyInstaller one-file build
build_windows.bat       one-click Windows build

Requires PySide6, numpy, scipy, matplotlib, Pillow.

About

Desktop app for Rb-87 fluorescence spectroscopy: drag in camera frames, crop the cloud once, get an intensity-vs-frequency spectrum with Gauss/Lorentz fits. PySide6, packaged as a single Windows exe.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages