.. index:: single: 2.0.0; release notes single: release notes; 2.0.0 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 :doc:`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 :doc:`/user_guide/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 :doc:`/user_guide/hardware_config`. - 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 :doc:`/user_guide/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 :doc:`/user_guide/cp-ftmw`. - Consolidated logging through a thread-safe ``LogHandler`` and replaced ``qDebug()`` everywhere with the ``bcLog`` / ``bcWarn`` / ``bcError`` / ``bcDebug`` and ``hwLog`` / ``hwWarn`` / ``hwError`` / ``hwDebug`` free-function families; a runtime debug-logging toggle in the new Application Configuration dialog writes a ``debug_YYYYMM.csv`` file when enabled. See :doc:`/user_guide/log_tab` and :doc:`/user_guide/application_config`. - Added an in-process crash handler that captures POSIX signals (Linux, macOS) and Windows unhandled exceptions to a diagnostic report under ``/log/crashes/``, with a startup notification when an earlier run crashed. Release builds keep debug info so the captured frames resolve to source lines via ``addr2line`` / ``atos`` / WinDbg. See :doc:`/user_guide/crash_reports`. - Overhauled the documentation: refreshed the :doc:`User Guide ` end to end against the 2.0 feature set, added the new :doc:`Developer Guide ` for contributors, and substantially expanded the :doc:`C++ API reference ` to cover the hardware, experiment, persistence, and orchestration classes. - Refreshed the companion ``blackchirp`` Python package against the v2 on-disk schema, added LIF read and processing support (``BCLIF``, ``BCLifTrace``), extended ``BCFTMW`` with 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 as ``0.1.0rc1``. See :doc:`/python`. Build and distribution ---------------------- - Replaced the qmake build with CMake. ``config.pri`` is no longer used; build options are configured through CMake cache variables. See :doc:`/user_guide/installation`. - Added official binary packages for Linux, Windows, and macOS, with bundled Qt redistributables on Windows and macOS. See :doc:`/user_guide/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_ALLHARDWARE`` and per-driver toggles) so packagers can produce restricted builds when needed. See :doc:`/user_guide/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.qrc`` resource with a dynamic FID simulation generator, so the Virtual digitizer produces synthetic data without bundling sample CSVs. See :doc:`/user_guide/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 :doc:`/user_guide/hardware_config/profiles`, :doc:`/user_guide/hardware_config/loadouts`, and :doc:`/user_guide/ftmw_configuration/presets`. - Added a first-run hardware onboarding flow that walks a new user through profile creation. See :doc:`/user_guide/first_run`. - Added the Hardware Loadouts submenu and a loadout selector in the runtime hardware configuration dialog. See :doc:`/user_guide/hardware_menu`. - Added the FTMW preset bar with full create, copy, save-as, and delete operations. See :doc:`/user_guide/ftmw_configuration/presets`. - Added the consolidated *FTMW Configuration* menu entry and ``FtmwConfigDialog``, replacing the v1.x scattered FTMW pages. See :doc:`/user_guide/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 :doc:`/user_guide/application_config`. - Added a ``VendorLibrary`` staging system and a Library Configuration interface for managing externally-supplied drivers, with platform-specific installation guidance. See :doc:`/user_guide/hardware_config/library_status` and :doc:`/user_guide/installation`. - Added the hardware settings registry: per-device settings are declared once and rendered into the per-device dialog by the ``HwSettingsWidget`` with 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 :doc:`/user_guide/hwdialog`. - Added per-object hardware threading configuration to the hardware profile. See :doc:`/user_guide/hardware_config/profiles`. - Added a "Direct Control" hardware concept for hardware operated outside an experiment. See :doc:`/user_guide/hardware_config`. 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 :doc:`/user_guide/python_hardware`. - Python drivers expose RS232, TCP, GPIB, and Custom protocols. See :doc:`/user_guide/python_hardware/per_type_capabilities`. - The Python hardware combo box prepopulates from class names scanned out of available scripts. See :doc:`/user_guide/python_hardware/selecting`. - Added runtime communication-protocol selection per hardware object via the per-device dialog, with protocol-specific widgets backed by group-based settings storage. See :doc:`/user_guide/hwdialog`. - Modernized the GPIB controller architecture so multiple GPIB controllers (mixed LAN and RS232) cohabitate in one installation. See :doc:`/user_guide/hardware_details`. - Added Test Connection and Communication Settings shortcuts to the per-device dialog. See :doc:`/user_guide/hwdialog`. - Replaced the four fixed AWG protection/gate spinboxes with a generalized marker system: arbitrary ``MarkerChannel`` / ``MarkerRole`` definitions are entered through a marker table on the chirp configuration tab. See :ref:`chirp-setup-markers` on the :doc:`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 :doc:`/user_guide/hardware_config/library_status` and :doc:`/user_guide/installation`. - Added the Spectrum vendor-library wrapper with dynamic loading for both Spectrum digitizer families. See :doc:`/user_guide/hardware_config/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 :doc:`/user_guide/cp-ftmw`. - Added backpressure-triggered pre-accumulation in ``FtmwDigitizer`` so the worker thread keeps up under bursty load. See :doc:`/user_guide/cp-ftmw`. - Added parallel batched parse and accumulate in ``AcquisitionManager``. See :doc:`/user_guide/cp-ftmw`. - Consolidated the FTMW experiment-setup pages into ``FtmwConfigWidget``. See :doc:`/user_guide/experiment_setup`. - Extracted the LO scan and DR scan controls into reusable widgets and incorporated them into the experiment-wizard Type page. See :doc:`/user_guide/experiment/acquisition_types`. - The number-of-chirps spinbox is now enabled unconditionally; a warning is emitted when the active digitizer does not support multi-record acquisition. See :doc:`/user_guide/ftmw_configuration/digitizer_setup`. User interface -------------- - Added a Help menu with About dialog, library information, and links to online resources. See :doc:`/user_guide/ui_overview`. - Added the FTMW preset submenu under the Hardware menu. See :doc:`/user_guide/hardware_menu`. - Reworked the experiment-info panel and wired ``HwStatusBox`` configure actions so each status box opens the device dialog directly. See :doc:`/user_guide/ui_overview`. - Polished the left-side status panel layout and shortened hardware status box titles. See :doc:`/user_guide/ui_overview`. - Added a Fixed step mode and full-precision handling to the ``ScientificSpinBox``. See :doc:`/user_guide/ui_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 :doc:`/user_guide/hardware_menu`. - Updated the Peak Find Widget icon. See :doc:`/user_guide/cp-ftmw`. - 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 :doc:`/user_guide/cp-ftmw`. - 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 :doc:`/user_guide/cp-ftmw`. - 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 :doc:`/user_guide/cp-ftmw`. - 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.csv`` file and falling back to the application-wide defaults when none has been saved, mirroring the FID processing-settings behavior. See :doc:`/user_guide/cp-ftmw`. - Added a selectable column delimiter for curve XY exports: a drop-down beside the right-click ``Export XY`` action chooses semicolon, comma, tab, or aligned whitespace. The choice is persisted application-wide and shared between Blackchirp and the viewer. See :doc:`/user_guide/plot_controls`. - Relaxed the experiment-setup dialog minimum size. See :doc:`/user_guide/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 :doc:`/user_guide/overlays`. Logging and diagnostics ----------------------- - Redesigned ``LogHandler`` as a thread-safe global singleton with a ``QAnyStringView`` API. See :doc:`/user_guide/log_tab`. - Added ``bcLog`` / ``bcWarn`` / ``bcError`` / ``bcDebug`` and ``hwLog`` / ``hwWarn`` / ``hwError`` / ``hwDebug`` free functions and migrated every call site in the source tree off ``logMessage`` signals and ``qDebug()``. See :doc:`/user_guide/log_tab`. - Added a runtime debug-logging toggle in the Application Configuration dialog; when enabled, debug-level output is written to a ``debug_YYYYMM.csv`` file alongside the standard log. See :doc:`/user_guide/application_config`. - Successful connection-test events are highlighted in the Log tab so they stand out from informational chatter. See :doc:`/user_guide/log_tab`. - Added an in-process crash handler. POSIX installs ``sigaction`` handlers (SIGSEGV/SIGABRT/SIGFPE/SIGILL/SIGBUS) on a ``sigaltstack`` and writes a text crash log via raw ``write(2)`` with frames resolved through ``dladdr`` to ``module(+0xoffset) [0xpc]`` lines. Windows installs ``SetUnhandledExceptionFilter`` plus 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 ``/log/crashes/`` and carry the build identity (git SHA) so they can be resolved against an unstripped binary. See :doc:`/user_guide/crash_reports` and :doc:`/developer_guide/crash_handling` (:commit:`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 :doc:`/user_guide/crash_reports` (:commit:`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 in ``cmake/Packaging.cmake`` (:commit:`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 :doc:`/user_guide/application_config`. - Migrated to label-based hardware identification across configurations and on-disk storage. Implementation key strings became labels keyed off the runtime hardware configuration. See :doc:`/user_guide/data_storage`. - Added a ``markers.csv`` file written under each experiment directory recording the active marker channel definitions for the run. See :doc:`/user_guide/data_storage`. - Added the ``RfConfigSnapshot`` helper for serializing the full RF configuration with each experiment. See :doc:`/user_guide/ftmw_configuration/rf_configuration`. Python companion module ----------------------- - Hardened ``BCFTMW`` and ``BCFid`` against schema drift across the v1 and v2 on-disk formats: window-function dispatch is driven by an explicit name → ``scipy.signal`` map, sideband selection accepts both numeric and string forms, ``FtUnits`` accepts both numeric and ``FtV`` / ``FtmV`` / ``FtuV`` / ``FtnV`` forms, and a single helper centralizes the dual-form parse used by every enum-bearing field. Unknown enum values raise ``ValueError`` rather than falling through to a silent default. See :doc:`/python/bcfid` and :doc:`/python/bcftmw` (:commit:`10bd9d08`). - ``BCExperiment`` reads ``markers.csv`` when present and exposes the active marker channel definitions as a ``markers`` DataFrame attribute. The ``hardware.csv`` reader accepts both the legacy ``subKey`` and the current ``driver`` second-column headers, and tolerates the historical ``hardwareType`` column being numeric, string, or absent — so v1 fixtures continue to load alongside v2 captures. See :doc:`/python/bcexperiment` (:commit:`10bd9d08`). - Added a differential-FID API on ``BCFTMW``: ``is_multi_segment``, ``num_backups``, and ``get_differential_fid(start, end)`` produce a ``BCFid`` whose data and shot count reflect the cumulative FID between two backup points in ``fidparams.csv``, with ``vmult`` scaling recomputed from the bounding entries. See :doc:`/python/bcftmw` (:commit:`10bd9d08`). - Added optional axis-unit selection on ``BCFid.x``, ``BCFid.xy``, ``BCFid.ft``, and ``BCFTMW.process_sideband``. Time axes accept ``s`` / ``ms`` / ``us`` / ``μs`` / ``ns`` and frequency axes accept ``Hz`` / ``kHz`` / ``MHz`` / ``GHz`` / ``THz``; intensities and the user-facing μs/MHz gate keyword arguments are unchanged. See :doc:`/python/bcfid` (:commit:`9285f0f8`). - Added ``BCLIF`` and ``BCLifTrace`` for LIF read and processing, mirroring the C++ ``LifTrace`` semantics. ``BCLifTrace`` exposes per-trace ``smooth`` (IIR low-pass plus Savitzky–Golay) and ``integrate`` (sample-space trapezoidal sum, with reference-channel ratio when a reference is present); ``BCLIF`` provides ``delay_axis`` / ``laser_axis``, ``delay_slice`` / ``laser_slice``, and ``image`` aggregating helpers with configurable ``fill=np.nan|0.0`` for missing scan points. See :doc:`/python/bclif` and :doc:`/python/bcliftrace` (:commit:`dc7e7640`). - Restructured the Sphinx documentation into per-class pages matching the C++ API reference layout, refreshed ``single-fid.ipynb`` against the v2 schema, and added a fully executed ``single-lif.ipynb`` covering trace loading, smoothing, integration, slice extraction, and 2-D image rendering. See :doc:`/python` (:commit:`7cb8ab84`). - Added multi-experiment FID coaveraging via the new ``coaverage_fids`` and ``coaverage_spectra`` module-level functions. ``coaverage_fids`` produces a :class:`BCFid` whose 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_spectra`` returns a shot-weighted magnitude-spectrum coaverage. Both refuse on any mismatch in ``spacing``, ``size``, ``sideband``, ``probefreq``, ``vmult``, or frame count. See :doc:`/python/bcfid`. - Tagged the package as ``0.1.0rc1`` on PyPI. ``pip install blackchirp`` continues to resolve to the prior stable release; testers opt in with ``pip install --pre blackchirp`` or ``pip install blackchirp==0.1.0rc1`` (:commit:`4a9b69d0`). Bug fixes --------- **Hardware.** - Fixed inverted marker bit-packing on the AWG70002A and AWG7122B (:commit:`ba07d008`). - Fixed common-LO clock persistence and clock-frequency signal chaining (:commit:`836b7750`). - Fixed the *Apply Clock Settings* button so clock changes can be pushed without closing the dialog (:commit:`cd07dd5f`). - Fixed aux-data registration key mismatches in the flow controller and temperature controller paths and corrected the resulting plot labels (:commit:`79dfe7e8`, :commit:`8e67bebb`, :commit:`8458aad9`). - Fixed flow-controller channel display and the underlying destructor; refined the gas-flow display layout (:commit:`e53d7f90`, :commit:`eb8d7fbc`, :commit:`6783af97`). - Fixed the flow-controller poll loop and the Python template- copy workflow (:commit:`63fee23d`). - Fixed Python hardware experiment aux-data emission and host- script deployment (:commit:`dfb57021`). - Fixed threaded hardware destructors not running on shutdown: ``~HardwareManager`` joined each worker thread but never deleted the moved-to-thread object, so settings persisted by ``~SettingsStorage::save()`` (such as flow-controller channel names on ``PythonFlowController``) were silently dropped on exit (:commit:`e0acf07d`). - Fixed a destruction race during application close when a Python hardware driver was actively polling: ``PythonProcess::sendRequest`` ran a nested ``QEventLoop`` on the hardware thread to service relay requests, and shutdown could destroy the driver while that loop was in flight, so the post-loop ``isRunning()`` check dereferenced a dangling pointer and the process segfaulted out of the ``FlowController`` poll path. Quiesce poll timers via a new ``HardwareObject::prepareForShutdown()`` virtual invoked before worker-thread teardown, with a ``QPointer`` guard around the nested loop for the residual case (:commit:`70fdc9ad`). - Fixed the flow-controller poll interval not refreshing when the user changed it in the Hardware Settings dialog: the ``PythonFlowController`` trampoline overrode ``readSettings`` without chaining to ``FlowController::readSettings``, so the base-class timer reload was silently bypassed. Restructured the contract as a non-virtual interface — ``HardwareObject`` exposes ``hwReadSettings`` as the sole entry point, each intermediate hardware base ``final``-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 (:commit:`d512ee5e`). **Hardware configuration.** - Fixed loadout persistence and timestamp handling on save (:commit:`1c9586b2`, :commit:`f8e83611`). - Fixed the ``SettingsStorage`` nested-group wipe that affected FTMW preset CRUD (:commit:`3d73f08d`). - Fixed several runtime-hardware-config defects: protocol registry initialization, vtable crashes during hardware destruction, and a deadlock in the configuration dialog (:commit:`68e49ab2`). - Fixed multiple Runtime Hardware Configuration Dialog defects (:commit:`7a299892`, :commit:`aced0817`, :commit:`ed915a93`, :commit:`d66aa076`). - Fixed ``BC_ALLHARDWARE`` build errors and the LIF logic under ``BC_ALLHARDWARE`` (:commit:`0bfe75c0`, :commit:`fe7b5f0a`). - Fixed GPIB protocol configuration and connection testing (:commit:`cfd85d62`). - Fixed Communication Settings dialog and clock-manager initialization (:commit:`19f60cf6`, :commit:`d733af0d`). - Fixed vendor-library search priority and the library browse dialog (:commit:`1c4f6604`). - Fixed ``QVariant`` enum serialization and duplicate error messages when switching protocols (:commit:`f7e3d6f7`). - Fixed optional-hardware configuration init and wizard page population (:commit:`be8a82e2`). **Acquisition.** - Fixed chirp recalculation and RF-config loss in the experiment wizard (:commit:`1483a2d7`). - Fixed a minor ``FtmwViewWidget`` rendering glitch under heavy processing load (:commit:`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 (:commit:`f335b11d`). **Tooling.** - Fixed an intermittent crash on closing ``blackchirp-viewer`` (:commit:`446a5c0a`). - Made ``ZoomPanPlot`` curve attach and detach thread-safe via a curve registry, eliminating a class of races that surfaced in both the main application and the viewer (:commit:`af4aab85`). - Fixed additional ``ZoomPanPlot`` defects surfaced during the API-reference work (:commit:`feb21753`). **User interface.** - Fixed ``ScientificSpinBox`` not displaying an initial value of ``0.0`` (:commit:`00b0608d`). - Fixed overlays and aux data never persisting for experiments opened by path: the disk-loading ``Experiment`` constructor passed the placeholder number rather than the header-resolved one to its sub-storages, and ``OverlayStorage`` gates all disk writes on a valid experiment number (:commit:`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 (:commit:`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 (:commit:`286fe2fe`). - Fixed a stray duplicate checkbox appearing in the overlay table when toggling visibility: the paint-based delegate also created a real checkbox editor (:commit:`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 (:commit:`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 (:commit:`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 (:commit:`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 (:commit:`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 (:commit:`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 (:commit:`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 (:commit:`3341b0ad`). **Python companion module.** - Made :meth:`BCFid.ft ` idempotent across all processing options. The windowed slice taken from ``self.data`` was a numpy view, so the in-place ``FidRemoveDC`` subtraction and the per-frame exp-decay multiplication mutated ``self.data`` and a second ``ft`` call on the same FID produced different output (:commit:`6fed7a0e`).