Blackchirp 2.0.0
Blackchirp 2.0.0 is a major release that replaces the qmake build with CMake and ships official binary packages, replaces compile-time hardware selection with a runtime configuration model, introduces Python hardware drivers as a first-class implementation type, rebuilds the acquisition pipeline around a lock-free ring buffer, and overhauls logging, configuration, and the on-disk hardware identifier scheme. A v1.x user upgrading to 2.0 should also read the migration guide, which walks through the upgrade actions for each user-visible change below.
Highlights
Replaced the qmake build with CMake and added official binary packages for Linux, Windows, and macOS, so most users no longer need to build from source. See Installation.
Replaced compile-time hardware selection with a runtime configuration model: a single binary supports any combination of compatible hardware, organized into profiles, loadouts, and FTMW presets selectable from the Hardware menu. See Hardware and Library Configuration.
Added Python hardware drivers as a first-class implementation type alongside the C++ drivers, with hot reload, custom protocol support, and per-type capability declarations. See Python Hardware.
Rebuilt the FTMW acquisition pipeline around a single-producer single-consumer ring buffer with parallel batched parse and accumulate, raising sustained shot rates and reducing dropped frames under load. See Viewing FTMW Data.
Consolidated logging through a thread-safe
LogHandlerand replacedqDebug()everywhere with thebcLog/bcWarn/bcError/bcDebugandhwLog/hwWarn/hwError/hwDebugfree-function families; a runtime debug-logging toggle in the new Application Configuration dialog writes adebug_YYYYMM.csvfile when enabled. See Application Log and Application Configuration.Added an in-process crash handler that captures POSIX signals (Linux, macOS) and Windows unhandled exceptions to a diagnostic report under
<savePath>/log/crashes/, with a startup notification when an earlier run crashed. Release builds keep debug info so the captured frames resolve to source lines viaaddr2line/atos/ WinDbg. See Crash Reports.Overhauled the documentation: refreshed the User Guide end to end against the 2.0 feature set, added the new Developer Guide for contributors, and substantially expanded the C++ API reference to cover the hardware, experiment, persistence, and orchestration classes.
Refreshed the companion
blackchirpPython package against the v2 on-disk schema, added LIF read and processing support (BCLIF,BCLifTrace), extendedBCFTMWwith a differential-FID API and configurable axis units, hardened the reader against schema drift across v1 and v2 fixtures, and restructured the Sphinx pages into a per-class layout. Tagged on PyPI as0.1.0rc1. See Python Module.
Build and distribution
Replaced the qmake build with CMake.
config.priis no longer used; build options are configured through CMake cache variables. See Installation.Added official binary packages for Linux, Windows, and macOS, with bundled Qt redistributables on Windows and macOS. See Installation.
Added cross-platform CPack packaging assets and a GitHub Actions release workflow that produces release artifacts for every supported platform.
Added a user-configurable hardware-selection system at configure time (
BC_ALLHARDWAREand per-driver toggles) so packagers can produce restricted builds when needed. See Installation.Declared Eigen3 as an explicit CMake dependency.
Added a CMake documentation build (Sphinx + Doxygen) with dual-Doxyfile support for ReadTheDocs.
Replaced the static
virtualdata.qrcresource with a dynamic FID simulation generator, so the Virtual digitizer produces synthetic data without bundling sample CSVs. See First Run.
Hardware configuration
Added the runtime hardware configuration model with profiles, loadouts, and FTMW presets. Hardware is enabled and configured from the Runtime Hardware Configuration dialog without recompilation. See Hardware Profiles, Loadouts, and FTMW Presets.
Added a first-run hardware onboarding flow that walks a new user through profile creation. See First Run.
Added the Hardware Loadouts submenu and a loadout selector in the runtime hardware configuration dialog. See Hardware Menu.
Added the FTMW preset bar with full create, copy, save-as, and delete operations. See FTMW Presets.
Added a stable per-profile identity so a profile deleted and recreated under the same
Type.labelis recognized as a different device: loadouts record each member’s identity on save, and hardware drift is detected on identity, not just on the profile key. See Loadouts.Added a deletion-consequence preview: removing a profile shows how each affected loadout and its FTMW and LIF presets are updated. Members of a required hardware type are substituted with the system fallback and their referencing presets are re-pointed to it; members with no fallback are dropped, along with any preset whose topology depends on them. The dialog spells out the destructive changes and summarizes the rebinds before you confirm. See Hardware Profiles.
Added the consolidated FTMW Configuration menu entry and
FtmwConfigDialog, replacing the v1.x scattered FTMW pages. See FTMW Configuration.Added the unified Application Configuration dialog (font, save path, runtime LIF toggle, debug-logging toggle), replacing the per-setting menu entries from v1.x. See Application Configuration.
Added a
VendorLibrarystaging system and a Library Configuration interface for managing externally-supplied drivers, with platform-specific installation guidance. See Library Status and Installation.Added the hardware settings registry: per-device settings are declared once and rendered into the per-device dialog by the
HwSettingsWidgetwith priority-grouped layout. All hardware classes (flow controllers, pressure controllers, temperature controllers, IO boards, GPIB controllers, LIF lasers and digitizers, FTMW digitizers, clocks, chirp sources, and pulse generators) were migrated onto the registry. See Hardware Dialog.Added value-gated visibility to the hardware settings dialog: a setting can be shown only when a sibling enumerated setting holds a given value, and an array-valued setting can be populated from a semicolon-delimited file through a new Import CSV… action in the array editor. See Hardware Dialog.
Added per-object hardware threading configuration to the hardware profile. See Hardware Profiles.
Added a “Direct Control” hardware concept for hardware operated outside an experiment. See Hardware and Library Configuration.
Hardware drivers
Added Python hardware drivers backed by a
QProcess/ JSON-IPC bridge, with hot reload from the per-device dialog and per-type trampolines for AWGs, flow controllers, IO boards, clocks, pressure controllers, temperature controllers, FTMW digitizers, LIF digitizers, pulse generators, GPIB controllers, and LIF lasers. See Python Hardware.Python drivers expose RS232, TCP, GPIB, and Custom protocols. See Per-Type Capabilities.
The Python hardware combo box prepopulates from class names scanned out of available scripts. See Selecting a Python Driver.
Added runtime communication-protocol selection per hardware object via the per-device dialog, with protocol-specific widgets backed by group-based settings storage. See Hardware Dialog.
Communication read settings — timeout and termination character — are now per-protocol. v1.x stored
timeoutandtermCharat the top of each hardware group; 2.0 stores them under a per-protocol sub-group (rs232,tcp,gpib,custom,virtual) so a single device can carry different communication parameters for each protocol it supports. Drivers register known-good per-protocol defaults, seeded when a device is first configured and overridable in the Communication Settings dialog; anything unregistered falls back to 200 ms timeout and\ntermination character. See Communication; users migrating from v1.x can recover their previous values from the v1.x settings file.Modernized the GPIB controller architecture so multiple GPIB controllers (mixed LAN and RS232) cohabitate in one installation. See Hardware Details.
Added Test Connection and Communication Settings shortcuts to the per-device dialog. See Hardware Dialog.
Replaced the four fixed AWG protection/gate spinboxes with a generalized marker system: arbitrary
MarkerChannel/MarkerRoledefinitions are entered through a marker table on the chirp configuration tab. See Markers Tab on the chirp setup page.Added the LabJack vendor-library wrapper with platform- specific backends (Linux/macOS exodriver, Windows UD), so LabJack support no longer requires the exodriver at compile time. See Library Status and Installation.
Added the Spectrum vendor-library wrapper with dynamic loading for both Spectrum digitizer families. See Library Status.
Acquisition and data flow
Replaced the per-shot Qt signal waveform path with a single-producer single-consumer ring buffer (
WaveformBuffer) and a worker-thread parse/accumulate stage. See Viewing FTMW Data.Added backpressure-triggered pre-accumulation in
FtmwDigitizerso the worker thread keeps up under bursty load. See Viewing FTMW Data.Added parallel batched parse and accumulate in
AcquisitionManager. See Viewing FTMW Data.Consolidated the FTMW experiment-setup pages into
FtmwConfigWidget. See Experiment Setup.Extracted the LO scan and DR scan controls into reusable widgets and incorporated them into the experiment-wizard Type page. See FTMW Experiment Setup.
The number-of-chirps spinbox is now enabled unconditionally; a warning is emitted when the active digitizer does not support multi-record acquisition. See Digitizer Setup.
User interface
Added a Help menu with About dialog, library information, and links to online resources. See User Interface Overview.
Added the FTMW preset submenu under the Hardware menu. See Hardware Menu.
Reworked the experiment-info panel and wired
HwStatusBoxconfigure actions so each status box opens the device dialog directly. See User Interface Overview.Polished the left-side status panel layout and shortened hardware status box titles. See User Interface Overview.
Added a Fixed step mode and full-precision handling to the
ScientificSpinBox. See User Interface Overview.Added a Save-As workflow on the FTMW preset bar that copies the current configuration into a new preset, with drift-detection on Save. See Hardware Menu.
Updated the Peak Find Widget icon. See Viewing FTMW Data.
Added an Appearance button to the Peak Find toolbar that opens the FT peak-marker styling editor directly, without hunting for the curve in the main-plot right-click menu. See Viewing FTMW Data.
Added a Peak Find display filter: a toggleable 2x2 grid filters the peak table by frequency and intensity range, plus a separate “In view” toggle that limits the table to peaks within the main FT plot’s visible range. These filters affect only the displayed table, not the search bounds or the peaks drawn on the plot. See Viewing FTMW Data.
Added peak navigation to the Peak Find panel: double-click a row to center the main FT plot on that peak, or use the row’s “Center on” context menu to frame any FT plot. With the table focused, Enter re-centers the current peak, Up/Down step through the visible rows, and Left/Right step to the next lower/higher frequency peak across the full peak list (regardless of filtering or sort order), centering the main plot on each. The frequency window half-width is configurable in the Peak Finding Options dialog. See Viewing FTMW Data.
The Peak Find search parameters (frequency range, SNR, window size, polynomial order, and navigation half-width) are now remembered per experiment, stored in a
peakfind.csvfile and falling back to the application-wide defaults when none has been saved, mirroring the FID processing-settings behavior. See Viewing FTMW Data.Added a selectable column delimiter for curve XY exports: a drop-down beside the right-click
Export XYaction chooses semicolon, comma, tab, or aligned whitespace. The choice is persisted application-wide and shared between Blackchirp and the viewer. See Plot Controls.Relaxed the experiment-setup dialog minimum size. See Experiment Setup.
Streamlined the overlay creation and configuration dialog: flattened the nested group boxes into aligned settings tables and moved the validity and progress indicators into the dialog button bar. See Overlays.
LIF
Added the LIF Conversion Stage hardware type, representing one physical stage — a doubling crystal, a sum-frequency mixing crystal, a difference-frequency mixing crystal — in a LIF setup’s frequency-conversion chain, plus the Sirah FCU driver for Sirah’s doubling-stage hardware. The Sirah Cobra driver no longer handles frequency conversion itself; that responsibility moved to the new hardware type. See LIF Conversion Stage.
Added LIF presets: a named, saved wiring of the frequency-conversion chain, scoped to the active hardware loadout and managed from an Apply / Save / Save As… / Rename… bar mirroring the FTMW preset bar. See LIF Presets.
Added a Conversion tab to the LIF experiment-setup page for building and previewing a LIF setup’s frequency-conversion chain: a table of conversion stages and how they are wired together, a live preview of the assembled chain and the resulting excitation-beam range, and inline validation of the wiring. See LIF Frequency Conversion.
Added
liftopology.csv, a file written at the root of each experiment recording the frequency-conversion chain used for the acquisition (omitted when no conversion chain is configured), read automatically byblackchirp-viewerand by theblackchirpPython module. See LIF Data Storage.Added selectable calibration schemes for the Sirah FCU doubling-crystal tuning: a best-effort BBO/KDP second-harmonic phase-matching model, or an imported polynomial or spline curve fit offline, replacing the placeholder grating math. Fitting is done outside Blackchirp with the
python/tools/scripts in the source repository. See LIF Conversion Stage.Added a standalone LIF Configuration dialog carrying both the acquisition and frequency-conversion editors, with a prompt to save conversion changes as a preset, and a LIF Preset menu that switches the active conversion preset from the menu bar — mirroring the FTMW configuration dialog and preset menu. See LIF Frequency Conversion.
Logging and diagnostics
Redesigned
LogHandleras a thread-safe global singleton with aQAnyStringViewAPI. See Application Log.Added
bcLog/bcWarn/bcError/bcDebugandhwLog/hwWarn/hwError/hwDebugfree functions and migrated every call site in the source tree offlogMessagesignals andqDebug(). See Application Log.Added a runtime debug-logging toggle in the Application Configuration dialog; when enabled, debug-level output is written to a
debug_YYYYMM.csvfile alongside the standard log. See Application Configuration.Successful connection-test events are highlighted in the Log tab so they stand out from informational chatter. See Application Log.
Added an in-process crash handler. POSIX installs
sigactionhandlers (SIGSEGV/SIGABRT/SIGFPE/SIGILL/SIGBUS) on asigaltstackand writes a text crash log via rawwrite(2)with frames resolved throughdladdrtomodule(+0xoffset) [0xpc]lines. Windows installsSetUnhandledExceptionFilterplus the C-runtime auxiliaries and emits a minidump (MiniDumpWriteDump) alongside a matching text sidecar so triage tooling sees the same header on both platforms. Crash artifacts land under<savePath>/log/crashes/and carry the build identity (git SHA) so they can be resolved against an unstripped binary. See Crash Reports and Crash Handling and Triage (68449b0b).Added a startup notification dialog when prior crash reports are present. The most recent acknowledged timestamp is persisted under the dialog’s settings group, so a dismissed report does not re-prompt unless a still-newer crash arrives. See Crash Reports (68449b0b).
Release builds now keep debug info (
-g//Zi) so the crash-handler stacktraces resolve against the unstripped binary. Stripping continues to happen at install time incmake/Packaging.cmake(68449b0b).
File formats and data storage
Introduced QSettings versioning: each major version stores its configuration under its own QSettings namespace (
Blackchirp2,Blackchirp3, …), so v1.x and v2.x do not share state. See Application Configuration.Migrated to label-based hardware identification across configurations and on-disk storage. Implementation key strings became labels keyed off the runtime hardware configuration. See Data Storage.
Added a
markers.csvfile written under each experiment directory recording the active marker channel definitions for the run. See Data Storage.Added the
RfConfigSnapshothelper for serializing the full RF configuration with each experiment. See RF Configuration.
Python companion module
Hardened
BCFTMWandBCFidagainst schema drift across the v1 and v2 on-disk formats: window-function dispatch is driven by an explicit name →scipy.signalmap, sideband selection accepts both numeric and string forms,FtUnitsaccepts both numeric andFtV/FtmV/FtuV/FtnVforms, and a single helper centralizes the dual-form parse used by every enum-bearing field. Unknown enum values raiseValueErrorrather than falling through to a silent default. See BCFid and BCFTMW (10bd9d08).BCExperimentreadsmarkers.csvwhen present and exposes the active marker channel definitions as amarkersDataFrame attribute. Thehardware.csvreader accepts both the legacysubKeyand the currentdriversecond-column headers, and tolerates the historicalhardwareTypecolumn being numeric, string, or absent — so v1 fixtures continue to load alongside v2 captures. See BCExperiment (10bd9d08).Added a differential-FID API on
BCFTMW:is_multi_segment,num_backups, andget_differential_fid(start, end)produce aBCFidwhose data and shot count reflect the cumulative FID between two backup points infidparams.csv, withvmultscaling recomputed from the bounding entries. See BCFTMW (10bd9d08).Added optional axis-unit selection on
BCFid.x,BCFid.xy,BCFid.ft, andBCFTMW.process_sideband. Time axes accepts/ms/us/μs/nsand frequency axes acceptHz/kHz/MHz/GHz/THz; intensities and the user-facing μs/MHz gate keyword arguments are unchanged. See BCFid (9285f0f8).Added
BCLIFandBCLifTracefor LIF read and processing, mirroring the C++LifTracesemantics.BCLifTraceexposes per-tracesmooth(IIR low-pass plus Savitzky–Golay) andintegrate(sample-space trapezoidal sum, with reference-channel ratio when a reference is present);BCLIFprovidesdelay_axis/laser_axis,delay_slice/laser_slice, andimageaggregating helpers with configurablefill=np.nan|0.0for missing scan points. See BCLIF and BCLifTrace (dc7e7640).Added frequency-conversion topology support to
BCLIF: ahas_topologyflag plusstages,final_stage, andlaser_keyattributes describing a LIF setup’s recorded conversion chain, andfundamental/at_stage/stage_frequenciesmethods that translate between the laser’s tuning value and any beam in the chain, incm-1/nm/GHz/eV.BCExperimentreads the newliftopology.csvfile into aliftopologyDataFrame attribute and hands it toBCLIFautomatically. See BCLIF and BCExperiment.Restructured the Sphinx documentation into per-class pages matching the C++ API reference layout, refreshed
single-fid.ipynbagainst the v2 schema, and added a fully executedsingle-lif.ipynbcovering trace loading, smoothing, integration, slice extraction, and 2-D image rendering. See Python Module (7cb8ab84).Added multi-experiment FID coaveraging via the new
coaverage_fidsandcoaverage_spectramodule-level functions.coaverage_fidsproduces aBCFidwhose raw integer data is the sample-by-sample sum of the inputs and whose shot count is the sum of input shot counts, with optional cross-correlation phase correction against a chosen reference window.coaverage_spectrareturns a shot-weighted magnitude-spectrum coaverage. Both refuse on any mismatch inspacing,size,sideband,probefreq,vmult, or frame count. See BCFid.Tagged the package as
0.1.0rc1on PyPI.pip install blackchirpcontinues to resolve to the prior stable release; testers opt in withpip install --pre blackchirporpip install blackchirp==0.1.0rc1(4a9b69d0).
Bug fixes
Hardware.
Fixed inverted marker bit-packing on the AWG70002A and AWG7122B (ba07d008).
Fixed common-LO clock persistence and clock-frequency signal chaining (836b7750).
Fixed the Apply Clock Settings button so clock changes can be pushed without closing the dialog (cd07dd5f).
Fixed aux-data registration key mismatches in the flow controller and temperature controller paths and corrected the resulting plot labels (79dfe7e8, 8e67bebb, 8458aad9).
Fixed flow-controller channel display and the underlying destructor; refined the gas-flow display layout (e53d7f90, eb8d7fbc, 6783af97).
Fixed the flow-controller poll loop and the Python template- copy workflow (63fee23d).
Fixed Python hardware experiment aux-data emission and host- script deployment (dfb57021).
Fixed threaded hardware destructors not running on shutdown:
~HardwareManagerjoined each worker thread but never deleted the moved-to-thread object, so settings persisted by~SettingsStorage::save()(such as flow-controller channel names onPythonFlowController) were silently dropped on exit (e0acf07d).Fixed a destruction race during application close when a Python hardware driver was actively polling:
PythonProcess::sendRequestran a nestedQEventLoopon the hardware thread to service relay requests, and shutdown could destroy the driver while that loop was in flight, so the post-loopisRunning()check dereferenced a dangling pointer and the process segfaulted out of theFlowControllerpoll path. Quiesce poll timers via a newHardwareObject::prepareForShutdown()virtual invoked before worker-thread teardown, with aQPointerguard around the nested loop for the residual case (70fdc9ad).Fixed the flow-controller poll interval not refreshing when the user changed it in the Hardware Settings dialog: the
PythonFlowControllertrampoline overrodereadSettingswithout chaining toFlowController::readSettings, so the base-class timer reload was silently bypassed. Restructured the contract as a non-virtual interface —HardwareObjectexposeshwReadSettingsas the sole entry point, each intermediate hardware basefinal-overrides it and dispatches to a per-base hook (fcReadSettings,pcReadSettings,tcReadSettings,pgReadSettings,awgReadSettings,clockReadSettings,ftmwReadSettings,gpibReadSettings,ioReadSettings,lifLaserReadSettings,lifDigitizerReadSettings) — so a derived driver that forgets to chain becomes a compile error rather than a silent runtime omission (d512ee5e).
Hardware configuration.
Fixed loadout persistence and timestamp handling on save (1c9586b2, f8e83611).
Fixed the
SettingsStoragenested-group wipe that affected FTMW preset CRUD (3d73f08d).Fixed several runtime-hardware-config defects: protocol registry initialization, vtable crashes during hardware destruction, and a deadlock in the configuration dialog (68e49ab2).
Fixed multiple Runtime Hardware Configuration Dialog defects (7a299892, aced0817, ed915a93, d66aa076).
Fixed
BC_ALLHARDWAREbuild errors and the LIF logic underBC_ALLHARDWARE(0bfe75c0, fe7b5f0a).Fixed GPIB protocol configuration and connection testing (cfd85d62).
Fixed Communication Settings dialog and clock-manager initialization (19f60cf6, d733af0d).
Fixed vendor-library search priority and the library browse dialog (1c4f6604).
Fixed
QVariantenum serialization and duplicate error messages when switching protocols (f7e3d6f7).Fixed optional-hardware configuration init and wizard page population (be8a82e2).
Fixed the hardware settings editor silently discarding an enum-valued setting when its metaobject lookup failed: the field rendered as an empty selector and, on save, wrote an invalid value over the previously stored one. It now falls back to a text field that preserves the current value (615787a6).
Acquisition.
Fixed chirp recalculation and RF-config loss in the experiment wizard (1483a2d7).
Fixed a minor
FtmwViewWidgetrendering glitch under heavy processing load (637d6d4e).Fixed a long-standing crash on LIF-only experiments when the backup interval was set to a non-zero value: the backup scheduler dereferenced the unallocated FTMW configuration. LIF data is segment-flushed at acquisition time, so backup is now skipped for non-FTMW experiments (f335b11d).
Tooling.
Fixed an intermittent crash on closing
blackchirp-viewer(446a5c0a).Made
ZoomPanPlotcurve attach and detach thread-safe via a curve registry, eliminating a class of races that surfaced in both the main application and the viewer (af4aab85).Fixed additional
ZoomPanPlotdefects surfaced during the API-reference work (feb21753).
User interface.
Fixed
ScientificSpinBoxnot displaying an initial value of0.0(00b0608d).Fixed overlays and aux data never persisting for experiments opened by path: the disk-loading
Experimentconstructor passed the placeholder number rather than the header-resolved one to its sub-storages, andOverlayStoragegates all disk writes on a valid experiment number (5a595db8).Fixed catalog overlays always rendering as a step plot and overwriting the saved curve style on every load. The stick-plot style is now a creation-time default, so switching a convolved catalog to a line plot survives reloads (1f473d60).
Fixed the overlay Configure dialog silently erasing an existing comment because the comment field was never populated from the overlay before the dialog wrote it back (286fe2fe).
Fixed a stray duplicate checkbox appearing in the overlay table when toggling visibility: the paint-based delegate also created a real checkbox editor (175e66b3).
Fixed a “pure virtual method called” crash when removing an overlay while a plot filter pass was in flight; the curve is now drained and unregistered before destruction (b82736e6).
Fixed the Peak Find Remove control doing nothing: the button’s clicked signal was never connected, so selected peaks could not be removed from the list (004c523b).
Fixed a use-after-free when a Peak Find pass outlived its widget. The background search discarded its future, so reloading the experiment or tearing down the dock mid-search could free members still in use; the pass is now drained before destruction (9428b017).
Fixed Peak List Export dialog defects: the dipole spin box ignored its enabled setting on load, persisted fractional intensity thresholds were truncated to integers, cancelling the save-file dialog raised a spurious export-failure box, and edits to the shots/intensity table were discarded unless the FTB format was exported (f15eb918).
Fixed the catalog overlay creation dialog leaving the frequency-range filtering controls disabled even after a valid catalog file was selected; they were only editable when reconfiguring an existing overlay (3341b0ad).
Fixed the Generic XY overlay dialog locking the delimiter, header-line, column-mapping, and filtering controls until the file already parsed, so a file that needed manual settings to parse could never be coaxed into parsing. Source-file validity is now existence-based; parse correctness still gates overlay creation (3341b0ad).
Fixed the Generic XY overlay reporting an opaque parser-availability or parse failure. The selected file is always handed to the Generic XY parser, and the failure message states the cause, such as a file containing only one column (3341b0ad).
Python companion module.
Made
BCFid.ftidempotent across all processing options. The windowed slice taken fromself.datawas a numpy view, so the in-placeFidRemoveDCsubtraction and the per-frame exp-decay multiplication mutatedself.dataand a secondftcall on the same FID produced different output (6fed7a0e).Fixed integer-coded enum cells failing to resolve when pandas delivered them as numpy scalars. A
fidparamsrow spanning mixed-dtype columns is upcast tofloat64, so an integer-coded field such assidebandreached the enum helper asnumpy.float64and raisedValueError: Unsupported enum value type. Numpy integer and integral-valued float scalars now resolve through the integer-code path, sois_lower_sidebandand other enum-bearing accessors work on older integer-coded exports (89ff0ba9).