--- title: "Spectral Analysis with PhysioAnalysis" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Spectral Analysis with PhysioAnalysis} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Introduction 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: 1. **Fast Fourier Transform (FFT)** -- computing magnitude spectra 2. **Power Spectral Density (PSD)** -- estimating and visualizing signal power across frequencies 3. **Time-frequency analysis** -- spectrograms and wavelet transforms for non-stationary signals ## Setup ```{r setup, eval=FALSE} library(PhysioCore) library(PhysioAnalysis) ``` ## Creating Example Data We begin by constructing a synthetic `PhysioExperiment` object with a known frequency composition so that we can verify our spectral analyses. ```{r create-data, eval=FALSE} 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 ) ``` ## FFT Analysis 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"`. ```{r fft, eval=FALSE} 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) ``` ### Interpreting the FFT Output 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). ```{r fft-freq, eval=FALSE} n <- nrow(fft_data) freqs <- seq(0, sr / 2, length.out = floor(n / 2) + 1) # Plot magnitude spectrum for channel 1 (should peak at 10 Hz) plot(freqs, fft_data[1:(floor(n/2) + 1), 1], type = "l", xlab = "Frequency (Hz)", ylab = "Magnitude", main = "FFT Magnitude - Channel 1 (10 Hz)") ``` ## Power Spectral Density The `plotPSD()` function provides a convenient way to compute and visualize the power spectral density for one or more channels. ```{r psd, eval=FALSE} # Plot PSD for all channels with log scale plotPSD(pe, channels = 1:4, log_scale = TRUE) # Plot PSD for a specific frequency range plotPSD(pe, channels = c(1, 2), freq_range = c(1, 50), log_scale = TRUE) # Linear scale PSD plotPSD(pe, channels = 1:2, log_scale = FALSE, freq_range = c(1, 50)) ``` ## Band Power Extraction 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). ```{r band-power, eval=FALSE} # Extract power in standard EEG bands bp <- bandPower(pe, bands = list( delta = c(1, 4), theta = c(4, 8), alpha = c(8, 13), beta = c(13, 30), gamma = c(30, 100) )) # The result contains power values for each band and channel bp ``` ## Spectrogram (Short-Time Fourier Transform) 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. ```{r spectrogram, eval=FALSE} # 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)) ``` ### Window Parameters The choice of window size and overlap affects the trade-off between time and frequency resolution: - **Larger windows** provide better frequency resolution but poorer time resolution. - **Higher overlap** provides smoother temporal estimates at the cost of increased computation. - Common window functions include Hanning (default), Hamming, and Blackman. ```{r spectrogram-params, eval=FALSE} # 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)) ``` ## Wavelet Transform 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. ```{r wavelet, eval=FALSE} # Compute wavelet transform for channel 1 wt <- waveletTransform(pe, frequencies = seq(1, 50, by = 0.5), channel = 1) # The result contains the wavelet power at each frequency and time point str(wt) ``` ## Hilbert Transform and Instantaneous Measures The Hilbert transform computes the analytic signal, which can be used to extract instantaneous amplitude (envelope) and instantaneous phase. ```{r hilbert, eval=FALSE} # Compute the analytic signal pe_hilbert <- hilbertTransform(pe) # Extract instantaneous amplitude (envelope) pe_amp <- instantaneousAmplitude(pe_hilbert) # Extract instantaneous phase pe_phase <- instantaneousPhase(pe_hilbert) ``` ## Summary | 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 | ## References - Oppenheim, A.V. & Willsky, A.S. (1997). *Signals and Systems*. 2nd ed. Prentice Hall. - Wickham, H. (2016). *ggplot2: Elegant Graphics for Data Analysis*. Springer-Verlag New York. ## Session Info ```{r session-info, eval=FALSE} sessionInfo() ```