Skip to content

Tag: add spectrum() — toolbox-free single-sided amplitude spectrum (frequency-domain sibling to the Tag analysis family) #338

Description

@HanSur94

Problem / motivation

FastSense has grown an entire time-domain Tag analysis family of proposed primitives — derivative() (#326), cumulativeIntegral() (#327), crossings(level) (#328), findPeaks(...) (#329), exceedance(level) (#316), movingStat(window,type) (#312), findGaps() (#306), resampleUniform(dt) (#308), stateDurations() (#258). Every one operates in the time domain.

The single most important analysis primitive for the target user — a MATLAB sensor-analysis engineer working with vibration / rotating-machinery / acoustic / structural data — is frequency-domain analysis, and it is absent from both the code and the tracker.

  • grep -rniE "fft|spectrum|psd|fourier|spectral" over libs/SensorThreshold/ → nothing (only a binary .mex false hit).
  • gh issue list --state all --search over fft / spectrum / amplitude spectrum / frequency domain / spectral / dominant frequency / fourier / psd / periodogramno matching issue.

"What frequencies are in this signal, and which one dominates?" is a canonical sensor question (bearing-defect orders, resonance, imbalance, line-frequency hum). Today a FastSense user must hand-roll fft, build the frequency vector, take abs, fold to single-sided, and normalize — exactly the boilerplate the rest of the analysis family exists to eliminate. It is the conspicuous missing sibling of that family.

Proposed feature

A base-Tag convenience method returning a single-sided amplitude spectrum computed with core fft (no Signal Processing Toolbox):

[f, amp] = tag.spectrum();                  % infer Fs from median dt over getXY
[f, amp] = tag.spectrum('SampleRate', 2000);
[f, amp] = tag.spectrum('Detrend', true);   % remove mean / linear trend before FFT
fPeak   = tag.dominantFrequency();          % optional drop-on: argmax of amp

Rough sketch

Single method on libs/SensorThreshold/Tag.m (base class, so every subclass inherits it — same placement as the rest of the proposed analysis family), built on the existing getXY(obj) accessor (Tag.m:120, overridden per subclass, e.g. SensorTag.m:115):

  1. [X, Y] = obj.getXY(); drop NaNs; require ≥ 2 points.
  2. Determine Fs: explicit 'SampleRate' NV wins; else infer from 1/median(diff(X)).
  3. Optional 'Detrend' (default false): subtract mean (or a linear fit) — toolbox-free.
  4. N = numel(Y); Yf = fft(Y); amp = abs(Yf(1:floor(N/2)+1))/N; amp(2:end-1) = 2*amp(2:end-1); f = (0:floor(N/2))' * Fs/N; → return [f, amp].

Pure-function, read-only; no new property, no toStruct/fromStruct change, no Tag/DashboardWidget contract touched. Output [f, amp] is a plain array pair the caller can hand to a standalone FastSense/ad-hoc plot or a widget — identical downstream shape to the rest of the family. dominantFrequency() (argmax of amp) is an optional one-line sibling.

Value

High. Unlocks the whole frequency-analysis workflow the target user base needs and that FastSense currently forces them to leave the library for; completes the analysis family with its most domain-critical member.

Constraints check

  • Toolbox-free: fft / abs / interp1 / polyfit are all core MATLAB and Octave — no Signal Processing Toolbox.
  • Backward-compatible: a brand-new method cannot break existing scripts or serialized dashboards; nothing else changes.
  • Pure MATLAB/Octave: yes; works through the existing Tag contract exactly as the filed time-domain family does.
  • Fit note (flagged for the product call): a meaningful FFT assumes uniform sampling, and sensor streams can be non-uniform. The method must state its policy clearly — either require near-uniform sampling and error with a helpful message pointing at resampleUniform (Tag: add resampleUniform(dt) to resample onto a uniform time grid (kind-aware interpolation) #308), or resample internally with a documented default. Both options are toolbox-free; this is a design decision, not a blocker.

Effort estimate

S–M — one method (+ optional dominantFrequency one-liner) in a single file, plus a focused test (pure sine at known Fs → single dominant bin at the right frequency; DC/mean handling; Detrend path; too-few-points guard).

Dedup

Clean. No issue/PR mentions FFT, spectrum, PSD, Fourier, spectral, or frequency-domain analysis. The time-domain analysis family (#306/#308/#312/#316/#326/#327/#328/#329/#258) is orthogonal — this is their frequency-domain sibling, not a duplicate.


AI-proposed via /feature-scout — needs a human product decision before implementation.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions