FtWorker
FtWorker is the analysis-pipeline class that converts Fid
objects into Ft magnitude spectra. Three slot methods cover
the three usage patterns: doFT() for a single FT, doFtDiff() for
the difference between two spectra, and processSideband() for the
incremental LO-scan stitching that builds a broadband spectrum from a
series of per-LO-step FTs. Each slot is invoked through
QtConcurrent::run rather than via a dedicated QThread; results
are returned both by signal (ftDone, ftDiffDone,
sidebandDone) and as the slot’s return value, so the same instance
serves both the asynchronous UI path (FtmwViewWidget) and the
synchronous batch path (BatchManager).
The transform itself uses the GSL mixed-radix real FFT, which is most
efficient when the FID length factors into powers of 2, 3, and 5. The
frequency-domain plot, peak finder, and overlay system in both
blackchirp and the blackchirp-viewer consume the resulting
Ft via ExperimentViewWidget; the user-facing controls
that drive FidProcessingSettings are described in
Data Storage and the FT-domain UI documentation.
Preprocessing pipeline
Before the FFT, FtWorker applies an optional pipeline of
time-domain steps driven by FidProcessingSettings:
Truncation to a sub-window via
startUs/endUs.DC removal (subtract the FID mean).
Exponential apodization (
expFilter).Zero-padding (
zeroPadFactor).Window-function apodization — one of
FtWindowFunction: Bartlett, Blackman, Blackman-Harris, Hamming, Hanning, Kaiser-Bessel.
The magnitude scale of the output Ft is controlled by
FidProcessingSettings::units. The enumeration values map directly
to powers of ten relative to the digitized voltage: e.g. FtmV = 3
multiplies by 10³ / rawSize, so the spectrum reads in mV per FFT
bin. The window-function cache is keyed on (window, length) and
guarded by pu_winfLock so repeated FFTs at the same size pay the
window cost only once.
Threading
FtWorker is a QObject but is not moved to a dedicated
QThread. Callers invoke doFT(), doFtDiff(), and
processSideband() through QtConcurrent::run, which schedules
each call on the global thread pool. The signals ftDone,
fidDone, ftDiffDone, and sidebandDone are emitted from the
thread-pool thread, so connections to UI slots require queued delivery
(the default when the receiver lives on a different thread). When
called from a non-UI thread (e.g. a BatchManager), the
return values of doFT() and filterFid() can be used directly
without waiting for the signals. The id parameter of doFT()
selects the path: pass id >= 0 to get signal delivery
(asynchronous) or id = -1 to suppress signals (synchronous).
GSL workspace allocation is guarded by pu_fftLock and spline
allocation by pu_splineLock, so the same FtWorker instance can
be called concurrently from multiple thread-pool threads provided each
concurrent call uses a different code path.
Resource management
GSL wavetables, workspaces, and spline objects are allocated lazily on
first use and freed by the destructor. When idle-cleanup is enabled
via setIdleCleanupEnabled(), resources are also freed automatically
after a 5-minute inactivity timeout (cleanupResources()). Call
resetIdleTimer() after each processing operation to restart the
countdown.
API Reference
-
class FtWorker : public QObject
Processes
Fidobjects into magnitude spectra using the GNU Scientific Library FFT.Not moved to a dedicated
QThread:callers invokedoFT(),doFtDiff(), andprocessSideband()throughQtConcurrent::run, so theftDone/fidDone/ftDiffDone/sidebandDonesignals are emitted on a thread-pool thread and require queued connections to UI slots. The id parameter ofdoFT()picks the path:id= -1 suppresses signals (synchronous use);id>= 0 emits async signals. Per-instance locks (pu_fftLock,pu_splineLock,pu_winfLock) allow concurrent calls on the same instance provided each call uses a different code path.GSL wavetables, workspaces, and spline objects are allocated lazily on first use and freed by the destructor. When idle-cleanup is enabled via
setIdleCleanupEnabled(), resources are also freed after a 5-minute inactivity timeout;resetIdleTimer()restarts the countdown after each processing operation.Public Types
-
enum FtUnits
Output magnitude units for the Fourier-transform result.
The enumeration value is the base-10 exponent applied to the raw GSL magnitude before dividing by the FID length. For example,
FtmV= 3 means the output is in millivolts.Values:
-
enumerator FtV
Volts.
-
enumerator FtmV
Millivolts.
-
enumerator FtuV
Microvolts.
-
enumerator FtnV
Nanovolts.
-
enumerator FtV
-
enum FtWindowFunction
Window functions applied to the FID before the FFT.
Windowing reduces spectral leakage at the cost of reduced frequency resolution.
Noneapplies a rectangular (uniform) window.Values:
-
enumerator None
No windowing (rectangular window).
-
enumerator Bartlett
Bartlett (triangular) window.
-
enumerator Blackman
Blackman window.
-
enumerator BlackmanHarris
Blackman-Harris window.
-
enumerator Hamming
Hamming window.
-
enumerator Hanning
Hanning (Hann) window.
-
enumerator KaiserBessel
Kaiser-Bessel window with \(\beta = 14\).
-
enumerator None
Public Functions
-
explicit FtWorker(QObject *parent = nullptr)
Constructor; initializes GSL pointer members to null and creates internal locks and idle timer.
- Parameters:
parent – Optional parent object.
-
~FtWorker()
Destructor; frees all GSL wavetables, workspaces, and spline objects.
Public Slots
-
Ft doFT(const FidList fl, const FtWorker::FidProcessingSettings &settings, int frame = 0, int id = -1, bool doubleSideband = false)
Filters and Fourier-transforms a list of FIDs.
Selects the FID at frame (or averages all FIDs when frame < 0), applies the preprocessing pipeline described by settings, then computes the mixed-radix GSL FFT and converts coefficients to a magnitude spectrum.
The magnitude scale factor is
10^(settings.units) / rawFidSize. The DC bin at the probe frequency is zeroed regardless of settings.When id >= 0,
fidDone()andftDone()signals are emitted (useful for asynchronous callers in the UI thread). When id == -1 the signals are suppressed and only the return value is used (useful for synchronous callers such asBatchManager).GSL workspace and wavetable are allocated or reallocated when the FID length changes; allocation is protected by
pu_fftLock.- Parameters:
fl – List of FIDs to process.
settings – Preprocessing and FFT parameters.
frame – Frame index to process; negative values average all frames.
id – Caller-supplied identifier forwarded to
ftDone()andfidDone(); -1 suppresses signals.doubleSideband – When
true, produce a symmetric double-sideband spectrum.
- Returns:
The completed magnitude spectrum, or a default-constructed
Ftif fl is empty.
-
void doFtDiff(const FidList refList, const FidList diffList, int refFrame, int diffFrame, const FtWorker::FidProcessingSettings &settings)
Computes the difference spectrum between two FID lists and emits
ftDiffDone().Each FID in refList and diffList must have matching length, sideband, and spacing. When the two spectra share the same LO frequency, the difference is computed bin-by-bin. When the LO frequencies differ, the diffList spectrum is resampled onto the refList frequency grid using cubic spline interpolation before subtraction.
- Parameters:
refList – Reference FID list.
diffList – Comparison FID list.
refFrame – Frame index for the reference.
diffFrame – Frame index for the comparison.
settings – Preprocessing and FFT parameters applied to both lists.
-
void processSideband(const SidebandProcessingData &d, const FidProcessingSettings &settings)
Processes one step of an LO-scan sideband co-average and emits
sidebandDone()on the last step.Call this slot once per LO frequency step with monotonically increasing
SidebandProcessingData::currentIndexvalues from 0 toSidebandProcessingData::totalFids- 1. The internalLoScanDataaccumulator is reset whencurrentIndex== 0. On the final step, the accumulated spectrum is emitted viasidebandDone().Individual FT bins are combined using the method specified by
SidebandProcessingData::dcMethod(harmonic or geometric mean, weighted by shot count). Fractional grid alignment between LO steps is resolved by linear interpolation of the nearest two bins.- Parameters:
d – Processing parameters and FID data for this LO step.
settings – Preprocessing and FFT parameters.
-
FilterResult filterFid(const Fid fid, const FtWorker::FidProcessingSettings &settings)
Applies the preprocessing pipeline to a single FID without computing an FFT.
Performs truncation, DC removal, exponential apodization, window function application, and zero-padding as specified by settings. This is called internally by
doFT()and can also be used independently to obtain a filtered FID for display.- Parameters:
fid – Source FID.
settings – Preprocessing parameters.
- Returns:
FilterResultcontaining the preprocessed floating-point samples and their min/max.
-
void cleanupResources()
Frees all GSL wavetables, workspaces, spline objects, and window-function cache.
Safe to call from any thread; each resource group is protected by its own read/write lock. Also stops the idle timer. After this call, the next
doFT()invocation will reallocate all necessary GSL resources.
-
void resetIdleTimer()
Restarts the idle-cleanup countdown timer.
Has no effect when idle cleanup is disabled or no resources are currently allocated. The timer is restarted via a queued
QMetaObject::invokeMethodcall to ensure it runs on the correct thread.
-
void setIdleCleanupEnabled(bool enabled)
Enables or disables automatic resource cleanup on idle timeout.
When enabled is
false, the idle timer is stopped immediately. When enabled istrue, the timer will fire after 5 minutes of inactivity and callcleanupResources().- Parameters:
enabled –
trueto enable idle cleanup,falseto disable.
Signals
-
void ftDone(Ft ft, int id)
Emitted when a
doFT()call completes.Only emitted when
doFT()is called with id >= 0. The id value is forwarded from thedoFT()call so the receiver can match results to requests.- Parameters:
ft – The completed magnitude spectrum.
id – Caller-supplied identifier passed to
doFT().
-
void fidDone(QVector<double> fid, double spacing, double min, double max, quint64 shots, int id)
Emitted after FID filtering is complete, carrying the preprocessed FID for display.
Only emitted when
doFT()is called with id >= 0.- Parameters:
fid – Preprocessed floating-point FID samples (after windowing/truncation/DC removal).
spacing – Inter-sample spacing in microseconds.
min – Minimum sample value after preprocessing.
max – Maximum sample value after preprocessing.
shots – Number of co-averaged shots.
id – Caller-supplied identifier passed to
doFT().
-
void ftDiffDone(Ft ft)
Emitted when a
doFtDiff()call completes.- Parameters:
ft – Difference spectrum (reference FT minus comparison FT).
-
void sidebandDone(Ft ft)
Emitted when the final step of
processSideband()completes.- Parameters:
ft – The fully co-averaged LO-scan sideband spectrum.
Private Functions
-
QPair<QVector<double>, double> resample(double f0, double spacing, const Ft ft)
Resamples the frequency axis of ft onto a grid starting at f0 with spacing spacing.
Uses a GSL cubic spline for interpolation. Points outside the valid range of ft are set to zero. Spline allocation is guarded by
pu_splineLock.- Parameters:
f0 – Starting frequency of the target grid (MHz).
spacing – Target frequency spacing (MHz).
ft – Source spectrum to resample.
- Returns:
Pair of (resampled magnitude vector, actual starting frequency of the output grid in MHz).
-
void makeWinf(int n, FtWindowFunction f)
Recomputes
d_winffor length n and function f.
-
void winBartlett(int n)
Fills
d_winfwith Bartlett coefficients.
-
void winBlackman(int n)
Fills
d_winfwith Blackman coefficients.
-
void winBlackmanHarris(int n)
Fills
d_winfwith Blackman-Harris coefficients.
-
void winHamming(int n)
Fills
d_winfwith Hamming coefficients.
-
void winHanning(int n)
Fills
d_winfwith Hanning coefficients.
-
void winKaiserBessel(int n, double beta)
Fills
d_winfwith Kaiser-Bessel coefficients for parameter beta.
-
void clearSplineMemory()
Frees the GSL spline and accelerator objects under
pu_splineLock.
Private Members
-
std::unique_ptr<QReadWriteLock> pu_fftLock
Guards GSL FFT wavetable and workspace allocation.
-
std::unique_ptr<QReadWriteLock> pu_splineLock
Guards GSL spline and accelerator allocation.
-
std::unique_ptr<QReadWriteLock> pu_winfLock
Guards the cached window-function vector.
-
gsl_fft_real_wavetable *real
Wavetable for GNU Scientific Library FFT operations.
-
gsl_fft_real_workspace *work
Workspace for GNU Scientific Library FFT operations.
-
int d_numPnts
FID length for which the current wavetable and workspace were allocated.
-
gsl_spline *p_spline
GSL cubic spline object used for cross-LO FT resampling.
-
gsl_interp_accel *p_accel
GSL interpolation accelerator associated with
p_spline.
-
int d_numSplinePoints
Number of points for which
p_splinewas allocated.
-
FtWindowFunction d_lastWinf = {None}
Window function used to compute the cached
d_winfvector.
-
int d_lastWinSize = {0}
Size for which
d_winfwas last computed.
-
struct FtWorker::LoScanData d_loScanData
-
QVector<double> d_winf
Cached window-function coefficients; recomputed when size or type changes.
-
std::unique_ptr<QTimer> pu_idleTimer
Single-shot timer that fires after 5 minutes of inactivity.
-
bool d_resourcesAllocated = {false}
truewhen any GSL resource has been allocated since the last cleanup.
-
bool d_idleCleanupEnabled = {false}
truewhen the idle-cleanup mechanism is active.
Private Slots
-
void onIdleTimeout()
Triggered by the idle timer; calls
cleanupResources()when idle cleanup is enabled.
-
void startIdleTimer()
Starts or restarts the idle timer; must be called from the object’s thread.
Friends
- friend class FtWorkerTest
-
struct FidProcessingSettings
Parameters that control FID preprocessing and FFT output.
All fields must be set before passing an instance to
doFT()orfilterFid().Public Members
-
double startUs
Start of the time window to process, in microseconds (0 = beginning of FID).
-
double endUs
End of the time window to process, in microseconds (0 = end of FID).
-
double expFilter
Exponential apodization time constant in microseconds (0 = disabled).
-
int zeroPadFactor
Zero-padding multiplier: 0 = none, 1 = next power of 2 × 2, 2 = × 4.
-
bool removeDC
When
true, subtract the mean of the windowed FID before the FFT.
-
double autoScaleIgnoreMHz
Frequency half-width around the LO (MHz) to exclude from autoscale min/max tracking.
-
FtWindowFunction windowFunction
Apodization window applied after truncation and DC removal.
-
double startUs
-
struct FilterResult
Return value of
filterFid().
-
struct LoScanData
Per-instance accumulator for an in-progress LO-scan sideband co-average.
Populated during successive
processSideband()calls; reset whenSidebandProcessingData::currentIndex== 0.Public Functions
-
inline uint indexOf(const double f)
Returns the output grid index nearest to frequency f.
-
inline double frequency(int index)
Returns the frequency corresponding to output grid index index.
-
inline double relDistance(double f)
Returns the fractional grid offset of f relative to its nearest grid point (in units of ftSpacing).
Public Members
-
QVector<double> ftData
Accumulated magnitude values on the output frequency grid.
-
uint ftPoints = {0}
Number of output frequency grid points.
-
double ftSpacing = {0.0}
Output frequency grid spacing in MHz.
-
quint64 totalShots = {0}
Total co-averaged shots accumulated so far.
-
std::pair<double, double> ftXRange = {0.0, 0.0}
[start, end] frequency range of the output grid (MHz).
-
QVector<quint64> counts
Per-bin shot-count accumulator used for weighted averaging.
-
inline uint indexOf(const double f)
-
struct SidebandProcessingData
Input bundle for a single step of an LO-scan sideband co-average.
processSideband()is called once per LO frequency step. WhencurrentIndexreachestotalFids- 1, the accumulated result is emitted viasidebandDone().Public Members
-
FidList fl
FID list for this LO step.
-
int frame = {0}
Frame index within
flto process (-1 = average all).
-
int totalFids = {0}
Total number of LO-frequency steps in the full scan.
-
int currentIndex = {0}
Zero-based index of this step within the scan.
-
double minOffset = {-1.0}
Minimum frequency offset from the LO to include (MHz).
-
double maxOffset = {-1.0}
Maximum frequency offset from the LO to include (MHz).
-
std::pair<double, double> loRange = {0.0, 0.0}
[min, max] LO probe-frequency range of the full scan (MHz).
-
RfConfig::Sideband sideband = {RfConfig::UpperSideband}
Sideband to process when not in double-sideband mode.
-
bool doubleSideband = {false}
When
true, process both sidebands simultaneously.
-
DeconvolutionMethod dcMethod = {Harmonic_Mean}
Method for combining overlapping FT bins across LO steps.
-
FidList fl
-
enum FtUnits