graph TD
A[Start: Define signal and objective] --> B{Uniform sampling?}
B -- No --> L[Use LOMBSCARGLE]
B -- Yes --> C{Need time-varying spectrum?}
C -- Yes --> D[Use STFT or SPECTROGRAM]
D --> E{Need reconstructed waveform?}
E -- Yes --> F[Use ISTFT]
E -- No --> G[Report time-frequency metrics]
C -- No --> H{Single-channel or multi-channel?}
H -- Single --> I{Exploration or monitoring?}
I -- Exploration --> J[Use ENG_PERIODOGRAM]
I -- Monitoring --> K[Use ENG_WELCH]
H -- Multi --> M[Use CSD + COHERENCE]
J --> N[Optional: RFFT + RFFTFREQ for custom features]
K --> N
M --> N
Spectral Analysis
Overview
Introduction Spectral analysis is the discipline of decomposing a signal into frequency components so engineers can see what oscillations exist, how strong they are, and when they occur. In practical terms, it translates raw time-domain data (voltage, vibration, pressure, acoustic level, current, displacement) into interpretable frequency-domain information for diagnostics, design, and control. A high-level reference is the Spectral density article, which frames why power concentration by frequency is central to modern signal processing.
From a business perspective, spectral analysis reduces uncertainty in systems where failures and inefficiencies are frequency-dependent. Rotating equipment faults produce harmonics and sidebands before catastrophic failure. Electrical networks carry switching noise at specific bands that affect compliance and reliability. Structures resonate at natural frequencies, so design teams need to avoid exciting those modes. In each case, teams are not merely asking “what happened over time?” but “which physical mechanisms are active?” Frequency-domain evidence provides that answer.
This category groups the most common industrial spectral workflows into Excel-friendly calculators backed by scientific Python. The core estimators come from SciPy Signal, while FFT primitives use NumPy FFT. Together they support one-pass diagnostics, long-run monitoring, and advanced time-frequency decomposition:
- ENG_PERIODOGRAM and ENG_WELCH estimate power spectral density (PSD) for stationary or approximately stationary data.
- CSD and COHERENCE quantify cross-channel coupling in frequency.
- STFT, SPECTROGRAM, and ISTFT handle nonstationary signals where content evolves over time.
- RFFT and RFFTFREQ provide the direct one-sided transform and frequency bins for fast custom pipelines.
- LOMBSCARGLE covers unevenly sampled data where FFT assumptions break.
This mapping also reflects Boardflare’s dual pillar strategy in technical work: physically grounded signal-processing methods on one side, and spreadsheet-operable decision workflows on the other. The result is not just “a chart,” but a repeatable process for turning sensor data into defensible engineering action.
When to Use It Spectral analysis is most valuable when the question is tied to periodicity, resonance, excitation, or coupling rather than simple time averages. Teams typically reach for these tools when time-domain plots look noisy or ambiguous, but domain knowledge suggests latent periodic structure.
One common scenario is predictive maintenance in rotating machinery. Suppose a reliability team monitors accelerometers on pumps and motors. RMS vibration may still be within limits, yet a spectral peak near bearing defect frequencies can appear weeks earlier. The team uses ENG_WELCH for robust PSD estimates across routine windows, then tracks peak growth and bandwidth over time. If two sensors on opposite housings show strong band-limited coupling via COHERENCE, the fault likely reflects a true mechanical path rather than local sensor noise. During root-cause work, CSD helps inspect phase-aware cross-power behavior between channels.
A second scenario is power electronics and grid-interfaced systems. Engineers validating an inverter care about switching harmonics, interharmonics, and control-loop artifacts. RFFT and RFFTFREQ support quick harmonic audits from short records, while ENG_PERIODOGRAM gives a baseline PSD estimate. For production test or noisy environments, ENG_WELCH is preferred because averaging lowers estimator variance and makes acceptance thresholds more stable. If current and voltage channels need causality clues in frequency, CSD and COHERENCE reveal where linear relationships are strong enough for transfer-function analysis.
A third scenario is structural dynamics and condition assessment for civil, aerospace, or automotive systems. Modal behavior is often time-varying: transient loads excite different bands as operating conditions change. Static PSD alone can hide this behavior. Here STFT and SPECTROGRAM show the time-frequency evolution, making it easier to isolate bursts, chirps, or intermittent resonances. After selective filtering or spectral editing, ISTFT reconstructs the time-domain signal for downstream fatigue or control simulations.
A fourth scenario appears in observational data where sampling is irregular, such as astronomy, remote telemetry, or field measurements with dropouts. Standard FFT methods assume uniform sample spacing and can produce misleading artifacts when that assumption is violated. LOMBSCARGLE is designed for this case and estimates periodic content from uneven timestamps without requiring naive interpolation.
In practice, teams combine these tools by workflow stage:
- Discovery: ENG_PERIODOGRAM, RFFT, RFFTFREQ
- Reliable monitoring: ENG_WELCH, COHERENCE
- Cross-channel diagnosis: CSD, COHERENCE
- Nonstationary analysis: STFT, SPECTROGRAM, ISTFT
- Irregular sampling: LOMBSCARGLE
Use this category when decisions depend on separating mechanism from noise. If the objective is only central tendency or trend, simpler time-domain statistics are usually enough.
How It Works Spectral methods rely on representing a finite sampled signal as a sum of sinusoidal components. For a sampled sequence x[n], the discrete Fourier transform (DFT) is
X[k] = \sum_{n=0}^{N-1} x[n] e^{-j2\pi kn/N}
where k indexes frequency bins. For real-valued input, negative-frequency components mirror positive frequencies, so one-sided transforms via RFFT are efficient.
Frequency-axis interpretation is handled by RFFTFREQ:
f_k = \frac{k}{Nd}, \quad k=0,\dots,\left\lfloor\frac{N}{2}\right\rfloor
with sample spacing d=1/f_s. This axis is essential for converting “bin index” into engineering units (Hz).
For energy or power interpretation, teams estimate power spectral density (PSD). A basic estimate is the periodogram:
\hat{P}_{xx}(f) = \frac{1}{Nf_s}\left|X(f)\right|^2
implemented in ENG_PERIODOGRAM. The periodogram is simple and high-resolution, but its variance is high: adjacent runs can fluctuate strongly even when the underlying process is unchanged.
Welch’s method, implemented by ENG_WELCH, reduces this variance by splitting the signal into overlapping segments, windowing each segment, computing periodograms, and averaging:
\hat{P}^{\text{Welch}}_{xx}(f) = \frac{1}{M}\sum_{m=1}^{M} \hat{P}^{(m)}_{xx}(f)
This introduces a bias-variance tradeoff: better stability but reduced frequency resolution. Operationally, this is often the right trade for monitoring and alerting.
Cross-spectral methods generalize PSD to multiple channels. CSD estimates cross power spectral density P_{xy}(f), while COHERENCE normalizes it to the familiar magnitude-squared coherence:
C_{xy}(f) = \frac{|P_{xy}(f)|^2}{P_{xx}(f)P_{yy}(f)}
Values near 1 indicate strong linear relation at frequency f; values near 0 indicate weak linear relation. Coherence is widely used to distinguish real coupling from coincidental spectral peaks.
For nonstationary signals, time localization is required. STFT computes a Fourier transform on sliding windows:
X(m,\omega)=\sum_{n=-\infty}^{\infty}x[n]w[n-m]e^{-j\omega n}
where w is the window and m is time index of the frame. SPECTROGRAM usually reports |X(m,\omega)|^2 (or related modes such as magnitude/phase), producing a time-frequency energy map. ISTFT performs overlap-add reconstruction when analysis/synthesis conditions are consistent (windowing, hop size, overlap, and boundary conventions).
When timestamps are uneven, classical FFT assumptions do not hold. LOMBSCARGLE solves a frequency-wise least-squares problem against sinusoidal bases. Conceptually, for each angular frequency \omega, it fits
y(t) \approx a\cos(\omega t) + b\sin(\omega t)
and uses fit quality as spectral power. This avoids forcing irregular data onto a uniform grid before analysis.
Implementation assumptions matter as much as formulas:
- Sampling and aliasing: meaningful spectra require sufficient sampling rate and anti-alias considerations.
- Window choice: Hann/Tukey/boxcar and others alter leakage and amplitude behavior.
- Segment settings:
nperseg,noverlap, andnfftcontrol resolution, variance, and interpolation density. - Detrending/scaling: options like constant/linear detrend and density vs spectrum scaling must match reporting intent.
- Stationarity scope: PSD methods assume local stationarity; STFT/spectrogram methods relax this by short windows.
These calculators expose those controls directly, so engineering teams can align analysis settings with standards, acceptance criteria, and physics.
Practical Example Consider a packaging line with repeated bearing issues on a conveyor drive. The site has two accelerometers on the gearbox (input and output side) sampled at f_s=2{,}000 Hz, plus motor current data at the same rate. The team wants early-warning detection and root-cause confidence before scheduling downtime.
Step 1: Build the frequency axis and quick sanity transform. They run RFFT on short baseline captures and map bins with RFFTFREQ. This confirms that expected shaft orders and harmonics are observable and not buried by obvious clipping or acquisition errors.
Step 2: Establish baseline PSD with two estimators. They compute ENG_PERIODOGRAM to inspect high-resolution peaks and ENG_WELCH to create a stable monitoring baseline. In review meetings, Welch becomes the operational KPI source because it is less volatile run-to-run.
Step 3: Test channel coupling. A peak near a suspected defect frequency appears in both gearbox channels. They compute CSD and COHERENCE. High coherence in a narrow band supports a true mechanical path rather than independent sensor artifacts. Low coherence elsewhere helps deprioritize unrelated broadband noise.
Step 4: Check nonstationary behavior under load transitions. During startup and load changes, the team runs STFT and SPECTROGRAM. They observe that the problematic band intensifies only after a torque step, indicating a condition-dependent excitation. This timing clue is critical for maintenance planning and for reproducing the issue in controlled tests.
Step 5: Reconstruct filtered signal for time-domain validation. They isolate affected time-frequency regions and use ISTFT to reconstruct a filtered waveform. The reconstructed signal is fed into existing time-domain envelope and peak-to-peak checks already used in reliability dashboards.
Step 6: Extend analysis to telemetry gaps. Some overnight records contain missing packets from wireless gateways, making uniform sampling assumptions weak. For those windows, the team uses LOMBSCARGLE on timestamped subsets to verify that the same periodic component persists despite irregular spacing.
Step 7: Operationalize in Excel-based governance. Maintenance and operations teams track three decision metrics per asset: (1) Welch band power growth, (2) coherence at defect-related bands, and (3) persistence across both uniform and uneven-sampled methods. Work orders trigger only when all three exceed thresholds, reducing false positives and unnecessary interventions.
This workflow shows the value of combining rigorous signal-processing methods with spreadsheet-native execution. Engineers retain methodological control while operations stakeholders get transparent, repeatable criteria tied directly to cost and risk.
How to Choose Choose calculators by data characteristics first, then by diagnostic objective, then by reporting requirement. The matrix below covers the most common choices in this category.
| Decision Need | Recommended Function | Use When | Strengths | Limits / Cautions |
|---|---|---|---|---|
| Fast one-sided transform of real data | RFFT | You need immediate frequency components from real-valued samples | Very fast; minimal overhead; ideal for custom feature extraction | Raw transform is not a PSD estimate; sensitive to windowing and record length |
| Frequency-bin axis for one-sided FFT | RFFTFREQ | You must map FFT bins to physical frequency units | Simple, deterministic mapping from n and d | Incorrect sample spacing gives incorrect engineering interpretation |
| Baseline PSD estimate with high detail | ENG_PERIODOGRAM | You want straightforward PSD with maximal nominal resolution | Simple and transparent; useful for exploratory peak discovery | High estimator variance; unstable for alert thresholds |
| Stable PSD for monitoring and thresholding | ENG_WELCH | You need robust repeatable PSD under noise | Lower variance through averaging; strong default for operations | Lower frequency resolution than periodogram; parameter tuning needed |
| Cross-spectrum between two channels | CSD | You need shared spectral content and phase-aware relation | Quantifies common frequency content and phase structure | Interpretation requires care if channels are weakly stationary or poorly synchronized |
| Normalized linear coupling by frequency | COHERENCE | You need confidence that shared peaks reflect true linear relation | Scale-free 0–1 metric; excellent for validating coupling | High coherence does not alone prove causality |
| Time-frequency decomposition for nonstationary signals | STFT | Frequency content changes over time | Rich complex representation; supports phase-aware analysis | Time-frequency resolution tradeoff depends on window/hop settings |
| Visual/array time-frequency power map | SPECTROGRAM | You need interpretable time-frequency energy tracking | Easy pattern detection for bursts, chirps, transients | Can hide phase detail depending on mode; parameter choices shape visibility |
| Reconstruct signal from STFT domain | ISTFT | You applied STFT-domain processing and need waveform output | Enables overlap-add reconstruction and downstream time checks | Requires parameter consistency with STFT and valid overlap/window assumptions |
| Spectral analysis for uneven timestamps | LOMBSCARGLE | Sampling is irregular or has gaps | Avoids naive resampling; robust for irregular observations | Frequency grid selection and normalization choices affect interpretation |
A practical decision flow is:
In most industrial settings, the best default stack is ENG_WELCH for baseline monitoring, COHERENCE for multi-sensor validation, and STFT/SPECTROGRAM when anomalies are episodic. ENG_PERIODOGRAM and RFFT are excellent tactical tools for rapid exploration, while LOMBSCARGLE is the right choice whenever timestamps are uneven.
For governance, teams should standardize parameter templates per asset class (sample rate, window type, segment length, overlap, scaling) and version-control those templates alongside threshold logic. That policy-level consistency makes cross-site comparisons meaningful and prevents hidden analysis drift over time. In dual-pillar terms, this is where scientific rigor and operational usability meet: advanced spectral methods rendered in a process stakeholders can execute, audit, and trust.
COHERENCE
Coherence is a frequency-domain measure of the linear relationship between two signals. It is the normalized cross power spectral density.
The magnitude squared coherence is defined as:
C_{xy}(f) = \frac{|P_{xy}(f)|^2}{P_{xx}(f) P_{yy}(f)}
Values range from 0 to 1, where 1 indicates perfect linear relationship and 0 indicates no relationship at that frequency.
Excel Usage
=COHERENCE(x, y, fs, window, nperseg, noverlap, nfft, spectral_detrend)
x(list[list], required): Time series of measurement values for first signal.y(list[list], required): Time series of measurement values for second signal.fs(float, optional, default: 1): Sampling frequency.window(str, optional, default: “hann”): Desired window to use.nperseg(int, optional, default: null): Length of each segment.noverlap(int, optional, default: null): Number of points to overlap between segments.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “constant”): Specifies how to detrend each segment.
Returns (list[list]): A 2D array where the first row is frequencies and the second row is the magnitude squared coherence.
Example 1: Basic Coherence
Inputs:
| x | y | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 | 1.1 | 2.1 | 3.1 | 4.1 | 5.1 | 4.1 | 3.1 | 2.1 | 1.1 |
Excel formula:
=COHERENCE({1,2,3,4,5,4,3,2,1}, {1.1,2.1,3.1,4.1,5.1,4.1,3.1,2.1,1.1})
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.111111 | 0.222222 | 0.333333 | 0.444444 |
| 1 | 1 | 1 | 1 | 1 |
Example 2: Coherence with linear detrending
Inputs:
| x | y | spectral_detrend | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | linear |
Excel formula:
=COHERENCE({1,3,5,7,9,11,13,15}, {2,4,6,8,10,12,14,16}, "linear")
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.125 | 0.25 | 0.375 | 0.5 |
| NaN | NaN | NaN | NaN | NaN |
Example 3: Coherence with scalar-compatible single values
Inputs:
| x | y |
|---|---|
| 2 | 2.5 |
Excel formula:
=COHERENCE(2, 2.5)
Expected output:
| Result |
|---|
| 0 |
| NaN |
Example 4: Coherence with explicit segment length
Inputs:
| x | y | nperseg | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0.1 | 0.9 | 0.2 | -1.1 | 0.1 | 1 | 0 | -0.9 | 4 |
Excel formula:
=COHERENCE({0,1,0,-1,0,1,0,-1}, {0.1,0.9,0.2,-1.1,0.1,1,0,-0.9}, 4)
Expected output:
| Result | ||
|---|---|---|
| 0 | 0.25 | 0.5 |
| NaN | 0.987256 | NaN |
Python Code
Show Code
import numpy as np
from scipy.signal import coherence as scipy_coherence
def coherence(x, y, fs=1, window='hann', nperseg=None, noverlap=None, nfft=None, spectral_detrend='constant'):
"""
Estimate the magnitude squared coherence (Cxy) using Welch's method.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.coherence.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values for first signal.
y (list[list]): Time series of measurement values for second signal.
fs (float, optional): Sampling frequency. Default is 1.
window (str, optional): Desired window to use. Default is 'hann'.
nperseg (int, optional): Length of each segment. Default is None.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'constant'.
Returns:
list[list]: A 2D array where the first row is frequencies and the second row is the magnitude squared coherence.
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
y_arr = to_1d(y)
detrend = spectral_detrend
if detrend == "False":
detrend = False
f, cxy = scipy_coherence(
x_arr,
y_arr,
fs=float(fs),
window=window,
nperseg=int(nperseg) if nperseg is not None else None,
noverlap=int(noverlap) if noverlap is not None else None,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend
)
return [f.tolist(), cxy.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
CSD
The cross power spectral density (CSD) is a measure of the common frequency content between two signals. It is calculated by taking the Fourier transform of the cross-correlation between the two signals.
Like Welch’s method for power spectral density, this function estimates the CSD by dividing the signals into overlapping segments, computing the cross-periodogram for each segment pair, and averaging the results.
Excel Usage
=CSD(x, y, fs, window, nperseg, noverlap, nfft, spectral_detrend, return_onesided, spectral_scaling, avg_method)
x(list[list], required): Time series of measurement values for first signal.y(list[list], required): Time series of measurement values for second signal.fs(float, optional, default: 1): Sampling frequency.window(str, optional, default: “hann”): Desired window to use.nperseg(int, optional, default: null): Length of each segment.noverlap(int, optional, default: null): Number of points to overlap between segments.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “constant”): Specifies how to detrend each segment.return_onesided(bool, optional, default: true): If True, return a one-sided spectrum for real data.spectral_scaling(str, optional, default: “density”): Selects between ‘density’ and ‘spectrum’.avg_method(str, optional, default: “mean”): Method to use when averaging periodograms.
Returns (list[list]): A 2D array representing frequencies and cross spectral density.
Example 1: Basic CSD
Inputs:
| x | y | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 | 1.1 | 2.1 | 3.1 | 4.1 | 5.1 | 4.1 | 3.1 | 2.1 | 1.1 |
Excel formula:
=CSD({1,2,3,4,5,4,3,2,1}, {1.1,2.1,3.1,4.1,5.1,4.1,3.1,2.1,1.1})
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.111111 | 0.222222 | 0.333333 | 0.444444 |
| 4.49611 | 10.5132 | 3.43142 | 0.263405 | 0.179396 |
| 0 | 5.26328e-16 | -7.89492e-16 | 8.22387e-17 | 1.39806e-16 |
Example 2: CSD with median averaging
Inputs:
| x | y | avg_method | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | median |
Excel formula:
=CSD({1,2,1,2,1,2,1,2}, {2,1,2,1,2,1,2,1}, "median")
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.125 | 0.25 | 0.375 | 0.5 |
| 0 | -4.10865e-33 | 0 | -0.666667 | -1.33333 |
| 0 | 0 | 0 | 0 | 0 |
Example 3: CSD with spectrum scaling
Inputs:
| x | y | spectral_scaling | nperseg | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | spectrum | 4 |
Excel formula:
=CSD({0,1,0,-1,0,1,0,-1}, {0,1,0,-1,0,1,0,-1}, "spectrum", 4)
Expected output:
| Result | ||
|---|---|---|
| 0 | 0.25 | 0.5 |
| 0 | 0.5 | 0 |
| 0 | 0 | 0 |
Example 4: CSD with scalar-compatible inputs
Inputs:
| x | y |
|---|---|
| 3 | 3.2 |
Excel formula:
=CSD(3, 3.2)
Expected output:
| Result |
|---|
| 0 |
| 0 |
| 0 |
Python Code
Show Code
import numpy as np
from scipy.signal import csd as scipy_csd
def csd(x, y, fs=1, window='hann', nperseg=None, noverlap=None, nfft=None, spectral_detrend='constant', return_onesided=True, spectral_scaling='density', avg_method='mean'):
"""
Estimate the cross power spectral density (Pxy) using Welch's method.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.csd.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values for first signal.
y (list[list]): Time series of measurement values for second signal.
fs (float, optional): Sampling frequency. Default is 1.
window (str, optional): Desired window to use. Default is 'hann'.
nperseg (int, optional): Length of each segment. Default is None.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'constant'.
return_onesided (bool, optional): If True, return a one-sided spectrum for real data. Default is True.
spectral_scaling (str, optional): Selects between 'density' and 'spectrum'. Valid options: Density, Spectrum. Default is 'density'.
avg_method (str, optional): Method to use when averaging periodograms. Valid options: Mean, Median. Default is 'mean'.
Returns:
list[list]: A 2D array representing frequencies and cross spectral density.
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
y_arr = to_1d(y)
detrend = spectral_detrend
if detrend == "False":
detrend = False
f, pxy = scipy_csd(
x_arr,
y_arr,
fs=float(fs),
window=window,
nperseg=int(nperseg) if nperseg is not None else None,
noverlap=int(noverlap) if noverlap is not None else None,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend,
return_onesided=bool(return_onesided),
scaling=spectral_scaling,
average=avg_method
)
return [f.tolist(), pxy.real.tolist(), pxy.imag.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
ENG_PERIODOGRAM
The periodogram is an estimate of the spectral density of a signal. It is calculated as the squared magnitude of the discrete Fourier transform (DFT) of the signal, normalized by the sampling frequency.
P(f) = \frac{\Delta t}{N} \left| \sum_{n=0}^{N-1} x_n e^{-i 2 \pi f n \Delta t} \right|^2
where x_n are the signal samples and N is the number of samples.
Excel Usage
=ENG_PERIODOGRAM(x, fs, window, nfft, spectral_detrend, return_onesided, spectral_scaling)
x(list[list], required): Time series of measurement values (Excel range).fs(float, optional, default: 1): Sampling frequency of the x time series.window(str, optional, default: “boxcar”): Desired window to use.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “constant”): Specifies how to detrend each segment.return_onesided(bool, optional, default: true): If True, return a one-sided spectrum for real data.spectral_scaling(str, optional, default: “density”): Selects between ‘density’ and ‘spectrum’.
Returns (list[list]): A 2D array where the first row is frequencies and the second row is the power spectral density.
Example 1: Basic PSD
Inputs:
| x | fs | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 | 1 |
Excel formula:
=ENG_PERIODOGRAM({1,2,3,4,5,4,3,2,1}, 1)
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.111111 | 0.222222 | 0.333333 | 0.444444 |
| 8.76512e-32 | 15.2752 | 0.0178125 | 0.222222 | 0.0403322 |
Example 2: Periodogram with linear detrending
Inputs:
| x | spectral_detrend | |||||||
|---|---|---|---|---|---|---|---|---|
| 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | linear |
Excel formula:
=ENG_PERIODOGRAM({1,3,5,7,9,11,13,15}, "linear")
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.125 | 0.25 | 0.375 | 0.5 |
| 0 | 0 | 0 | 0 | 0 |
Example 3: Periodogram with spectrum scaling
Inputs:
| x | spectral_scaling | nfft | |||||||
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | spectrum | 8 |
Excel formula:
=ENG_PERIODOGRAM({0,1,0,-1,0,1,0,-1}, "spectrum", 8)
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.125 | 0.25 | 0.375 | 0.5 |
| 0 | 0 | 0.5 | 0 | 0 |
Example 4: Periodogram with scalar-compatible input
Inputs:
| x |
|---|
| 5 |
Excel formula:
=ENG_PERIODOGRAM(5)
Expected output:
| Result |
|---|
| 0 |
| 0 |
Python Code
Show Code
import numpy as np
from scipy.signal import periodogram as scipy_periodogram
def eng_periodogram(x, fs=1, window='boxcar', nfft=None, spectral_detrend='constant', return_onesided=True, spectral_scaling='density'):
"""
Estimate power spectral density using a periodogram.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.periodogram.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values (Excel range).
fs (float, optional): Sampling frequency of the x time series. Default is 1.
window (str, optional): Desired window to use. Default is 'boxcar'.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'constant'.
return_onesided (bool, optional): If True, return a one-sided spectrum for real data. Default is True.
spectral_scaling (str, optional): Selects between 'density' and 'spectrum'. Valid options: Density, Spectrum. Default is 'density'.
Returns:
list[list]: A 2D array where the first row is frequencies and the second row is the power spectral density.
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
detrend = spectral_detrend
if detrend == "False":
detrend = False
f, pxx = scipy_periodogram(
x_arr,
fs=float(fs),
window=window,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend,
return_onesided=bool(return_onesided),
scaling=spectral_scaling
)
return [f.tolist(), pxx.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
ENG_WELCH
Welch’s method (also known as the periodogram averaging method) computes an estimate of the power spectral density by dividing the data into overlapping segments, computing a modified periodogram for each segment, and averaging these periodograms.
This method reduces noise in the estimated power spectra in exchange for reducing the frequency resolution. It is more robust than the standard periodogram for signals with significant noise.
Excel Usage
=ENG_WELCH(x, fs, window, nperseg, noverlap, nfft, spectral_detrend, return_onesided, spectral_scaling, avg_method)
x(list[list], required): Time series of measurement values (Excel range).fs(float, optional, default: 1): Sampling frequency of the x time series.window(str, optional, default: “hann”): Desired window to use.nperseg(int, optional, default: null): Length of each segment.noverlap(int, optional, default: null): Number of points to overlap between segments.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “constant”): Specifies how to detrend each segment.return_onesided(bool, optional, default: true): If True, return a one-sided spectrum for real data.spectral_scaling(str, optional, default: “density”): Selects between ‘density’ and ‘spectrum’.avg_method(str, optional, default: “mean”): Method to use when averaging periodograms.
Returns (list[list]): A 2D array where the first row is frequencies and the second row is the power spectral density.
Example 1: Welch default (Hann window)
Inputs:
| x | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 |
Excel formula:
=ENG_WELCH({1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1})
Expected output:
| Result | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.0526316 | 0.105263 | 0.157895 | 0.210526 | 0.263158 | 0.315789 | 0.368421 | 0.421053 | 0.473684 |
| 0.37173 | 11.0677 | 27.5414 | 4.97818 | 0.0016883 | 0.323246 | 0.522246 | 0.0457904 | 0.00507076 | 0.185125 |
Example 2: Welch with median averaging
Inputs:
| x | avg_method | nperseg | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | median | 4 |
Excel formula:
=ENG_WELCH({0,1,0,-1,0,1,0,-1,0,1}, "median", 4)
Expected output:
| Result | ||
|---|---|---|
| 0 | 0.25 | 0.5 |
| 0 | 1.6 | 0 |
Example 3: Welch with spectrum scaling
Inputs:
| x | spectral_scaling | nperseg | noverlap | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | spectrum | 4 | 2 |
Excel formula:
=ENG_WELCH({1,2,1,2,1,2,1,2}, "spectrum", 4, 2)
Expected output:
| Result | ||
|---|---|---|
| 0 | 0.25 | 0.5 |
| 0 | 0.125 | 0.25 |
Example 4: Welch with scalar-compatible input
Inputs:
| x |
|---|
| 4 |
Excel formula:
=ENG_WELCH(4)
Expected output:
| Result |
|---|
| 0 |
| 0 |
Python Code
Show Code
import numpy as np
from scipy.signal import welch as scipy_welch
def eng_welch(x, fs=1, window='hann', nperseg=None, noverlap=None, nfft=None, spectral_detrend='constant', return_onesided=True, spectral_scaling='density', avg_method='mean'):
"""
Estimate power spectral density using Welch's method.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.welch.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values (Excel range).
fs (float, optional): Sampling frequency of the x time series. Default is 1.
window (str, optional): Desired window to use. Default is 'hann'.
nperseg (int, optional): Length of each segment. Default is None.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'constant'.
return_onesided (bool, optional): If True, return a one-sided spectrum for real data. Default is True.
spectral_scaling (str, optional): Selects between 'density' and 'spectrum'. Valid options: Density, Spectrum. Default is 'density'.
avg_method (str, optional): Method to use when averaging periodograms. Valid options: Mean, Median. Default is 'mean'.
Returns:
list[list]: A 2D array where the first row is frequencies and the second row is the power spectral density.
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
detrend = spectral_detrend
if detrend == "False":
detrend = False
f, pxx = scipy_welch(
x_arr,
fs=float(fs),
window=window,
nperseg=int(nperseg) if nperseg is not None else None,
noverlap=int(noverlap) if noverlap is not None else None,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend,
return_onesided=bool(return_onesided),
scaling=spectral_scaling,
average=avg_method
)
return [f.tolist(), pxx.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
ISTFT
The Inverse Short-Time Fourier Transform (ISTFT) reconstructs a time-domain signal from its STFT representation.
Faithful reconstruction requires that the STFT parameters (window, overlap, etc.) match those used in the forward transform and that the Constant OverLap Add (COLA) constraint is satisfied.
Excel Usage
=ISTFT(zxx_grid, fs, window, nperseg, noverlap, input_onesided, boundary)
zxx_grid(list[list], required): The STFT grid as returned by the stft function (Excel range).fs(float, optional, default: 1): Sampling frequency.window(str, optional, default: “hann”): Desired window to use.nperseg(int, optional, default: null): Number of data points per segment.noverlap(int, optional, default: null): Number of points to overlap between segments.input_onesided(bool, optional, default: true): If True, interpret input as one-sided.boundary(bool, optional, default: true): If True, input signal was extended at boundaries.
Returns (list[list]): A 2D array where the first row is segment times and the second row is the reconstructed time-domain signal.
Example 1: STFT/ISTFT roundtrip
Inputs:
| zxx_grid | fs | ||
|---|---|---|---|
| 0 | 0.5 | 1 | |
| 0 (Re) | 1 | 1 | |
| 0 (Im) | 0 | 0 |
Excel formula:
=ISTFT({"",0,0.5;"0 (Re)",1,1;"0 (Im)",0,0}, 1)
Expected output:
| Result |
|---|
| 0 |
| 0.5 |
Example 2: ISTFT with two frequency bins
Inputs:
| zxx_grid | fs | ||
|---|---|---|---|
| 0 | 0.5 | 2 | |
| 0 (Re) | 1 | 1 | |
| 0 (Im) | 0 | 0 | |
| 0.5 (Re) | 0 | 0 | |
| 0.5 (Im) | 0 | 0 |
Excel formula:
=ISTFT({"",0,0.5;"0 (Re)",1,1;"0 (Im)",0,0;"0.5 (Re)",0,0;"0.5 (Im)",0,0}, 2)
Expected output:
| Result |
|---|
| 0 |
| 0.5 |
Example 3: ISTFT with explicit segment and overlap
Inputs:
| zxx_grid | fs | nperseg | noverlap | ||
|---|---|---|---|---|---|
| 0 | 1 | 2 | 4 | 2 | |
| 0 (Re) | 1 | 0 | |||
| 0 (Im) | 0 | 0 | |||
| 0.5 (Re) | 0.5 | 0.5 | |||
| 0.5 (Im) | 0 | 0 |
Excel formula:
=ISTFT({"",0,1;"0 (Re)",1,0;"0 (Im)",0,0;"0.5 (Re)",0.5,0.5;"0.5 (Im)",0,0}, 2, 4, 2)
Expected output:
| Result | |
|---|---|
| 0 | 0.5 |
| 0 | 0.5 |
Example 4: ISTFT without boundary extension
Inputs:
| zxx_grid | fs | boundary | ||
|---|---|---|---|---|
| 0 | 0.5 | 1 | false | |
| 0 (Re) | 0.5 | 0.5 | ||
| 0 (Im) | 0 | 0 |
Excel formula:
=ISTFT({"",0,0.5;"0 (Re)",0.5,0.5;"0 (Im)",0,0}, 1, FALSE)
Expected output:
| Result | ||
|---|---|---|
| 0 | 1 | 2 |
| 0 | 0.25 | 0.25 |
Python Code
Show Code
import numpy as np
from scipy.signal import istft as scipy_istft
def istft(zxx_grid, fs=1, window='hann', nperseg=None, noverlap=None, input_onesided=True, boundary=True):
"""
Perform the Inverse Short-Time Fourier Transform (ISTFT).
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.istft.html
This example function is provided as-is without any representation of accuracy.
Args:
zxx_grid (list[list]): The STFT grid as returned by the stft function (Excel range).
fs (float, optional): Sampling frequency. Default is 1.
window (str, optional): Desired window to use. Default is 'hann'.
nperseg (int, optional): Number of data points per segment. Default is None.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
input_onesided (bool, optional): If True, interpret input as one-sided. Default is True.
boundary (bool, optional): If True, input signal was extended at boundaries. Default is True.
Returns:
list[list]: A 2D array where the first row is segment times and the second row is the reconstructed time-domain signal.
"""
try:
if not isinstance(zxx_grid, list) or not all(isinstance(row, list) for row in zxx_grid):
return "Error: zxx_grid must be a 2D list"
if len(zxx_grid) < 3:
return "Error: zxx_grid must include header and at least one complex row pair"
if (len(zxx_grid) - 1) % 2 != 0:
return "Error: zxx_grid must contain pairs of real and imaginary rows"
row_length = len(zxx_grid[0])
if row_length < 2:
return "Error: zxx_grid must include at least one time column"
if any(len(row) != row_length for row in zxx_grid):
return "Error: zxx_grid rows must all have the same length"
zxx_rows = []
for i in range(1, len(zxx_grid), 2):
re_row = [float(x) for x in zxx_grid[i][1:]]
im_row = [float(x) for x in zxx_grid[i+1][1:]]
complex_row = [complex(r, im) for r, im in zip(re_row, im_row)]
zxx_rows.append(complex_row)
zxx_arr = np.array(zxx_rows)
# Infer a reasonable nperseg from the given STFT matrix if not explicitly provided.
# For a one-sided (default) STFT, the number of frequency bins is nperseg//2 + 1.
# For a two-sided STFT, the number of frequency bins equals nperseg.
if nperseg is None:
bins = zxx_arr.shape[0]
if bool(input_onesided):
nperseg_val = max(2, 2 * (bins - 1))
else:
nperseg_val = max(1, bins)
else:
nperseg_val = int(nperseg)
noverlap_val = None
if noverlap is not None:
noverlap_val = int(noverlap)
if noverlap_val >= nperseg_val:
return "Error: noverlap must be less than nperseg"
# Ensure the STFT matrix has the expected number of frequency bins for the chosen nperseg.
expected_bins = (nperseg_val // 2 + 1) if bool(input_onesided) else nperseg_val
if zxx_arr.shape[0] < expected_bins:
pad_rows = expected_bins - zxx_arr.shape[0]
zxx_arr = np.vstack([zxx_arr, np.zeros((pad_rows, zxx_arr.shape[1]), dtype=complex)])
elif zxx_arr.shape[0] > expected_bins:
return "Error: zxx_grid has more frequency bins than expected for the given nperseg"
t, x = scipy_istft(
zxx_arr,
fs=float(fs),
window=window,
nperseg=nperseg_val,
noverlap=noverlap_val,
input_onesided=bool(input_onesided),
boundary=bool(boundary),
)
t_list = list(t)
x_list = list(x)
max_len = max(len(t_list), len(x_list))
t_list += [""] * (max_len - len(t_list))
x_list += [""] * (max_len - len(x_list))
return [t_list, x_list]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
LOMBSCARGLE
The Lomb-Scargle periodogram estimates spectral power for data sampled at uneven time intervals. It computes a least-squares fit of sinusoidal components across a set of angular frequencies, making it useful when standard FFT assumptions of uniform sampling are not met.
For observations (x_i, y_i) and angular frequency \omega, the method estimates power by fitting sinusoidal terms and evaluating the fit quality over the supplied frequency grid.
Excel Usage
=LOMBSCARGLE(x, y, freqs, precenter, normalize)
x(list[list], required): Sample times (Excel range).y(list[list], required): Observed signal values (Excel range).freqs(list[list], required): Angular frequency grid (radians per unit time) (Excel range).precenter(bool, optional, default: false): If True, subtract the mean of y before computing the periodogram.normalize(bool, optional, default: false): If True, normalize periodogram values by the residual variance.
Returns (list[list]): A 2D array where the first row is angular frequencies and the second row is Lomb-Scargle power values.
Example 1: Unevenly sampled signal periodogram
Inputs:
| x | y | freqs | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.8 | 1.9 | 3.1 | 4.7 | 6 | 0 | 0.7 | 1 | 0.2 | -0.8 | -0.3 | 0.5 | 1 | 1.5 | 2 |
Excel formula:
=LOMBSCARGLE({0,0.8,1.9,3.1,4.7,6}, {0,0.7,1,0.2,-0.8,-0.3}, {0.5,1,1.5,2})
Expected output:
| Result | |||
|---|---|---|---|
| 0.5 | 1 | 1.5 | 2 |
| 0.662122 | 1.1068 | 0.156344 | 0.0138262 |
Example 2: Periodogram with precentering
Inputs:
| x | y | freqs | precenter | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1.3 | 2 | 3.8 | 5.2 | 1.2 | 1.4 | 0.2 | -0.6 | -0.3 | 0.4 | 0.9 | 1.4 | true |
Excel formula:
=LOMBSCARGLE({0,1.3,2,3.8,5.2}, {1.2,1.4,0.2,-0.6,-0.3}, {0.4,0.9,1.4}, TRUE)
Expected output:
| Result | ||
|---|---|---|
| 0.4 | 0.9 | 1.4 |
| 1.24138 | 1.44547 | 0.278972 |
Example 3: Periodogram with normalization
Inputs:
| x | y | freqs | normalize | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 4 | 7 | 0.2 | 0.9 | 0.1 | -0.5 | -0.1 | 0.3 | 0.7 | 1.1 | true |
Excel formula:
=LOMBSCARGLE({0,1,2,4,7}, {0.2,0.9,0.1,-0.5,-0.1}, {0.3,0.7,1.1}, TRUE)
Expected output:
| Result | ||
|---|---|---|
| 0.3 | 0.7 | 1.1 |
| 0.403186 | 0.748432 | 0.589561 |
Example 4: Single angular frequency input
Inputs:
| x | y | freqs | ||||||
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 1 | 0.5 | -0.2 | -0.8 | 1.2 |
Excel formula:
=LOMBSCARGLE({0,1,2,3}, {1,0.5,-0.2,-0.8}, 1.2)
Expected output:
| Result |
|---|
| 1.2 |
| 0.924347 |
Python Code
Show Code
import numpy as np
from scipy.signal import lombscargle as scipy_lombscargle
def lombscargle(x, y, freqs, precenter=False, normalize=False):
"""
Estimate a Lomb-Scargle periodogram for unevenly sampled data.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.lombscargle.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Sample times (Excel range).
y (list[list]): Observed signal values (Excel range).
freqs (list[list]): Angular frequency grid (radians per unit time) (Excel range).
precenter (bool, optional): If True, subtract the mean of y before computing the periodogram. Default is False.
normalize (bool, optional): If True, normalize periodogram values by the residual variance. Default is False.
Returns:
list[list]: A 2D array where the first row is angular frequencies and the second row is Lomb-Scargle power values.
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
y_arr = to_1d(y)
freqs_arr = to_1d(freqs)
if x_arr.size != y_arr.size:
return "Error: x and y must contain the same number of elements"
if freqs_arr.size == 0:
return "Error: freqs must contain at least one value"
pgram = scipy_lombscargle(
x_arr,
y_arr,
freqs_arr,
precenter=bool(precenter),
normalize=bool(normalize)
)
return [freqs_arr.tolist(), pgram.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
RFFT
The real FFT computes the discrete Fourier transform (DFT) of a real-valued signal and returns only the nonnegative-frequency terms. This reduces redundant output compared with the full complex FFT because negative-frequency components are implied by conjugate symmetry.
For a real sequence x_n of length N, the transform is:
X_k = \sum_{n=0}^{N-1} x_n e^{-i 2\pi kn/N}, \quad k = 0, \dots, \lfloor N/2 \rfloor
Excel Usage
=RFFT(a, n, axis, norm)
a(list[list], required): Real-valued signal samples (Excel range).n(int, optional, default: null): Length of the transformed axis of the output.axis(int, optional, default: -1): Axis over which to compute the transform.norm(str, optional, default: null): Normalization mode.
Returns (list[list]): A 2D array where the first row is the real part and the second row is the imaginary part of the one-sided FFT output.
Example 1: One-sided FFT of simple real signal
Inputs:
| a | |||
|---|---|---|---|
| 0 | 1 | 0 | -1 |
Excel formula:
=RFFT({0,1,0,-1})
Expected output:
| Result | ||
|---|---|---|
| 0 | 0 | 0 |
| 0 | -2 | 0 |
Example 2: One-sided FFT with explicit transform length
Inputs:
| a | n | ||
|---|---|---|---|
| 1 | 2 | 3 | 8 |
Excel formula:
=RFFT({1,2,3}, 8)
Expected output:
| Result | ||||
|---|---|---|---|---|
| 6 | 2.41421 | -2 | -0.414214 | 2 |
| 0 | -4.41421 | -2 | 1.58579 | 0 |
Example 3: One-sided FFT with orthonormal scaling
Inputs:
| a | norm | |||
|---|---|---|---|---|
| 2 | 0 | -2 | 0 | ortho |
Excel formula:
=RFFT({2,0,-2,0}, "ortho")
Expected output:
| Result | ||
|---|---|---|
| 0 | 2 | 0 |
| 0 | 0 | 0 |
Example 4: One-sided FFT for single scalar input
Inputs:
| a |
|---|
| 5 |
Excel formula:
=RFFT(5)
Expected output:
| Result |
|---|
| 5 |
| 0 |
Python Code
Show Code
import numpy as np
from numpy.fft import rfft as numpy_rfft
def rfft(a, n=None, axis=-1, norm=None):
"""
Compute the one-dimensional discrete Fourier transform for real input.
See: https://numpy.org/doc/stable/reference/generated/numpy.fft.rfft.html
This example function is provided as-is without any representation of accuracy.
Args:
a (list[list]): Real-valued signal samples (Excel range).
n (int, optional): Length of the transformed axis of the output. Default is None.
axis (int, optional): Axis over which to compute the transform. Default is -1.
norm (str, optional): Normalization mode. Valid options: Backward, Ortho, Forward. Default is None.
Returns:
list[list]: A 2D array where the first row is the real part and the second row is the imaginary part of the one-sided FFT output.
"""
try:
def to_ndarray(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([[float(x) for x in row] for row in v], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
a_arr = to_ndarray(a)
n_val = int(n) if n is not None else None
axis_val = int(axis)
norm_val = norm if norm is not None and str(norm) != "" else None
result = numpy_rfft(a_arr, n=n_val, axis=axis_val, norm=norm_val)
flat_result = np.ravel(result)
return [flat_result.real.tolist(), flat_result.imag.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
RFFTFREQ
This function returns the discrete frequency-bin centers corresponding to the output of a one-sided real FFT. It provides the nonnegative frequency axis used to interpret amplitudes from real-input transforms.
For transform length n and sample spacing d, the bins are:
f_k = \frac{k}{d n}, \quad k = 0, 1, \dots, \left\lfloor\frac{n}{2}\right\rfloor
Excel Usage
=RFFTFREQ(n, d)
n(int, required): Window length.d(float, optional, default: 1): Sample spacing (inverse of sampling rate).
Returns (list[list]): A single-row 2D array of nonnegative sample frequencies.
Example 1: Frequency bins for even length
Inputs:
| n |
|---|
| 8 |
Excel formula:
=RFFTFREQ(8)
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 0.125 | 0.25 | 0.375 | 0.5 |
Example 2: Frequency bins for odd length
Inputs:
| n |
|---|
| 7 |
Excel formula:
=RFFTFREQ(7)
Expected output:
| Result | |||
|---|---|---|---|
| 0 | 0.142857 | 0.285714 | 0.428571 |
Example 3: Frequency bins with custom sample spacing
Inputs:
| n | d |
|---|---|
| 8 | 0.1 |
Excel formula:
=RFFTFREQ(8, 0.1)
Expected output:
| Result | ||||
|---|---|---|---|---|
| 0 | 1.25 | 2.5 | 3.75 | 5 |
Example 4: Frequency bins for longer transform
Inputs:
| n | d |
|---|---|
| 16 | 0.5 |
Excel formula:
=RFFTFREQ(16, 0.5)
Expected output:
| Result | ||||||||
|---|---|---|---|---|---|---|---|---|
| 0 | 0.125 | 0.25 | 0.375 | 0.5 | 0.625 | 0.75 | 0.875 | 1 |
Python Code
Show Code
from numpy.fft import rfftfreq as numpy_rfftfreq
def rfftfreq(n, d=1):
"""
Return sample frequencies for one-sided real FFT bins.
See: https://numpy.org/doc/stable/reference/generated/numpy.fft.rfftfreq.html
This example function is provided as-is without any representation of accuracy.
Args:
n (int): Window length.
d (float, optional): Sample spacing (inverse of sampling rate). Default is 1.
Returns:
list[list]: A single-row 2D array of nonnegative sample frequencies.
"""
try:
n_val = int(n)
d_val = float(d)
if n_val <= 0:
return "Error: n must be a positive integer"
if d_val <= 0:
return "Error: d must be positive"
freqs = numpy_rfftfreq(n_val, d=d_val)
return [freqs.tolist()]
except Exception as e:
return f"Error: {str(e)}"Online Calculator
SPECTROGRAM
A spectrogram is a visual representation of the spectrum of frequencies of a signal as it varies with time. When applied to an audio signal, spectrograms are sometimes called sonographs, voiceprints, or waterfalls.
The spectrogram is computed by taking the squared magnitude of the Short-Time Fourier Transform (STFT) of the signal. It provides a time-frequency distribution of the signal’s energy.
Excel Usage
=SPECTROGRAM(x, fs, window, nperseg, noverlap, nfft, spectral_detrend, return_onesided, spectral_scaling, spectrogram_mode)
x(list[list], required): Time series of measurement values.fs(float, optional, default: 1): Sampling frequency.window(str, optional, default: “tukey”): Desired window to use.nperseg(int, optional, default: null): Length of each segment.noverlap(int, optional, default: null): Number of points to overlap between segments.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “constant”): Specifies how to detrend each segment.return_onesided(bool, optional, default: true): If True, return a one-sided spectrum for real data.spectral_scaling(str, optional, default: “density”): Selects between power spectral density (‘density’) and power spectrum (‘spectrum’).spectrogram_mode(str, optional, default: “psd”): Defines what kind of return values are expected.
Returns (list[list]): A 2D array representing the spectrogram grid.
Example 1: Basic Spectrogram
Inputs:
| x | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 |
Excel formula:
=SPECTROGRAM({1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1})
Expected output:
| Result | |
|---|---|
| 9.5 | |
| 0 | 0.582152 |
| 0.0526316 | 4.91559 |
| 0.105263 | 31.2987 |
| 0.157895 | 0.354778 |
| 0.210526 | 0.598176 |
| 0.263158 | 0.841238 |
| 0.315789 | 0.268336 |
| 0.368421 | 0.0406904 |
| 0.421053 | 0.0463173 |
| 0.473684 | 0.20166 |
Example 2: Spectrogram in magnitude mode
Inputs:
| x | spectrogram_mode | nperseg | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | 0 | 1 | magnitude | 4 |
Excel formula:
=SPECTROGRAM({0,1,0,-1,0,1,0,-1,0,1}, "magnitude", 4)
Expected output:
| Result | ||
|---|---|---|
| 2 | 6 | |
| 0 | 0 | 0 |
| 0.25 | 1.1547 | 1.1547 |
| 0.5 | 0 | 0 |
Example 3: Spectrogram in phase mode
Inputs:
| x | spectrogram_mode | nperseg | noverlap | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | phase | 4 | 2 |
Excel formula:
=SPECTROGRAM({1,2,1,2,1,2,1,2}, "phase", 4, 2)
Expected output:
| Result | |||
|---|---|---|---|
| 2 | 4 | 6 | |
| 0 | 0 | 0 | 0 |
| 0.25 | 0 | 0 | 0 |
| 0.5 | 3.14159 | 3.14159 | 3.14159 |
Example 4: Spectrogram with scalar-compatible input
Inputs:
| x |
|---|
| 2 |
Excel formula:
=SPECTROGRAM(2)
Expected output:
| Result | |
|---|---|
| 0.5 | |
| 0 | 0 |
Python Code
Show Code
import numpy as np
from scipy.signal import spectrogram as scipy_spectrogram
def spectrogram(x, fs=1, window='tukey', nperseg=None, noverlap=None, nfft=None, spectral_detrend='constant', return_onesided=True, spectral_scaling='density', spectrogram_mode='psd'):
"""
Compute a spectrogram with consecutive Fourier transforms.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.spectrogram.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values.
fs (float, optional): Sampling frequency. Default is 1.
window (str, optional): Desired window to use. Default is 'tukey'.
nperseg (int, optional): Length of each segment. Default is None.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'constant'.
return_onesided (bool, optional): If True, return a one-sided spectrum for real data. Default is True.
spectral_scaling (str, optional): Selects between power spectral density ('density') and power spectrum ('spectrum'). Valid options: Density, Spectrum. Default is 'density'.
spectrogram_mode (str, optional): Defines what kind of return values are expected. Valid options: PSD, Magnitude, Angle, Phase. Default is 'psd'.
Returns:
list[list]: A 2D array representing the spectrogram grid.
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
detrend = spectral_detrend
if detrend == "False":
detrend = False
win = window
if win == "tukey":
win = ('tukey', 0.25)
f, t, sxx = scipy_spectrogram(
x_arr,
fs=float(fs),
window=win,
nperseg=int(nperseg) if nperseg is not None else None,
noverlap=int(noverlap) if noverlap is not None else None,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend,
return_onesided=bool(return_onesided),
scaling=spectral_scaling,
mode=spectrogram_mode
)
output = []
header = [""] + t.tolist()
output.append(header)
for i, freq in enumerate(f):
row = [float(freq)] + sxx[i, :].tolist()
output.append(row)
return output
except Exception as e:
return f"Error: {str(e)}"Online Calculator
STFT
The Short-Time Fourier Transform (STFT) is used to quantify the change of a nonstationary signal’s frequency and phase content over time.
It is computed by dividing a longer time signal into shorter segments of equal length and then computing the Fourier transform separately on each shorter segment.
Excel Usage
=STFT(x, fs, window, nperseg, noverlap, nfft, spectral_detrend, return_onesided, boundary, padded)
x(list[list], required): Time series of measurement values.fs(float, optional, default: 1): Sampling frequency.window(str, optional, default: “hann”): Desired window to use.nperseg(int, optional, default: 256): Length of each segment.noverlap(int, optional, default: null): Number of points to overlap between segments.nfft(int, optional, default: null): Length of the FFT used.spectral_detrend(str, optional, default: “False”): Specifies how to detrend each segment.return_onesided(bool, optional, default: true): If True, return a one-sided spectrum.boundary(str, optional, default: “zeros”): Specifies whether the input signal is extended at both ends.padded(bool, optional, default: true): If True, zero-pad signal to fit segments.
Returns (list[list]): A 2D array representing the STFT grid (interleaved real and imaginary).
Example 1: Basic STFT
Inputs:
| x | ||||||||
|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 4 | 3 | 2 | 1 |
Excel formula:
=STFT({1,2,3,4,5,4,3,2,1})
Expected output:
| Result | |||
|---|---|---|---|
| 0 | 5 | 10 | |
| 0.0 (Re) | 1.64381 | 3.21239 | 0.143807 |
| 0.0 (Im) | 0 | 0 | 0 |
| 0.1111111111111111 (Re) | -0.694229 | -1.86154 | 0.0557706 |
| 0.1111111111111111 (Im) | 0.95196 | -0.828119 | -0.123841 |
| 0.2222222222222222 (Re) | -0.0772516 | 0.154503 | -0.0772516 |
| 0.2222222222222222 (Im) | -0.317934 | 0.400537 | -0.0826035 |
| 0.3333333333333333 (Re) | -0.0719035 | 0.143807 | -0.0719035 |
| 0.3333333333333333 (Im) | -0.018854 | -0.0156369 | 0.034491 |
| 0.4444444444444444 (Re) | 0.0214811 | -0.0429621 | 0.0214811 |
| 0.4444444444444444 (Im) | 0.0291447 | -0.0703818 | 0.0412371 |
Example 2: STFT with constant detrending
Inputs:
| x | spectral_detrend | nperseg | |||||||
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | -1 | 0 | 1 | 0 | -1 | constant | 4 |
Excel formula:
=STFT({0,1,0,-1,0,1,0,-1}, "constant", 4)
Expected output:
| Result | |||||
|---|---|---|---|---|---|
| 0 | 2 | 4 | 6 | 8 | |
| 0.0 (Re) | 0 | 0 | 0 | 0 | 0 |
| 0.0 (Im) | 0 | 0 | 0 | 0 | 0 |
| 0.25 (Re) | 0.125 | 0 | 0 | 0 | -0.125 |
| 0.25 (Im) | 0.25 | -0.5 | 0.5 | -0.5 | 0.25 |
| 0.5 (Re) | -0.25 | 0 | 0 | 0 | 0.25 |
| 0.5 (Im) | 0 | 0 | 0 | 0 | 0 |
Example 3: STFT without boundary extension and padding
Inputs:
| x | boundary | padded | nperseg | noverlap | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | None | false | 4 | 2 |
Excel formula:
=STFT({1,2,1,2,1,2,1,2}, "None", FALSE, 4, 2)
Expected output:
| Result | |||
|---|---|---|---|
| 2 | 4 | 6 | |
| 0.0 (Re) | 1.5 | 1.5 | 1.5 |
| 0.0 (Im) | 0 | 0 | 0 |
| 0.25 (Re) | -0.5 | -0.5 | -0.5 |
| 0.25 (Im) | 0 | 0 | 0 |
| 0.5 (Re) | -0.5 | -0.5 | -0.5 |
| 0.5 (Im) | 0 | 0 | 0 |
Example 4: STFT with scalar-compatible input
Inputs:
| x |
|---|
| 3 |
Excel formula:
=STFT(3)
Expected output:
| Result | |
|---|---|
| 0 | |
| 0.0 (Re) | 3 |
| 0.0 (Im) | 0 |
Python Code
Show Code
import numpy as np
from scipy.signal import stft as scipy_stft
def stft(x, fs=1, window='hann', nperseg=256, noverlap=None, nfft=None, spectral_detrend='False', return_onesided=True, boundary='zeros', padded=True):
"""
Compute the Short Time Fourier Transform (STFT).
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): Time series of measurement values.
fs (float, optional): Sampling frequency. Default is 1.
window (str, optional): Desired window to use. Default is 'hann'.
nperseg (int, optional): Length of each segment. Default is 256.
noverlap (int, optional): Number of points to overlap between segments. Default is None.
nfft (int, optional): Length of the FFT used. Default is None.
spectral_detrend (str, optional): Specifies how to detrend each segment. Valid options: Constant, Linear, None. Default is 'False'.
return_onesided (bool, optional): If True, return a one-sided spectrum. Default is True.
boundary (str, optional): Specifies whether the input signal is extended at both ends. Valid options: Zeros, Even, Odd, Constant, None. Default is 'zeros'.
padded (bool, optional): If True, zero-pad signal to fit segments. Default is True.
Returns:
list[list]: A 2D array representing the STFT grid (interleaved real and imaginary).
"""
try:
def to_1d(v):
if isinstance(v, list):
if all(isinstance(row, list) for row in v):
return np.array([float(x) for row in v for x in row], dtype=float)
return np.array([float(x) for x in v], dtype=float)
return np.array([float(v)], dtype=float)
x_arr = to_1d(x)
detrend = spectral_detrend
if detrend == "False":
detrend = False
bound = boundary
if bound == "None":
bound = None
f, t, zxx = scipy_stft(
x_arr,
fs=float(fs),
window=window,
nperseg=int(nperseg),
noverlap=int(noverlap) if noverlap is not None else None,
nfft=int(nfft) if nfft is not None else None,
detrend=detrend,
return_onesided=bool(return_onesided),
boundary=bound,
padded=bool(padded)
)
output = []
header = [""] + t.tolist()
output.append(header)
for i, freq in enumerate(f):
row_real = [f"{freq} (Re)"] + zxx[i, :].real.tolist()
row_imag = [f"{freq} (Im)"] + zxx[i, :].imag.tolist()
output.append(row_real)
output.append(row_imag)
return output
except Exception as e:
return f"Error: {str(e)}"Online Calculator