PhysioAnalysis provides a comprehensive set of spectral analysis
tools for physiological signal data stored in
PhysioExperiment objects. This vignette covers three core
spectral analysis workflows:
We begin by constructing a synthetic PhysioExperiment
object with a known frequency composition so that we can verify our
spectral analyses.
set.seed(42)
sr <- 256 # sampling rate in Hz
duration <- 4 # seconds
n_time <- sr * duration
t <- seq(0, duration - 1/sr, by = 1/sr)
# Simulate a 4-channel signal with known frequency components:
# Channel 1: 10 Hz sine (alpha)
# Channel 2: 10 Hz + 25 Hz sine (alpha + beta)
# Channel 3: White noise
# Channel 4: 10 Hz sine + noise
signal <- matrix(0, nrow = n_time, ncol = 4)
signal[, 1] <- sin(2 * pi * 10 * t)
signal[, 2] <- sin(2 * pi * 10 * t) + 0.5 * sin(2 * pi * 25 * t)
signal[, 3] <- rnorm(n_time)
signal[, 4] <- sin(2 * pi * 10 * t) + 0.3 * rnorm(n_time)
pe <- PhysioExperiment(
assays = list(raw = signal),
colData = S4Vectors::DataFrame(
label = c("Ch1_alpha", "Ch2_alpha_beta", "Ch3_noise", "Ch4_alpha_noise")
),
samplingRate = sr
)The fftSignals() function computes the discrete Fourier
transform along the time axis of the default assay and stores the
magnitude spectrum in a new assay named "fft".
pe_fft <- fftSignals(pe)
# The FFT result is stored as a new assay
assayNames(pe_fft)
# Access the magnitude spectrum
fft_data <- SummarizedExperiment::assay(pe_fft, "fft")
dim(fft_data) # time x channels (frequency bins x channels)The magnitude spectrum returned by fftSignals() has the
same dimensions as the input data. The first half of the rows
corresponds to frequencies from 0 Hz to the Nyquist frequency (sampling
rate / 2).
The plotPSD() function provides a convenient way to
compute and visualize the power spectral density for one or more
channels.
The bandPower() function extracts power within
predefined or custom frequency bands. This is useful for quantifying
activity in standard EEG bands (delta, theta, alpha, beta, gamma).
The spectrogram() function computes a time-frequency
representation of the signal using the Short-Time Fourier Transform
(STFT). This is useful for analyzing how the frequency content of a
signal changes over time.
# Compute spectrogram for channel 1
spec <- spectrogram(pe, window_size = 128, overlap = 0.75, channel = 1)
# The result contains:
# - power: frequency x time power matrix
# - frequencies: frequency vector (Hz)
# - times: time vector (seconds)
str(spec)
# Visualize the spectrogram
plotSpectrogram(spec, freq_range = c(1, 50))The choice of window size and overlap affects the trade-off between time and frequency resolution:
# Higher frequency resolution (larger window)
spec_high_freq <- spectrogram(pe, window_size = 512, overlap = 0.75, channel = 1)
plotSpectrogram(spec_high_freq, freq_range = c(1, 50))
# Higher time resolution (smaller window)
spec_high_time <- spectrogram(pe, window_size = 64, overlap = 0.75, channel = 1)
plotSpectrogram(spec_high_time, freq_range = c(1, 50))The waveletTransform() function uses Morlet wavelets to
compute a time-frequency representation. Compared to STFT, wavelet
analysis provides better frequency resolution at low frequencies and
better time resolution at high frequencies.
The Hilbert transform computes the analytic signal, which can be used to extract instantaneous amplitude (envelope) and instantaneous phase.
| Function | Purpose | Output |
|---|---|---|
fftSignals() |
Magnitude spectrum via FFT | New assay |
plotPSD() |
Power spectral density visualization | ggplot |
bandPower() |
Power in frequency bands | List |
spectrogram() |
STFT time-frequency analysis | List |
waveletTransform() |
Wavelet time-frequency analysis | List |
hilbertTransform() |
Analytic signal via Hilbert transform | New assay |
plotSpectrogram() |
Spectrogram visualization | ggplot |