| Title: | Sparse Time Series Decomposition Using Matching Pursuit and Orthogonal Matching Pursuit |
|---|---|
| Description: | Provides tools for analysing and decomposing time series data using the Matching Pursuit (MP) algorithm, a greedy signal decomposition technique that represents complex signals as a linear combination of simpler functions (called atoms) selected from a redundant dictionary. Support for the Orthogonal Matching Pursuit (OMP) variant of the classical MP algorithm is also provided. For more details see Mallat and Zhang (1993) <doi:10.1109/78.258082>, Pati et al. (1993) <doi:10.1109/ACSSC.1993.342465>, Elad (2010) <doi:10.1007/978-1-4419-7011-4> and Różański (2024) <doi:10.1145/3674832>. |
| Authors: | Artur Gramacki [aut, cre] (ORCID: <https://orcid.org/0000-0002-1610-9743>), Jarosław Gramacki [ctb] (ORCID: <https://orcid.org/0000-0001-5032-1353>), Piotr T. Różański [ctb] (ORCID: <https://orcid.org/0000-0002-0457-6731>, provided technical guidance on the operation of the EMPI software) |
| Maintainer: | Artur Gramacki <[email protected]> |
| License: | GPL-3 |
| Version: | 1.4.0 |
| Built: | 2026-11-01 03:24:03 UTC |
| Source: | https://github.com/artur-gramacki/matchingpursuit |
sig objectCreates an object of class sig from signal data already available
in R. The function provides a convenient way to prepare signals
for subsequent processing and decomposition without importing them from
a file.
as_sig(signal, sampling_frequency)as_sig(signal, sampling_frequency)
signal |
A numeric vector, matrix, or data frame containing the signal values. For multi-channel signals, individual channels are assumed to be stored in columns. |
sampling_frequency |
A single positive numeric value specifying the sampling frequency of the signal in Hz. |
The time vector is generated automatically from the number of signal
samples and the specified sampling frequency. The resulting object has
the same basic structure as objects returned by
read_csv_signals().
An object of class sig, which is a list containing:
signal: A data frame containing the signal values.
sampling_frequency: The sampling frequency in Hz.
time: A numeric vector containing the time coordinates
of the signal samples in seconds, starting at 0.
read_csv_signals,
read_edf_signals,
read_wfdb_signals
# Single-channel signal x <- rnorm(1000) sig <- as_sig(x, sampling_frequency = 100) str(sig) # Multi-channel signal x <- cbind( channel1 = rnorm(1000), channel2 = rnorm(1000) ) sig <- as_sig(x, sampling_frequency = 100) str(sig)# Single-channel signal x <- rnorm(1000) sig <- as_sig(x, sampling_frequency = 100) str(sig) # Multi-channel signal x <- cbind( channel1 = rnorm(1000), channel2 = rnorm(1000) ) sig <- as_sig(x, sampling_frequency = 100) str(sig)
Deletes all files in the MatchingPursuit cache directory.
clear_cache()clear_cache()
Logical scalar. Returns TRUE if all files were successfully removed,
and FALSE otherwise. The return value is invisible.
if (interactive()) { clear_cache() }if (interactive()) { clear_cache() }
Designs notch, low-pass, high-pass, band-pass, and band-stop Butterworth filters for a specified sampling frequency.
design_filters( sampling_frequency = 256, notch = NULL, notch_order = 2, lowpass = NULL, lowpass_order = 4, highpass = NULL, highpass_order = 4, bandpass = NULL, bandpass_order = 4, bandstop = NULL, bandstop_order = 4 )design_filters( sampling_frequency = 256, notch = NULL, notch_order = 2, lowpass = NULL, lowpass_order = 4, highpass = NULL, highpass_order = 4, bandpass = NULL, bandpass_order = 4, bandstop = NULL, bandstop_order = 4 )
sampling_frequency |
Sampling frequency in Hz. |
notch |
Numeric vector of length two specifying the lower and upper
cutoff frequencies of the notch filter in Hz.
|
notch_order |
Positive integer specifying the notch filter order. |
lowpass |
Numeric value specifying the low-pass cutoff frequency in Hz.
|
lowpass_order |
Positive integer specifying the low-pass filter order. |
highpass |
Numeric value specifying the high-pass cutoff frequency in Hz.
|
highpass_order |
Positive integer specifying the high-pass filter order. |
bandpass |
Numeric vector of length two specifying the lower and upper
cutoff frequencies of the band-pass filter in Hz.
|
bandpass_order |
Positive integer specifying the band-pass filter order. |
bandstop |
Numeric vector of length two specifying the lower and upper
cutoff frequencies of the band-stop filter in Hz.
|
bandstop_order |
Positive integer specifying the band-stop filter order. |
A list containing the designed Butterworth filter objects
(or NULL for omitted filters):
Notch filter used to remove a specific narrow frequency band.
Low-pass filter that attenuates high-frequency components.
High-pass filter that attenuates low-frequency components.
Band-pass filter that retains frequencies within a selected range.
Band-stop filter that removes frequencies within a selected range.
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out <- read_edf_signals(file, resampling = FALSE) signal <- out$signal sampling_frequency <- out$sampling_frequency fc <- design_filters( sampling_frequency = sampling_frequency, notch = c(49, 51), lowpass = 40, highpass = 1, bandpass = c(0.5, 40), bandstop = c(10, 50) ) print(fc) signal::freqz(fc$notch, Fs = sampling_frequency) signal::freqz(fc$lowpass, Fs = sampling_frequency) signal::freqz(fc$highpass, Fs = sampling_frequency) signal::freqz(fc$bandpass, Fs = sampling_frequency) signal::freqz(fc$bandstop, Fs = sampling_frequency) plot(signal[, 1], type = "l", panel.first = grid()) signal_filt <- signal for (m in 1:ncol(signal)) { signal_filt[, m] <- signal::filtfilt(fc$notch, signal_filt[, m]); # 50Hz notch filter signal_filt[, m] <- signal::filtfilt(fc$lowpass, signal_filt[, m]); # Low pass IIR Butterworth signal_filt[, m] <- signal::filtfilt(fc$highpass, signal_filt[, m]); # High pass IIR Butterwoth } plot(signal_filt[, 1], type = "l", panel.first = grid())file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out <- read_edf_signals(file, resampling = FALSE) signal <- out$signal sampling_frequency <- out$sampling_frequency fc <- design_filters( sampling_frequency = sampling_frequency, notch = c(49, 51), lowpass = 40, highpass = 1, bandpass = c(0.5, 40), bandstop = c(10, 50) ) print(fc) signal::freqz(fc$notch, Fs = sampling_frequency) signal::freqz(fc$lowpass, Fs = sampling_frequency) signal::freqz(fc$highpass, Fs = sampling_frequency) signal::freqz(fc$bandpass, Fs = sampling_frequency) signal::freqz(fc$bandstop, Fs = sampling_frequency) plot(signal[, 1], type = "l", panel.first = grid()) signal_filt <- signal for (m in 1:ncol(signal)) { signal_filt[, m] <- signal::filtfilt(fc$notch, signal_filt[, m]); # 50Hz notch filter signal_filt[, m] <- signal::filtfilt(fc$lowpass, signal_filt[, m]); # Low pass IIR Butterworth signal_filt[, m] <- signal::filtfilt(fc$highpass, signal_filt[, m]); # High pass IIR Butterwoth } plot(signal_filt[, 1], type = "l", panel.first = grid())
Methods for printing, summarizing, and plotting objects of class
"edf", together with a print method for objects returned by
summary().
## S3 method for class 'edf' plot( x, begin = NULL, end = NULL, panel_height = NULL, rainbow = FALSE, bg_colour = "white", txt_col = "black", zero_line = TRUE, main = NULL, ... ) ## S3 method for class 'edf' print(x, ...) ## S3 method for class 'edf' summary(object, ...) ## S3 method for class 'summary.edf' print(x, ...)## S3 method for class 'edf' plot( x, begin = NULL, end = NULL, panel_height = NULL, rainbow = FALSE, bg_colour = "white", txt_col = "black", zero_line = TRUE, main = NULL, ... ) ## S3 method for class 'edf' print(x, ...) ## S3 method for class 'edf' summary(object, ...) ## S3 method for class 'summary.edf' print(x, ...)
x |
An object of class |
begin |
Time point (in seconds) at which to start plotting.
If |
end |
Time point (in seconds) at which to stop plotting.
If |
panel_height |
Controls the vertical spacing between individual signals.
If |
rainbow |
Logical. If |
bg_colour |
Background colour. |
txt_col |
Colour of text elements. |
zero_line |
Logical. If |
main |
Plot title. If |
... |
Additional arguments. Currently ignored. |
object |
An object of class |
Objects of class "edf" represent multi-channel signals imported
from EDF files, together with sampling information, channel names,
a time vector, and the source record name.
print.edf() and print.summary.edf() return their input
object invisibly.
summary.edf() returns an object of class "summary.edf"
containing record information, signal dimensions, sampling information,
channel names, and basic descriptive statistics for each channel.
plot.edf() is called for its side effect and returns no value.
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") x <- read_edf_signals(file, resampling = FALSE) print(x) summary(x) plot( x, begin = 0, end = 10, panel_height = NULL, rainbow = TRUE, bg_colour = "black", txt_col = "white", zero_line = TRUE, main = "EEG signals stored in the EEG.edf file" ) plot( x, begin = 0, end = 10, panel_height = NULL, rainbow = FALSE, bg_colour = "white", txt_col = "black", zero_line = TRUE, main = "EEG signals stored in the EEG.edf file" )file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") x <- read_edf_signals(file, resampling = FALSE) print(x) summary(x) plot( x, begin = 0, end = 10, panel_height = NULL, rainbow = TRUE, bg_colour = "black", txt_col = "white", zero_line = TRUE, main = "EEG signals stored in the EEG.edf file" ) plot( x, begin = 0, end = 10, panel_height = NULL, rainbow = FALSE, bg_colour = "white", txt_col = "black", zero_line = TRUE, main = "EEG signals stored in the EEG.edf file" )
An EEG montage refers to the arrangement of EEG electrodes and the way their signals are displayed relative to one another during electroencephalogram interpretation. The same EEG recording may appear very different depending on the montage used. This function implements the three montage methods most commonly used in practice: 1) Bipolar Montage, 2) Referential (Monopolar) Montage, and 3) Average Reference Montage.
eeg_montage( x, montage_type = c("average", "reference", "bipolar"), ref_channel = NULL, bipolar_pairs = NULL )eeg_montage( x, montage_type = c("average", "reference", "bipolar"), ref_channel = NULL, bipolar_pairs = NULL )
x |
Object of class |
montage_type |
A character string specifying the montage type.
|
ref_channel |
Name of the reference channel for |
bipolar_pairs |
List of electrodes pairs for |
To check the channel names in the analysed EEG recording,
use the read_edf_params() function.
An object of class edf, which is a list with fields:
signal |
Data frame containing all signal channels. |
sampling_frequency |
Sampling frequency. |
time |
Time stamps. |
signal_names |
Names of the signal channels. |
record_name |
Name of the EDF file. |
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out <- read_edf_signals(file, resampling = FALSE, from = 0, to = 10) read_edf_params(file) # The classical double banana montage. pairs <- list( c("Fp2", "F4"), c("F4", "C4"), c("C4", "P4"), c("P4", "O2"), c("Fp1", "F3"), c("F3", "C3"), c("C3", "P3"), c("P3", "O1"), c("Fp2", "F8"), c("F8", "T4"), c("T4", "T6"), c("T6", "O2"), c("Fp1", "F7"), c("F7", "T3"), c("T3", "T5"), c("T5", "O1"), c("Fz", "Cz"), c("Cz", "Pz") ) signal_bip_mont <- eeg_montage(out, montage_type = "bipolar", bipolar_pairs = pairs) signal_ref_mont <- eeg_montage(out, montage_type = "reference", ref_channel = "O1") signal_avg_mont <- eeg_montage(out, montage_type = "average") head(signal_bip_mont$signal) head(signal_ref_mont$signal) head(signal_avg_mont$signal)file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out <- read_edf_signals(file, resampling = FALSE, from = 0, to = 10) read_edf_params(file) # The classical double banana montage. pairs <- list( c("Fp2", "F4"), c("F4", "C4"), c("C4", "P4"), c("P4", "O2"), c("Fp1", "F3"), c("F3", "C3"), c("C3", "P3"), c("P3", "O1"), c("Fp2", "F8"), c("F8", "T4"), c("T4", "T6"), c("T6", "O2"), c("Fp1", "F7"), c("F7", "T3"), c("T3", "T5"), c("T5", "O1"), c("Fz", "Cz"), c("Cz", "Pz") ) signal_bip_mont <- eeg_montage(out, montage_type = "bipolar", bipolar_pairs = pairs) signal_ref_mont <- eeg_montage(out, montage_type = "reference", ref_channel = "O1") signal_avg_mont <- eeg_montage(out, montage_type = "average") head(signal_bip_mont$signal) head(signal_ref_mont$signal) head(signal_avg_mont$signal)
The EMPI program is installed using the empi_install() function and stored in the
cache directory. This function checks whether the EMPI program is still available there
(users have full access to the cache directory and may remove its contents at any time).
empi_check()empi_check()
A character string containing the full path to the EMPI executable if found.
If EMPI is not available, invisibly returns NULL and displays a
message suggesting installation with empi_install().
empi_install,
empi_locate,
empi_execute,
plot.mp
if (interactive()) { empi_check() }if (interactive()) { empi_check() }
Runs the EMPI program for the given data (signal).
empi_execute( signal, empi_options = NULL, write_to_file = FALSE, path = NULL, file_name = NULL, ... )empi_execute( signal, empi_options = NULL, write_to_file = FALSE, path = NULL, file_name = NULL, ... )
signal |
An object of class |
empi_options |
If |
write_to_file |
If |
path |
Directory in which the SQLite database file will be saved.
If |
file_name |
Name of the file to create if |
... |
Additional arguments passed to |
The EMPI program (source code and binary files for multiple operating systems) can be downloaded from https://github.com/develancer/empi. Details are presented in the journal paper: Różański, P. T. (2024). empi: GPU-Accelerated Matching Pursuit with Continuous Dictionaries. ACM Transactions on Mathematical Software, Volume 50, Issue 3, Article No. 17, pp. 1-17, doi:10.1145/3674832.
Results of signal decomposition using the MP algorithm. An object of class
mp is returned. If write_to_file = TRUE, the results are also written
to a SQLite file in the path directory.
atoms |
A data frame describing the selected atoms. |
signal |
Matrix containing the original signal(s). |
reconstruction |
Matrix containing the reconstructed signal(s). |
selected_atoms |
List of matrices containing selected atoms for each channel. |
time |
Time vector corresponding to signal samples. |
sampling_frequency |
Sampling frequency. |
empi_check,
empi_install,
empi_locate,
plot.mp
if (interactive()) { file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") signal <- read_csv_signals(file) out_empi <- empi_execute( signal = signal ) # Suppress standard output and standard error out_empi <- empi_execute( signal = signal, ignore.stdout = TRUE, ignore.stderr = TRUE ) # The default EMPI options have been modified; see the EMPI README.md for details. # The '--full-atoms-in-signal' option restricts the decomposition to atoms # fully contained within the analyzed signal. # The decomposition results are saved to a SQLite database file. out_empi <- empi_execute( signal = signal, empi_options = "-o local --full-atoms-in-signal -i 50 --gabor", write_to_file = TRUE, path = NULL, file_name = "my_decomposition.db" ) plot(out_empi, freq_divide = 4) }if (interactive()) { file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") signal <- read_csv_signals(file) out_empi <- empi_execute( signal = signal ) # Suppress standard output and standard error out_empi <- empi_execute( signal = signal, ignore.stdout = TRUE, ignore.stderr = TRUE ) # The default EMPI options have been modified; see the EMPI README.md for details. # The '--full-atoms-in-signal' option restricts the decomposition to atoms # fully contained within the analyzed signal. # The decomposition results are saved to a SQLite database file. out_empi <- empi_execute( signal = signal, empi_options = "-o local --full-atoms-in-signal -i 50 --gabor", write_to_file = TRUE, path = NULL, file_name = "my_decomposition.db" ) plot(out_empi, freq_divide = 4) }
Downloads the Enhanced Matching Pursuit Implementation (EMPI) external program compatible with the current operating system and stores it in the package cache directory.
empi_install()empi_install()
The function detects the operating system (Windows, Linux, macOS arm64), downloads the appropriate archive from the official repository, verifies its integrity using a checksum, and extracts it.
The function downloads the EMPI program in a version compatible with the operating system used (Windows, Linux, MacOS-x64, MacOS-arm64) and stores it in the package cache directory.
empi_check,
empi_locate,
empi_execute,
plot.mp
if (interactive()) { empi_install() }if (interactive()) { empi_install() }
Returns Enhanced Matching Pursuit Implementation binary locations for the following operating systems: Windows, Linux, macOS-arm64.
empi_locate()empi_locate()
A list containing:
url: URL of the EMPI binary archive,
fname: archive file name.
empi_check,
empi_install,
empi_execute,
plot.mp
sys <- Sys.info()[["sysname"]] mach <- Sys.info()[["machine"]] if (sys %in% c("Windows", "Linux") || (sys == "Darwin" && mach == "arm64")) { empi_locate() }sys <- Sys.info()[["sysname"]] mach <- Sys.info()[["machine"]] if (sys %in% c("Windows", "Linux") || (sys == "Darwin" && mach == "arm64")) { empi_locate() }
Generates a real-valued Gabor atom consisting of a sinusoidal component localized by a Gaussian envelope. Gabor atoms provide simultaneous localization in time and frequency and are commonly used in time-frequency dictionaries for Matching Pursuit decomposition.
gabor_atom( number_of_samples, sampling_frequency, mean, phase, sigma, frequency, normalization = TRUE )gabor_atom( number_of_samples, sampling_frequency, mean, phase, sigma, frequency, normalization = TRUE )
number_of_samples |
Positive integer specifying the number of samples in the generated Gabor atom. |
sampling_frequency |
Sampling frequency in Hz. |
mean |
Time position of the center of the Gaussian envelope, in seconds. |
phase |
Phase of the sinusoidal component, in radians. |
sigma |
Positive scale parameter controlling the width of the Gaussian envelope, in seconds. |
frequency |
Frequency of the sinusoidal component in Hz. |
normalization |
Logical; if |
A list containing four numeric vectors of length number_of_samples:
cosine |
Cosine wave. |
gauss |
Gaussian envelope. |
gabor |
Gabor function. |
time |
Time vector corresponding to the signal samples. |
number_of_samples <- 512 sampling_frequency <- 256.0 mean <- 1 phase <- pi sigma <- 0.5 frequency <- 5.0 normalization = TRUE out <- gabor_atom( number_of_samples, sampling_frequency, mean, phase, sigma, frequency, normalization ) # Verify unit-norm normalization sqrt(sum(out$gabor^2)) plot(out$time, out$gabor, type = "l", xlab = "t", ylab = "gabor", panel.first = grid())number_of_samples <- 512 sampling_frequency <- 256.0 mean <- 1 phase <- pi sigma <- 0.5 frequency <- 5.0 normalization = TRUE out <- gabor_atom( number_of_samples, sampling_frequency, mean, phase, sigma, frequency, normalization ) # Verify unit-norm normalization sqrt(sum(out$gabor^2)) plot(out$time, out$gabor, type = "l", xlab = "t", ylab = "gabor", panel.first = grid())
Computes complex projection coefficients between one or more signals and a set of Gabor atoms using FFT-based frequency-domain operations.
gabor_projection_fft(block, signal, sigma_divisor = NULL)gabor_projection_fft(block, signal, sigma_divisor = NULL)
block |
A matrix describing a single Gabor dictionary block, typically
obtained as a subset of the output of |
signal |
A numeric vector, matrix, or data frame containing the signal(s) to be analyzed. For matrices and data frames, each column is treated as a separate signal channel. |
sigma_divisor |
Optional positive numeric value controlling the width
of the Gaussian envelope. The envelope scale is calculated as
|
For each time position defined in block, the corresponding signal
segment is multiplied by a normalized Gaussian envelope and transformed
using the Fast Fourier Transform. Only Fourier coefficients corresponding
to the frequencies specified in the dictionary are retained.
Atom supports may extend beyond the observed signal boundaries. In this case, samples outside the signal are treated as zero. The complete Gaussian envelope is normalized before boundary truncation; the part overlapping the observed signal is not renormalized.
The Gaussian envelope is constructed over the complete atom support and normalized to unit L2 norm before it is applied to the signal. If the atom support extends before the first signal sample or beyond the last signal sample, only the overlapping signal samples contribute to the projection; values outside the observed signal are implicitly treated as zero.
Consequently, the visible part of a boundary-crossing atom is not renormalized. This preserves the normalization of the complete atom independently of its position relative to the signal boundaries.
A list with two matrices:
proj_mod_mtx |
Magnitudes of the complex projection coefficients. Rows correspond to
atoms in |
fft_bin_mtx |
Complex Fourier coefficients corresponding to the Gabor frequencies.
Rows correspond to atoms in |
This function is used internally by mp_core_gabor() and
omp_core_gabor() to evaluate Gabor candidate projections.
It is also exported to support advanced experiments and
methodological testing.
read_gabor_dict,
mp_core_gabor,
omp_core_gabor
signal <- as.matrix(rnorm(256)) sampling_frequency <- 256 duration <- 1 xml_file <- system.file("extdata", "one_block.xml", package = "MatchingPursuit") block <- read_gabor_dict( xml_file = xml_file, full_atoms_in_signal = FALSE, sampling_frequency = sampling_frequency, duration = duration, verbose = TRUE ) out <- gabor_projection_fft(block, signal) pmm <- out$proj_mod_mtx scm <- out$fft_bin_mtx head(scm) head(pmm) # Projection magnitudes are the moduli of the complex coefficients head(Mod(scm))signal <- as.matrix(rnorm(256)) sampling_frequency <- 256 duration <- 1 xml_file <- system.file("extdata", "one_block.xml", package = "MatchingPursuit") block <- read_gabor_dict( xml_file = xml_file, full_atoms_in_signal = FALSE, sampling_frequency = sampling_frequency, duration = duration, verbose = TRUE ) out <- gabor_projection_fft(block, signal) pmm <- out$proj_mod_mtx scm <- out$fft_bin_mtx head(scm) head(pmm) # Projection magnitudes are the moduli of the complex coefficients head(Mod(scm))
Generates an XML dictionary file containing a set of Gabor atoms.
generate_xml_dict(N, file, max_window_length = c("3N", "N-1"))generate_xml_dict(N, file, max_window_length = c("3N", "N-1"))
N |
Integer. Length of the analyzed signal in samples. |
file |
Character string. Path to the XML file that will be created. The output follows the MPTK dictionary XML structure and contains Gabor blocks. |
max_window_length |
Character string specifying the upper limit used
when generating window lengths. |
The generated dictionary contains multiple Gabor blocks with logarithmically
distributed window lengths. The smallest window length is fixed to 17 samples
and the maximum window length is determined by max_window_length.
It can be set to the largest odd integer not exceeding either 3*N
or N-1. The 3*N upper limit is chosen heuristically.
The window lengths are generated on a logarithmic scale and then quantized to obtain a set of practical window sizes. Window lengths are forced to be odd, which provides an exact temporal centre for symmetric Gaussian/Gabor windows. The window shift is estimated as approximately 6 percent of the window length:
The FFT size is selected as the smallest power of two satisfying:
This corresponds to the zero-padding strategy commonly used in MPTK-like Gabor dictionaries.
The dictionary generation procedure is based on the following rules.
The rules were derived from an analysis of XML files generated by the
EMPI program using the --dictionary-output option (see the
read_gabor_dict() function and the corresponding vignette available
on CRAN).
Minimum window length: 17 samples.
Maximum window length: determined by max_window_length.
Number of scales:
Logarithmic spacing of scales:
where
Quantization of window lengths depending on their size.
Enforcement of odd window lengths.
Window shift proportional to window length.
FFT size selected as a power of two.
The function writes an XML dictionary file to file. Invisibly returns a
data frame containing the generated dictionary parameters:
windowLen - Gabor window length in samples,
windowShift - temporal shift between consecutive atoms,
fftSize - FFT size used for the block.
# Generate a dictionary for a 256-sample signal xml_file <- tempfile(fileext = ".xml") # Default setting: maximum window length based on 3*N dict <- generate_xml_dict( N = 256, file = xml_file ) dict # Read the generated Gabor dictionary for a 2-second, # 128-Hz signal (256 samples) atoms_dict <- read_gabor_dict( xml_file, sampling_frequency = 128, duration = 2, full_atoms_in_signal = FALSE, verbose = TRUE ) head(atoms_dict) tail(atoms_dict) # Alternative setting: limit the maximum window length to N-1 dict <- generate_xml_dict( N = 256, file = xml_file, max_window_length = "N-1" ) dict# Generate a dictionary for a 256-sample signal xml_file <- tempfile(fileext = ".xml") # Default setting: maximum window length based on 3*N dict <- generate_xml_dict( N = 256, file = xml_file ) dict # Read the generated Gabor dictionary for a 2-second, # 128-Hz signal (256 samples) atoms_dict <- read_gabor_dict( xml_file, sampling_frequency = 128, duration = 2, full_atoms_in_signal = FALSE, verbose = TRUE ) head(atoms_dict) tail(atoms_dict) # Alternative setting: limit the maximum window length to N-1 dict <- generate_xml_dict( N = 256, file = xml_file, max_window_length = "N-1" ) dict
Materialize a Gabor dictionary with fixed or atom-specific phases
materialize_gabor( atoms_dict, sampling_frequency, duration, sigma_divisor = 3, phases = 0, phase_mode = c("grid", "per_atom") )materialize_gabor( atoms_dict, sampling_frequency, duration, sigma_divisor = 3, phases = 0, phase_mode = c("grid", "per_atom") )
atoms_dict |
Parameter matrix returned by read_gabor_dict(). |
sampling_frequency |
Sampling frequency in Hz. |
duration |
Signal duration in seconds. |
sigma_divisor |
Positive Gaussian-envelope scale divisor; default 3. |
phases |
Numeric vector of phases in radians. In "grid" mode each phase is used for every atom. In "per_atom" mode there must be exactly one phase per dictionary row. |
phase_mode |
Either "grid" (default, original behavior) or "per_atom" (one phase per atom). |
A Gabor atom is treated as degenerate when its cosine-modulated Gaussian
envelope is (numerically) zero before normalization. In particular, some
combinations of frequency, phase, and window length can make the sampled
cosine vanish at every sample. The implementation rejects an atom if its
norm is less than 1e-10 * sqrt(sum(w^2)), where w is the
Gaussian envelope.
A second, distinct case occurs when the atom has no usable samples within the signal interval, for example when its entire support lies outside the interval. Such an atom is rejected by the visible-fragment norm check.
In phase_mode = "grid", invalid atom columns are skipped; in
phase_mode = "per_atom", an error is raised to preserve the
one-to-one correspondence between dictionary rows and output columns.
Dense numeric matrix with one column per materialized atom. In "grid" mode, degenerate columns are removed, as in the original implementation. In "per_atom" mode, a degenerate atom causes an error so that column positions always match rows of atoms_dict.
fs <- 256 duration <- 2 xml_file <- system.file( "extdata", "one_block.xml", package = "MatchingPursuit" ) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = fs, duration = duration, full_atoms_in_signal = TRUE ) D <- materialize_gabor( atoms_dict = atoms_dict, sampling_frequency = fs, duration = duration, phases = 0, phase_mode = "grid" ) # Select four atoms with low frequencies, distributed across the signal target_time <- seq(0.25, 1.75, length.out = 4) target_freq <- c(4, 8, 12, 20) idx <- sapply(seq_along(target_time), function(i) { which.min( abs(atoms_dict[, "time_sec"] - target_time[i]) + abs(atoms_dict[, "freq_hz"] - target_freq[i]) / 10 ) }) matplot( (0:(nrow(D) - 1)) / fs, D[, idx, drop = FALSE], type = "l", lty = 1, xlab = "Time [s]", ylab = "Amplitude", main = "Four Gabor atoms" )fs <- 256 duration <- 2 xml_file <- system.file( "extdata", "one_block.xml", package = "MatchingPursuit" ) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = fs, duration = duration, full_atoms_in_signal = TRUE ) D <- materialize_gabor( atoms_dict = atoms_dict, sampling_frequency = fs, duration = duration, phases = 0, phase_mode = "grid" ) # Select four atoms with low frequencies, distributed across the signal target_time <- seq(0.25, 1.75, length.out = 4) target_freq <- c(4, 8, 12, 20) idx <- sapply(seq_along(target_time), function(i) { which.min( abs(atoms_dict[, "time_sec"] - target_time[i]) + abs(atoms_dict[, "freq_hz"] - target_freq[i]) / 10 ) }) matplot( (0:(nrow(D) - 1)) / fs, D[, idx, drop = FALSE], type = "l", lty = 1, xlab = "Time [s]", ylab = "Amplitude", main = "Four Gabor atoms" )
Computes a sparse representation of a signal using the classical Matching Pursuit (MP) algorithm and a dictionary of atoms.
mp_core( dictionary, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sparse = FALSE, verbose = FALSE )mp_core( dictionary, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sparse = FALSE, verbose = FALSE )
dictionary |
A dictionary of atoms. Can be a numeric vector, matrix, data frame, or an
object derived from class |
signal |
Can be a numeric vector, matrix, or data frame. Signals are assumed to be stored in columns. The signal length (number of rows) must match the atom length. |
channel |
Index of the signal channel to decompose. If |
n_nonzero_coefs |
Maximum number of non-zero coefficients in the sparse representation.
If |
tol |
Stopping tolerance expressed as the maximum allowed relative residual
energy, |
sparse |
Logical; if |
verbose |
Logical; flag indicating whether progress information should be printed. |
This is a native R implementation of the classical MP algorithm supporting
arbitrary matrix-based dictionaries. It provides direct access to the
decomposition procedure and can be used independently of the Gabor-specific
workflow. For high-performance Matching Pursuit decomposition using the
external EMPI backend, see empi_locate(), empi_install(),
empi_check(), and empi_execute().
Dictionary atoms are normalized internally to unit L2 norm. For classical
MP, the reduction in squared residual norm at iteration is therefore
theoretically equal to the squared MP coefficient. The former definition
is used explicitly to maintain a consistent interpretation of
energy across MP and OMP decompositions.
A list containing the result of the Matching Pursuit decomposition with the following elements:
selected_atoms |
Matrix of selected unit-L2-normalized dictionary atoms used in the reconstruction. |
signal |
The analyzed signal channel returned as a numeric vector. |
reconstruction |
The MP approximation of the signal. |
coefs |
Numeric vector of estimated coefficients for selected atoms. |
energy |
Numeric vector containing the reduction in squared residual norm
associated with each pursuit iteration,
|
support |
Integer vector of selected atom indices at every iteration. |
residual |
Final residual vector. |
relative_residual_energy |
Relative residual energy, |
n_iters |
Number of iterations performed by the algorithm. |
omp_core,
read_gabor_dict,
mp_omp_execute
dictionary <- matrix( c( 1.0, 0.9, 0.1, 1.0, -0.2, 0.3, 0.7, -0.5, 1.2, 0.4, 0.2, 1.0, 0.8, -0.3, 1.0, -0.6, 0.5, 0.9, -0.1, 0.8, 0.0, 0.1, 1.0, 0.5, 0.7, 1.1, -0.4, 0.2, 0.6, -0.7, 0.9, -0.2, 0.4, 1.3, 0.1, 0.0, 0.8, -0.9, 0.5, 1.0, -0.3, 0.6, 1.1, -0.4, 0.2, 0.7, -0.8, 1.0, 0.3, 0.9), nrow = 5, byrow = TRUE ) signal <- matrix( c( 4, 3, 5, 2, 2, 1, 2, 3, 3, 2, 4, 1, 5, 4, 3, 2, 1, 3, 2, 4), nrow = 5, byrow = TRUE ) fit <- mp_core( dictionary = dictionary, signal = signal, channel = 1, n_nonzero_coefs = 3, verbose = TRUE ) fit$coefs # [1] 6.274348 2.535423 1.870568 fit$support # [1] 9 5 7 fit$relative_residual_energy # [1] 1.0000000 0.2842283 0.1673489 0.1037303 # More realistic example, see mp_omp_execute() examples.dictionary <- matrix( c( 1.0, 0.9, 0.1, 1.0, -0.2, 0.3, 0.7, -0.5, 1.2, 0.4, 0.2, 1.0, 0.8, -0.3, 1.0, -0.6, 0.5, 0.9, -0.1, 0.8, 0.0, 0.1, 1.0, 0.5, 0.7, 1.1, -0.4, 0.2, 0.6, -0.7, 0.9, -0.2, 0.4, 1.3, 0.1, 0.0, 0.8, -0.9, 0.5, 1.0, -0.3, 0.6, 1.1, -0.4, 0.2, 0.7, -0.8, 1.0, 0.3, 0.9), nrow = 5, byrow = TRUE ) signal <- matrix( c( 4, 3, 5, 2, 2, 1, 2, 3, 3, 2, 4, 1, 5, 4, 3, 2, 1, 3, 2, 4), nrow = 5, byrow = TRUE ) fit <- mp_core( dictionary = dictionary, signal = signal, channel = 1, n_nonzero_coefs = 3, verbose = TRUE ) fit$coefs # [1] 6.274348 2.535423 1.870568 fit$support # [1] 9 5 7 fit$relative_residual_energy # [1] 1.0000000 0.2842283 0.1673489 0.1037303 # More realistic example, see mp_omp_execute() examples.
Performs Matching Pursuit directly on a parameterized Gabor dictionary without materializing the complete dictionary as a time-domain matrix.
mp_core_gabor( atoms_dict, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sigma_divisor = NULL, verbose = FALSE )mp_core_gabor( atoms_dict, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sigma_divisor = NULL, verbose = FALSE )
atoms_dict |
Matrix-like object describing candidate Gabor atoms,
typically returned by |
signal |
An object of class |
channel |
Integer index of the signal channel to analyze. If |
n_nonzero_coefs |
Optional positive integer specifying the maximum
number of selected atoms when |
tol |
Optional stopping tolerance for the relative residual energy.
If specified, it overrides |
sigma_divisor |
Optional positive numeric value controlling the width
of the Gaussian envelope. If |
verbose |
Logical; if |
Candidate projections are evaluated blockwise using
gabor_projection_fft(). For each candidate, the complex FFT coefficient
provides the projections of the current residual onto its cosine and sine
components. Precomputed 2 x 2 Gram matrix terms are then used to determine
analytically the phase that maximizes the normalized projection.
The complete time-domain dictionary is never stored in memory. A full real-valued waveform is constructed only for the atom selected in the current MP iteration. The selected waveform is normalized to unit L2 norm over the part overlapping the observed signal before the classical MP residual update is applied.
Unlike mp_core(), which operates on a fixed matrix dictionary,
mp_core_gabor() optimizes the phase of every Gabor candidate with
respect to the current residual at every MP iteration.
A list containing:
selected_atoms |
Matrix whose columns are the selected unit-L2-normalized time-domain atoms. |
signal |
Analyzed signal channel as a numeric vector. |
reconstruction |
Signal reconstruction after the performed MP iterations. |
coefs |
MP coefficients of the selected atoms. |
energy |
Decrease in residual energy attributable to each MP iteration. |
support |
Row indices of the selected atoms in |
residual |
Final residual signal. |
relative_residual_energy |
Relative residual energy at iteration 0 and after each completed MP iteration. |
n_iters |
Number of completed MP iterations. |
frequency |
Selected atom frequencies in Hz. |
phase |
Optimized selected atom phases in radians. |
scale |
Selected atom scales in seconds. |
position |
Selected atom centre positions in seconds. |
atom_begin |
Selected atom start positions in seconds. |
window_len |
Selected atom window lengths in seconds. |
atom_begin_sample |
Selected atom start positions in samples. |
window_len_samples |
Selected atom window lengths in samples. |
sampling_frequency |
Sampling frequency in Hz. |
sigma_divisor |
Gaussian envelope divisor actually used. |
n_candidates |
Number of candidate atoms in |
read_gabor_dict,
gabor_projection_fft,
omp_core_gabor,
mp_core
signal_file <- system.file( "extdata", "sample1.csv", package = "MatchingPursuit" ) xml_file <- system.file( "extdata", "one_block.xml", package = "MatchingPursuit" ) signal <- read_csv_signals(signal_file, col_names_in_csv = FALSE) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = signal$sampling_frequency, duration = nrow(signal$signal) / signal$sampling_frequency, full_atoms_in_signal = TRUE ) fit <- mp_core_gabor( atoms_dict = atoms_dict, signal = signal, channel = 1, n_nonzero_coefs = 10 )signal_file <- system.file( "extdata", "sample1.csv", package = "MatchingPursuit" ) xml_file <- system.file( "extdata", "one_block.xml", package = "MatchingPursuit" ) signal <- read_csv_signals(signal_file, col_names_in_csv = FALSE) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = signal$sampling_frequency, duration = nrow(signal$signal) / signal$sampling_frequency, full_atoms_in_signal = TRUE ) fit <- mp_core_gabor( atoms_dict = atoms_dict, signal = signal, channel = 1, n_nonzero_coefs = 10 )
Performs sparse signal decomposition using either the Matching Pursuit (MP) or
Orthogonal Matching Pursuit (OMP) algorithm, as specified by the mode
parameter. The decomposition is performed independently for each signal channel
using a parameterized Gabor dictionary without materializing the complete
dictionary as a time-domain matrix.
mp_omp_execute( signal, mode = NULL, dictionary = NULL, full_atoms_in_signal = FALSE, n_nonzero_coefs = NULL, tol = NULL, verbose = FALSE, progress = TRUE )mp_omp_execute( signal, mode = NULL, dictionary = NULL, full_atoms_in_signal = FALSE, n_nonzero_coefs = NULL, tol = NULL, verbose = FALSE, progress = TRUE )
signal |
An object of class |
mode |
|
dictionary |
Character string specifying the path to an XML file
containing the dictionary specification. It can be generated using
|
full_atoms_in_signal |
Logical. If |
n_nonzero_coefs |
Optional positive integer specifying the maximum
number of selected atoms for each signal channel when |
tol |
Optional stopping tolerance for the relative residual energy,
between 0 and 1. If specified, it overrides |
verbose |
Logical; if |
progress |
Logical; if |
The returned object is of class "mp" and can be visualized using
plot() and tf_map().
The XML dictionary specification is first processed by
read_gabor_dict(). For each signal channel, the selected algorithm
iteratively searches the parameterized Gabor dictionary for the atom
best matching the current residual. Candidate projections are evaluated
using FFT-based computations, and the phase of each candidate is optimized
analytically.
In MP mode, mp_core_gabor() updates the residual by subtracting
the contribution of the selected atom at each iteration. In OMP mode,
omp_core_gabor() additionally recomputes the coefficients of all
selected atoms by least squares using an incremental Cholesky factorization.
The complete time-domain dictionary is never stored in memory. Only the
selected Gabor atoms are reconstructed and retained. The decomposition
stops when the specified number of atoms has been selected or, if
tol is provided, when the relative residual energy reaches the
requested tolerance, subject to the algorithm's iteration limit.
The results from all channels are combined into an object of class
"mp", which can be visualized using plot() and
tf_map().
An object of class "mp" containing:
atoms |
A data frame describing the selected atoms. |
signal |
Matrix containing the original signal(s). |
reconstruction |
Matrix containing the reconstructed signal(s). |
selected_atoms |
List of matrices containing selected unit-L2-normalized atoms for each channel. |
time |
Time vector corresponding to signal samples. |
sampling_frequency |
Sampling frequency. |
The atoms data frame contains:
channel_id — signal channel identifier,
atom_number — atom index within the channel,
energy — atom energy contribution,
envelope — envelope type,
frequency — atom frequency (Hz),
phase — atom phase (radians),
scale — atom scale (seconds),
position — atom centre position (seconds).
read_gabor_dict,
generate_xml_dict,
omp_core_gabor,
mp_core_gabor
# +-------------------------------------------------------------+ # | Read signal | # +-------------------------------------------------------------+ file <- system.file( "extdata", "sample3.csv", package = "MatchingPursuit" ) signal <- read_csv_signals( file, col_names_in_csv = TRUE ) # +-------------------------------------------------------------+ # | Run Matching Pursuit (MP-R backend) | # +-------------------------------------------------------------+ fit_mp <- mp_omp_execute( mode = "mp", signal = signal, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_mp, channel = 3) # +-------------------------------------------------------------+ # | Run Orthogonal Matching Pursuit (OMP-R backend) | # +-------------------------------------------------------------+ fit_omp <- mp_omp_execute( mode = "omp", signal = signal, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_omp, channel = 3) # +-------------------------------------------------------------+ # | Stop decomposition using residual energy tolerance | # +-------------------------------------------------------------+ fit_mp_tol <- mp_omp_execute( mode = "mp", signal = signal, tol = 0.1, verbose = TRUE ) plot(fit_mp_tol, channel = 3) # +-------------------------------------------------------------+ # | Restrict Gabor atoms to the signal boundaries | # +-------------------------------------------------------------+ fit_mp_full <- mp_omp_execute( mode = "mp", signal = signal, full_atoms_in_signal = TRUE, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_mp_full, channel = 3) # +-------------------------------------------------------------+ # | Use an external XML dictionary specification | # +-------------------------------------------------------------+ xml_file <- system.file( "extdata", "sample3.xml", package = "MatchingPursuit" ) fit_mp_xml <- mp_omp_execute( mode = "mp", signal = signal, dictionary = xml_file, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_mp_xml, channel = 3)# +-------------------------------------------------------------+ # | Read signal | # +-------------------------------------------------------------+ file <- system.file( "extdata", "sample3.csv", package = "MatchingPursuit" ) signal <- read_csv_signals( file, col_names_in_csv = TRUE ) # +-------------------------------------------------------------+ # | Run Matching Pursuit (MP-R backend) | # +-------------------------------------------------------------+ fit_mp <- mp_omp_execute( mode = "mp", signal = signal, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_mp, channel = 3) # +-------------------------------------------------------------+ # | Run Orthogonal Matching Pursuit (OMP-R backend) | # +-------------------------------------------------------------+ fit_omp <- mp_omp_execute( mode = "omp", signal = signal, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_omp, channel = 3) # +-------------------------------------------------------------+ # | Stop decomposition using residual energy tolerance | # +-------------------------------------------------------------+ fit_mp_tol <- mp_omp_execute( mode = "mp", signal = signal, tol = 0.1, verbose = TRUE ) plot(fit_mp_tol, channel = 3) # +-------------------------------------------------------------+ # | Restrict Gabor atoms to the signal boundaries | # +-------------------------------------------------------------+ fit_mp_full <- mp_omp_execute( mode = "mp", signal = signal, full_atoms_in_signal = TRUE, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_mp_full, channel = 3) # +-------------------------------------------------------------+ # | Use an external XML dictionary specification | # +-------------------------------------------------------------+ xml_file <- system.file( "extdata", "sample3.xml", package = "MatchingPursuit" ) fit_mp_xml <- mp_omp_execute( mode = "mp", signal = signal, dictionary = xml_file, n_nonzero_coefs = 10, verbose = TRUE ) plot(fit_mp_xml, channel = 3)
Converts the output of mp_core_gabor() or omp_core_gabor()
into a standardized object of class "mp".
mp_omp_gabor_to_mp(core, sampling_frequency)mp_omp_gabor_to_mp(core, sampling_frequency)
core |
A list returned by |
sampling_frequency |
Numeric scalar specifying the sampling frequency of the analyzed signal in Hz. |
The function transforms a single-channel Gabor decomposition result
into the object structure used by mp_omp_execute().
The channel identifier in the resulting object is always set to 1.
It preserves the original signal, reconstructed signal, selected atoms,
atom energies, and time-frequency parameters, including frequency,
phase, scale, and position.
The reconstruction is obtained by multiplying the matrix of selected
atoms by their corresponding coefficients.
The resulting object can be used with functions that accept objects
of class "mp", including time-frequency visualization tools
such as tf_map().
This function does not perform signal decomposition. It only converts
an existing decomposition result into the standard "mp" format.
The function is intended exclusively for the Gabor-specific core
implementations. It is not designed for the general-purpose
mp_core() and omp_core() functions.
An object of class "mp" containing:
Data frame containing the channel identifier, atom number, energy, envelope type, frequency, phase, scale, and position of each selected Gabor atom.
Numeric matrix containing the original signal
(samples 1).
Numeric matrix containing the reconstructed
signal (samples 1).
List containing the matrix of selected Gabor atoms for the analyzed channel.
Numeric vector containing the time coordinates of signal samples in seconds.
Sampling frequency in Hz.
mp_core_gabor,
omp_core_gabor,
mp_omp_execute,
tf_map
# Generate a Gabor dictionary sampling_frequency <- 128 duration <- 1 t <- seq(0, duration - 1 / sampling_frequency, by = 1 / sampling_frequency) y <- sin(2 * pi * 20 * t) + 0.5 * sin(2 * pi * 50 * t) sig <- as_sig(y, sampling_frequency) xml_file <- tempfile(fileext = ".xml") generate_xml_dict(length(y), xml_file) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = sampling_frequency, duration = duration ) # MP decomposition fit_mp <- mp_core_gabor( atoms_dict = atoms_dict, signal = sig, channel = 1, n_nonzero_coefs = 20, verbose = FALSE ) out_mp <- mp_omp_gabor_to_mp(fit_mp, sampling_frequency) # OMP decomposition fit_omp <- omp_core_gabor( atoms_dict = atoms_dict, signal = sig, channel = 1, n_nonzero_coefs = 20, verbose = FALSE ) out_omp <- mp_omp_gabor_to_mp(fit_omp, sampling_frequency) # Verify the resulting object class(out_omp) head(out_omp$atoms) # Verify reconstruction consistency max(abs(out_omp$reconstruction[, 1] - fit_omp$reconstruction))# Generate a Gabor dictionary sampling_frequency <- 128 duration <- 1 t <- seq(0, duration - 1 / sampling_frequency, by = 1 / sampling_frequency) y <- sin(2 * pi * 20 * t) + 0.5 * sin(2 * pi * 50 * t) sig <- as_sig(y, sampling_frequency) xml_file <- tempfile(fileext = ".xml") generate_xml_dict(length(y), xml_file) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = sampling_frequency, duration = duration ) # MP decomposition fit_mp <- mp_core_gabor( atoms_dict = atoms_dict, signal = sig, channel = 1, n_nonzero_coefs = 20, verbose = FALSE ) out_mp <- mp_omp_gabor_to_mp(fit_mp, sampling_frequency) # OMP decomposition fit_omp <- omp_core_gabor( atoms_dict = atoms_dict, signal = sig, channel = 1, n_nonzero_coefs = 20, verbose = FALSE ) out_omp <- mp_omp_gabor_to_mp(fit_omp, sampling_frequency) # Verify the resulting object class(out_omp) head(out_omp$atoms) # Verify reconstruction consistency max(abs(out_omp$reconstruction[, 1] - fit_omp$reconstruction))
Methods for printing, summarizing, and plotting objects of class
"mp", together with a print method for objects returned by
summary().
## S3 method for class 'mp' plot( x, channel = 1, mode = "sqrt", freq_divide = NULL, increase_factor = 8, shortening_factor_x = 2, shortening_factor_y = 2, atom_centers = "crosses", display_grid = FALSE, color = "white", palette = "my custom palette", plot_signals = TRUE, verbose = FALSE, ... ) ## S3 method for class 'mp' print(x, ...) ## S3 method for class 'mp' summary(object, ...) ## S3 method for class 'summary.mp' print(x, ...)## S3 method for class 'mp' plot( x, channel = 1, mode = "sqrt", freq_divide = NULL, increase_factor = 8, shortening_factor_x = 2, shortening_factor_y = 2, atom_centers = "crosses", display_grid = FALSE, color = "white", palette = "my custom palette", plot_signals = TRUE, verbose = FALSE, ... ) ## S3 method for class 'mp' print(x, ...) ## S3 method for class 'mp' summary(object, ...) ## S3 method for class 'summary.mp' print(x, ...)
x |
An object of class |
channel |
Channel to process and display. |
mode |
|
freq_divide |
Specifies how many times the displayed frequency range in the T-F map
should be reduced. At high sampling rates, and when a low-pass filter with
a cut-off frequency much lower than the sampling frequency is used, a large part of
the T-F map may contain no blobs. If the sampling frequency is |
increase_factor |
Factor controlling the increase in the number of pixels along the frequency axis. Non-negative integers such as 2, 4, 5, or 8 are typically appropriate. |
shortening_factor_x |
Usually, a value of 2 provides better visualization of atoms. |
shortening_factor_y |
Usually, a value of 2 provides better visualization of atoms. |
atom_centers |
|
display_grid |
Logical. If |
color |
Color of the small crosses and atom numbers. |
palette |
Palette from the list returned by |
plot_signals |
Logical. If |
verbose |
Logical flag indicating whether progress information should be printed. |
... |
Additional arguments. Currently ignored. |
object |
An object of class |
Objects of class "mp" represent the result of a Matching Pursuit
or Orthogonal Matching Pursuit decomposition. They contain the original
signal, its reconstruction, parameters of the selected atoms, individual
selected atom waveforms, the corresponding time vector, and sampling
frequency.
The plotting method displays a time-frequency (T-F) map to visualize
the decomposition. It is a wrapper around tf_map() with
out_mode = "plot".
print.mp() and print.summary.mp() return their input
object invisibly.
summary.mp() returns an object of class "summary.mp"
containing signal dimensions, sampling information, the total number
of selected atoms, the number of selected atoms per channel,
signal, residual, relative residual, and explained energy information.
plot.mp() is called for its side effect and returns no value.
tf_map,
empi_execute,
mp_omp_execute
## Not run: file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") signal <- read_csv_signals(file, col_names = "ch1") # Execute the MP algorithm. out_empi <- empi_execute(signal = signal) # Print and summarize the decomposition. print(out_empi) summary(out_empi) # Plot a time-frequency map based on MP atoms. plot(out_empi) ## End(Not run)## Not run: file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") signal <- read_csv_signals(file, col_names = "ch1") # Execute the MP algorithm. out_empi <- empi_execute(signal = signal) # Print and summarize the decomposition. print(out_empi) summary(out_empi) # Plot a time-frequency map based on MP atoms. plot(out_empi) ## End(Not run)
Performs Orthogonal Matching Pursuit (OMP) to obtain a sparse representation of a signal using a dictionary of candidate atoms.
omp_core( dictionary, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sparse = FALSE, verbose = FALSE )omp_core( dictionary, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sparse = FALSE, verbose = FALSE )
dictionary |
A dictionary of atoms. Can be a numeric vector, matrix, data frame, or an
object derived from class |
signal |
Can be a numeric vector, matrix, or data frame. Signals are assumed to be stored in columns. The signal length (number of rows) must match the atom length. |
channel |
Index of the signal channel to decompose. If |
n_nonzero_coefs |
Maximum number of non-zero coefficients in the sparse representation.
If |
tol |
Optional stopping tolerance for the relative residual energy, defined as
The algorithm stops when this value is less than or equal to
|
sparse |
Logical; if |
verbose |
Logical; flag indicating whether progress information should be printed. |
Unlike classical Matching Pursuit, OMP recomputes the coefficients of all previously selected atoms at each iteration by solving a least-squares problem. This makes the residual orthogonal to the subspace spanned by the selected atoms and generally provides a more accurate approximation for a given number of atoms.
The least-squares problem is solved efficiently using incremental Cholesky factorization.
At each iteration, the atom with the largest absolute correlation with the current residual is selected. All coefficients associated with the selected atoms are then recomputed simultaneously by least squares, and the residual is updated.
For OMP, the quantity stored in energy is not calculated from the
final coefficient of an individual atom. Selected atoms can be strongly
correlated, and therefore quantities such as
coefs^2 * colSums(selected_atoms^2) are not additive contributions
to the energy of the reconstruction.
Instead, the energy associated with the atom selected at iteration
is defined as the reduction in residual energy:
Thus, energy[k] quantifies the reduction in residual energy
associated with the -th OMP iteration, after adding a new atom
and re-estimating all active coefficients.
A list containing the result of the Orthogonal Matching Pursuit decomposition with the following elements:
selected_atoms |
Matrix of selected unit-L2-normalized dictionary atoms used in the reconstruction. |
signal |
The analyzed signal channel returned as a numeric vector. |
reconstruction |
OMP reconstruction of the signal |
coefs |
Final least-squares coefficients corresponding to
|
energy |
Numeric vector containing the reduction in residual energy produced at
each OMP iteration,
|
support |
Indices of the selected atoms in the input dictionary, in selection order. |
residual |
Final residual vector. |
relative_residual_energy |
Relative residual energy after initialization and after each OMP iteration. |
n_iters |
Number of OMP iterations performed. |
mp_core,
omp_core_gabor,
mp_omp_execute
dictionary <- matrix( c( 1.0, 0.9, 0.1, 1.0, -0.2, 0.3, 0.7, -0.5, 1.2, 0.4, 0.2, 1.0, 0.8, -0.3, 1.0, -0.6, 0.5, 0.9, -0.1, 0.8, 0.0, 0.1, 1.0, 0.5, 0.7, 1.1, -0.4, 0.2, 0.6, -0.7, 0.9, -0.2, 0.4, 1.3, 0.1, 0.0, 0.8, -0.9, 0.5, 1.0, -0.3, 0.6, 1.1, -0.4, 0.2, 0.7, -0.8, 1.0, 0.3, 0.9), nrow = 5, byrow = TRUE ) signal <- matrix( c( 4, 3, 5, 2, 2, 1, 2, 3, 3, 2, 4, 1, 5, 4, 3, 2, 1, 3, 2, 4), nrow = 5, byrow = TRUE ) fit <- omp_core( dictionary = dictionary, signal = signal, channel = 1, n_nonzero_coefs = 3, verbose = TRUE ) fit$coefs # [1] 5.282278 2.637693 2.195920 fit$support # [1] 9 5 7 fit$relative_residual_energy # [1] 1.00000000 0.28422833 0.16609350 0.08795047 # For Gabor-specific decomposition, see omp_core_gabor() # and mp_omp_execute().dictionary <- matrix( c( 1.0, 0.9, 0.1, 1.0, -0.2, 0.3, 0.7, -0.5, 1.2, 0.4, 0.2, 1.0, 0.8, -0.3, 1.0, -0.6, 0.5, 0.9, -0.1, 0.8, 0.0, 0.1, 1.0, 0.5, 0.7, 1.1, -0.4, 0.2, 0.6, -0.7, 0.9, -0.2, 0.4, 1.3, 0.1, 0.0, 0.8, -0.9, 0.5, 1.0, -0.3, 0.6, 1.1, -0.4, 0.2, 0.7, -0.8, 1.0, 0.3, 0.9), nrow = 5, byrow = TRUE ) signal <- matrix( c( 4, 3, 5, 2, 2, 1, 2, 3, 3, 2, 4, 1, 5, 4, 3, 2, 1, 3, 2, 4), nrow = 5, byrow = TRUE ) fit <- omp_core( dictionary = dictionary, signal = signal, channel = 1, n_nonzero_coefs = 3, verbose = TRUE ) fit$coefs # [1] 5.282278 2.637693 2.195920 fit$support # [1] 9 5 7 fit$relative_residual_energy # [1] 1.00000000 0.28422833 0.16609350 0.08795047 # For Gabor-specific decomposition, see omp_core_gabor() # and mp_omp_execute().
Performs Orthogonal Matching Pursuit directly on a parameterized Gabor dictionary without materializing the complete dictionary as a time-domain matrix.
omp_core_gabor( atoms_dict, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sigma_divisor = NULL, verbose = FALSE )omp_core_gabor( atoms_dict, signal, channel = NULL, n_nonzero_coefs = NULL, tol = NULL, sigma_divisor = NULL, verbose = FALSE )
atoms_dict |
Matrix-like object describing candidate Gabor atoms,
typically returned by |
signal |
An object of class |
channel |
Integer index of the signal channel to analyze. If |
n_nonzero_coefs |
Optional positive integer specifying the maximum
number of selected atoms when |
tol |
Optional stopping tolerance for the relative residual energy.
If specified, it overrides |
sigma_divisor |
Optional positive numeric value controlling the width
of the Gaussian envelope. If |
verbose |
Logical; if |
Candidate selection uses the same parameterized Gabor search as
mp_core_gabor(). At each OMP iteration, all candidates are evaluated
against the current residual and the phase of the newly selected atom is
optimized analytically.
Once an atom has been selected, its phase remains fixed. The coefficients of all selected atoms are then recomputed jointly by least squares, as in classical OMP. The least-squares problem is updated efficiently using an incremental Cholesky factorization.
The complete Gabor dictionary is never stored as a time-domain matrix. Only the selected unit-L2-normalized atoms are materialized and retained in the active dictionary.
A single row of atoms_dict represents a fixed time position, frequency,
and window length, while phase is optimized continuously. Consequently, the
same row index may in principle be selected more than once with different
phases, provided that the resulting time-domain atoms are linearly
independent. Near-linear dependence is detected through the Cholesky update;
a rejected candidate is skipped and the next-best candidate is tested.
A list containing:
selected_atoms |
Matrix whose columns are the selected unit-L2-normalized time-domain atoms. |
signal |
Analyzed signal channel as a numeric vector. |
reconstruction |
OMP reconstruction of the signal. |
coefs |
Final least-squares coefficients corresponding to
|
energy |
Reduction in residual energy produced at each OMP iteration. |
support |
Row indices of the selected atoms in |
residual |
Final residual signal. |
relative_residual_energy |
Relative residual energy at iteration 0 and after each completed OMP iteration. |
n_iters |
Number of completed OMP iterations. |
frequency |
Selected atom frequencies in Hz. |
phase |
Optimized phases fixed at the time each atom was selected. |
scale |
Selected atom scales in seconds. |
position |
Selected atom centre positions in seconds. |
atom_begin |
Selected atom start positions in seconds. |
window_len |
Selected atom window lengths in seconds. |
atom_begin_sample |
Selected atom start positions in samples. |
window_len_samples |
Selected atom window lengths in samples. |
sampling_frequency |
Sampling frequency in Hz. |
sigma_divisor |
Gaussian envelope divisor actually used. |
n_candidates |
Number of parameter rows in |
mp_core_gabor,
read_gabor_dict,
gabor_projection_fft,
omp_core
signal_file <- system.file( "extdata", "sample1.csv", package = "MatchingPursuit" ) xml_file <- system.file( "extdata", "one_block.xml", package = "MatchingPursuit" ) signal <- read_csv_signals(signal_file, col_names_in_csv = FALSE) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = signal$sampling_frequency, duration = nrow(signal$signal) / signal$sampling_frequency, full_atoms_in_signal = TRUE ) fit <- omp_core_gabor( atoms_dict = atoms_dict, signal = signal, channel = 1, n_nonzero_coefs = 10 )signal_file <- system.file( "extdata", "sample1.csv", package = "MatchingPursuit" ) xml_file <- system.file( "extdata", "one_block.xml", package = "MatchingPursuit" ) signal <- read_csv_signals(signal_file, col_names_in_csv = FALSE) atoms_dict <- read_gabor_dict( xml_file = xml_file, sampling_frequency = signal$sampling_frequency, duration = nrow(signal$signal) / signal$sampling_frequency, full_atoms_in_signal = TRUE ) fit <- omp_core_gabor( atoms_dict = atoms_dict, signal = signal, channel = 1, n_nonzero_coefs = 10 )
A straightforward reference implementation of the Orthogonal Matching Pursuit (OMP) algorithm that closely follows its mathematical formulation. The function is intended for reference and illustrative purposes and does not use computational optimizations. The least-squares problem is solved explicitly using the normal-equation formula.
omp_reference( dictionary, signal, n_nonzero_coefs = NULL, tol = NULL, verbose = FALSE )omp_reference( dictionary, signal, n_nonzero_coefs = NULL, tol = NULL, verbose = FALSE )
dictionary |
A dictionary of atoms. Can be a numeric vector, matrix, or data frame. Atoms are assumed to be stored in columns. Dictionary atoms are internally normalized to unit L2 norm before decomposition. Therefore, atom selection is invariant to arbitrary scaling of dictionary columns. |
signal |
A numeric vector. |
n_nonzero_coefs |
Maximum number of non-zero coefficients in the sparse representation.
If |
tol |
Optional stopping tolerance for the relative residual energy, defined as
The algorithm stops when this value is less than or equal to
|
verbose |
Logical. If |
This implementation is intended for small illustrative examples rather
than large-scale computations. In particular, when verbose = TRUE,
detailed information is printed at every iteration, including residual
and reconstruction vectors. For large signals or a large number of
iterations, this may produce a substantial amount of console output.
This implementation operates on a single signal represented by a numeric
vector. The signal argument must therefore be a numeric vector,
not a matrix containing multiple signals or channels.
Because the least-squares problem is solved explicitly through the normal equations, the implementation may fail for singular or nearly singular selected subdictionaries and is not intended for numerically demanding applications.
Dictionary atoms are internally normalized to unit Euclidean norm before decomposition. The returned coefficients are provided both for the normalized working dictionary and for the original dictionary scaling.
A list containing:
selected_atoms |
Indices of the atoms selected by OMP. |
coefficients_normalized_dict |
Coefficient vector corresponding to the normalized working dictionary. |
coefficients_original_dict |
Coefficient vector corresponding to the original (unnormalized) dictionary. |
reconstruction_normalized_dict |
Signal reconstruction obtained using the normalized working dictionary. |
reconstruction_original_dict |
Signal reconstruction obtained using the original dictionary. |
residual_normalized_dict |
Residual corresponding to the reconstruction based on the normalized working dictionary. |
residual_original_dict |
Residual corresponding to the reconstruction based on the original dictionary. |
normalized_reconstruction_error_normalized_dict |
Normalized reconstruction error (NRE) for the normalized working
dictionary, defined as |
normalized_reconstruction_error_original_dict |
Normalized reconstruction error (NRE) for the original dictionary,
defined as |
orthogonality |
A list containing, for each OMP iteration, the inner products between the current residual and all atoms selected up to that iteration. Values should be numerically close to zero. |
residual_energy |
Residual energy after each OMP iteration,
defined as |
iterations |
Number of OMP iterations performed. |
dictionary <- matrix( c( 1.0, 0.9, 0.1, 1.0, -0.2, 0.3, 0.7, -0.5, 1.2, 0.4, 0.2, 1.0, 0.8, -0.3, 1.0, -0.6, 0.5, 0.9, -0.1, 0.8, 0.0, 0.1, 1.0, 0.5, 0.7, 1.1, -0.4, 0.2, 0.6, -0.7, 0.9, -0.2, 0.4, 1.3, 0.1, 0.0, 0.8, -0.9, 0.5, 1.0, -0.3, 0.6, 1.1, -0.4, 0.2, 0.7, -0.8, 1.0, 0.3, 0.9), nrow = 5, byrow = TRUE ) signal <- c(4, 2, 3, 5, 1) out <- omp_reference( dictionary = dictionary, signal = signal, n_nonzero_coefs = 3, verbose = TRUE ) outdictionary <- matrix( c( 1.0, 0.9, 0.1, 1.0, -0.2, 0.3, 0.7, -0.5, 1.2, 0.4, 0.2, 1.0, 0.8, -0.3, 1.0, -0.6, 0.5, 0.9, -0.1, 0.8, 0.0, 0.1, 1.0, 0.5, 0.7, 1.1, -0.4, 0.2, 0.6, -0.7, 0.9, -0.2, 0.4, 1.3, 0.1, 0.0, 0.8, -0.9, 0.5, 1.0, -0.3, 0.6, 1.1, -0.4, 0.2, 0.7, -0.8, 1.0, 0.3, 0.9), nrow = 5, byrow = TRUE ) signal <- c(4, 2, 3, 5, 1) out <- omp_reference( dictionary = dictionary, signal = signal, n_nonzero_coefs = 3, verbose = TRUE ) out
Reads the atom parameters from a SQLite database produced by empi_execute().
read_atom_params(db_file)read_atom_params(db_file)
db_file |
A character string giving the path to a SQLite database file. |
A data frame containing the atom parameters stored in the database:
channel_id |
Channel identifier. |
atom_number |
Atom number. |
energy |
Energy of the atom. |
frequency |
Frequency of the atom. |
phase |
Phase of the atom. |
scale |
Scaling factor. |
position |
Position of the atom in time. |
# Example database containing data from 18 channels file <- system.file("extdata", "EEG_filter_resample_montage.db", package = "MatchingPursuit") out <- read_atom_params(file) out[which(out$channel_id == 1), ] out[which(out$channel_id == 18), ]# Example database containing data from 18 channels file <- system.file("extdata", "EEG_filter_resample_montage.db", package = "MatchingPursuit") out <- read_atom_params(file) out[which(out$channel_id == 1), ] out[which(out$channel_id == 18), ]
Reads and validates a CSV file structure
read_csv_signals(file, col_names = NULL, col_names_in_csv = FALSE)read_csv_signals(file, col_names = NULL, col_names_in_csv = FALSE)
file |
File to be read and checked. The first line of the file must contain two numbers:
the sampling frequency in Hz ( |
col_names |
Optional character vector of column names. If not specified, default names are created. |
col_names_in_csv |
Logical value. If |
A list containing:
Data frame containing all signals (rows = samples, columns = channels).
Sampling frequency.
Time vector corresponding to signal samples.
file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") # The first line of the file must contain two numbers: # a) the sampling frequency in Hz # b) the signal length in seconds out <- read.csv(file, header = FALSE) head(out) signal <- read_csv_signals(file, col_names = "signal_1") head(signal$signal) signal$sampling_frequency head(signal$time) tail(signal$time) file <- system.file("extdata", "sample2.csv", package = "MatchingPursuit") signal <- read_csv_signals(file, col_names = c("signal_1")) head(signal$signal) signal$sampling_frequency # Now, the csv file contains signal names in the second line file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") signal <- read_csv_signals(file, col_names_in_csv = TRUE) head(signal$signal) signal$sampling_frequencyfile <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") # The first line of the file must contain two numbers: # a) the sampling frequency in Hz # b) the signal length in seconds out <- read.csv(file, header = FALSE) head(out) signal <- read_csv_signals(file, col_names = "signal_1") head(signal$signal) signal$sampling_frequency head(signal$time) tail(signal$time) file <- system.file("extdata", "sample2.csv", package = "MatchingPursuit") signal <- read_csv_signals(file, col_names = c("signal_1")) head(signal$signal) signal$sampling_frequency # Now, the csv file contains signal names in the second line file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") signal <- read_csv_signals(file, col_names_in_csv = TRUE) head(signal$signal) signal$sampling_frequency
Reads a selected EDF or EDF+ file and returns basic signal parameters (channel names, sampling frequency of each channel, number of samples per channel, and signal duration in seconds). Additional information stored in EDF+ files (such as interrupted recordings or time-stamped annotations) is not used by the package and is therefore not read.
read_edf_params(file)read_edf_params(file)
file |
Path to the EDF / EDF+ file to be read. |
A data frame containing the basic parameters of the EDF / EDF+ file:
channel_name |
Channel name. |
frequency |
Channel sampling frequency. |
no_of_samples |
Number of samples in the channel. |
length_sec |
Channel duration, in seconds. |
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") read_edf_params(file)file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") read_edf_params(file)
The function reads a selected EDF or EDF+ file. Optionally, resampling can be performed (upsampling or downsampling).
read_edf_signals( file, resampling = FALSE, sf_new = NULL, from = NULL, to = NULL, verbose = FALSE )read_edf_signals( file, resampling = FALSE, sf_new = NULL, from = NULL, to = NULL, verbose = FALSE )
file |
Path to the EDF / EDF+ file to be read. |
resampling |
If |
sf_new |
Target sampling frequency used for upsampling or downsampling. |
from |
Starting time of the signal to be loaded (in seconds). |
to |
Ending time of the signal to be loaded (in seconds). |
verbose |
Logical flag indicating whether progress information should be printed. |
If resampling = TRUE, signals are resampled according to the target frequency
specified by f.new. Since the EDF standard allows different sampling rates per channel,
some channels may be upsampled while others are downsampled. The function does not support
independent resampling of individual channels.
An object of class edf, which is a list with fields:
signal |
Data frame containing all signal channels. |
sampling_frequency |
Sampling frequency after optional resampling. |
time |
Time stamps after optional resampling. |
signal_names |
Names of the signal channels. |
record_name |
Name of the EDF file. |
# Read EDF signals without resampling file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out1 <- read_edf_signals(file, resampling = FALSE) lapply(out1, class) out1$sampling_frequency # Read EDF signals and resample them to 128 Hz out2 <- read_edf_signals(file, resampling = TRUE, sf_new = 128, verbose = TRUE) lapply(out2, class) out2$sampling_frequency# Read EDF signals without resampling file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out1 <- read_edf_signals(file, resampling = FALSE) lapply(out1, class) out1$sampling_frequency # Read EDF signals and resample them to 128 Hz out2 <- read_edf_signals(file, resampling = TRUE, sf_new = 128, verbose = TRUE) lapply(out2, class) out2$sampling_frequency
Reads data from a SQLite file (.db) created by the Matching Pursuit algorithm.
The reconstructed signal(s) and Gabor function(s) are also returned.
read_empi_db(db_file)read_empi_db(db_file)
db_file |
A character string giving the path to a SQLite database file. |
An object of class "mp" containing:
A data frame describing the selected atoms.
Matrix containing the original signal(s).
Matrix containing the reconstructed signal(s).
List of matrices containing selected atoms for each channel.
Time vector corresponding to signal samples.
Sampling frequency.
file <- system.file("extdata", "EEG_filter_resample_montage.db", package = "MatchingPursuit") out <- read_empi_db(file) n_channels <- ncol(out$signal) signal <- out$signal reconstruction <- out$reconstruction t <- out$time sampling_frequency <- out$sampling_frequency old.par <- par("mfrow", "pty", "mai") par(mfrow = c(2, 1)) par(pty = "m") par(mai = c(0.9, 0.5, 0.3, 0.4)) plot( signal[,1], type = "l", col = "blue", main = paste("channel: ", 1, " / " , n_channels, " (original signal)", sep = ""), xaxt = "n", ylab = "", xlab = "time [sec]" ) len <- length(signal[, 1]) lab <- seq(t[1], t[len] + 1 / sampling_frequency, length.out = 11) axis(side = 1, las = 1, cex.axis = 0.9, at = seq(0, len, length.out = 11), labels = lab) plot( reconstruction[,1], type = "l", col = "blue", main = paste("channel: ", 1, " / " , n_channels, " (reconstructed signal)", sep = ""), xaxt = "n", ylab = "", xlab = "time [sec]" ) axis(side = 1, las = 1, cex.axis = 0.9, at = seq(0, len, length.out = 11), labels = lab) par(old.par)file <- system.file("extdata", "EEG_filter_resample_montage.db", package = "MatchingPursuit") out <- read_empi_db(file) n_channels <- ncol(out$signal) signal <- out$signal reconstruction <- out$reconstruction t <- out$time sampling_frequency <- out$sampling_frequency old.par <- par("mfrow", "pty", "mai") par(mfrow = c(2, 1)) par(pty = "m") par(mai = c(0.9, 0.5, 0.3, 0.4)) plot( signal[,1], type = "l", col = "blue", main = paste("channel: ", 1, " / " , n_channels, " (original signal)", sep = ""), xaxt = "n", ylab = "", xlab = "time [sec]" ) len <- length(signal[, 1]) lab <- seq(t[1], t[len] + 1 / sampling_frequency, length.out = 11) axis(side = 1, las = 1, cex.axis = 0.9, at = seq(0, len, length.out = 11), labels = lab) plot( reconstruction[,1], type = "l", col = "blue", main = paste("channel: ", 1, " / " , n_channels, " (reconstructed signal)", sep = ""), xaxt = "n", ylab = "", xlab = "time [sec]" ) axis(side = 1, las = 1, cex.axis = 0.9, at = seq(0, len, length.out = 11), labels = lab) par(old.par)
The function parses an XML file describing a multiscale Gabor dictionary.
read_gabor_dict( xml_file, sampling_frequency, duration, verbose = FALSE, full_atoms_in_signal = FALSE )read_gabor_dict( xml_file, sampling_frequency, duration, verbose = FALSE, full_atoms_in_signal = FALSE )
xml_file |
Path to the XML file containing the dictionary definition. |
sampling_frequency |
Sampling frequency (in Hz) of the signal associated with the dictionary. |
duration |
Duration of the signal (in seconds) used to determine the number of valid time positions. |
verbose |
Logical; if |
full_atoms_in_signal |
Logical. If |
Each <block> in the XML file defines a time-frequency scale of atoms
using three parameters:
windowLen — length of the analysis window (in samples),
windowShift — step size between consecutive windows,
fftSize — FFT size defining frequency resolution.
The function assumes an XML structure containing param nodes with
name and value attributes. An example XML file is shown below.
For simplicity, the example contains only one block; in practice, dictionary
files usually contain multiple blocks.
<?xml version="1.0" encoding="ISO-8859-1"?> <dict> <block> <param name="windowLen" value="31"/> <param name="windowShift" value="2"/> <param name="fftSize" value="64"/> </block> </dict>
Each block generates a grid of atoms over time and frequency bins, forming a multiresolution Gabor dictionary. Smaller windows provide better time resolution, while larger windows improve frequency resolution.
The treatment of atoms near signal boundaries is controlled by
full_atoms_in_signal.
If TRUE, only atoms fully contained within the signal support are
generated. In this case, atom start positions satisfy
where is the atom start position, is the signal length,
and is the window length. If the signal is shorter than the window
length, no time positions are generated for that block.
If FALSE, atom centres are allowed at positions throughout the
signal, and the support of an atom may extend beyond the signal boundaries.
A matrix where each row describes a Gabor atom with the following columns:
block |
Block identifier from the XML file. |
time_sample |
Start position of the atom support (in samples). |
time_sec |
Start position of the atom support (in seconds). |
freq_bin |
Frequency bin index. |
freq_hz |
Frequency in Hertz. |
window_len |
Window length of the atom support, in samples. |
fft_size |
FFT size used to define the frequency grid. |
The output of read_gabor_dict() is a parameterized description
of the Gabor time-frequency grid. It serves as input to
mp_core_gabor() and omp_core_gabor(), which perform
iterative signal decomposition directly on the parameterized dictionary.
At each iteration, candidate Gabor atoms are evaluated against the current residual using FFT-based projections and analytical phase optimization. Only the selected atoms are reconstructed in the time domain, avoiding materialization of the complete dictionary.
The higher-level mp_omp_execute() function handles dictionary
preparation and multi-channel decomposition internally.
XML dictionary definitions exported by EMPI can be read directly by this
function. Additional XML elements not used by read_gabor_dict() are
ignored. The argument full_atoms_in_signal controls the boundary
convention corresponding to the EMPI --full-atoms-in-signal option.
For full details on the EMPI options and their behavior, see the
EMPI documentation in README.md.
generate_xml_dict,
mp_core_gabor,
omp_core_gabor,
mp_omp_execute
# +-------------------------------------------------------------+ # | Step 1: Read signal | # +-------------------------------------------------------------+ sig_file <- system.file( "extdata", "sample3.csv", package = "MatchingPursuit" ) sample3 <- read_csv_signals( sig_file, col_names_in_csv = TRUE ) sampling_frequency <- sample3$sampling_frequency duration <- nrow(sample3$signal) / sampling_frequency # +-------------------------------------------------------------+ # | Step 2: Read dictionary | # +-------------------------------------------------------------+ xml_file <- system.file( "extdata", "sample3.xml", package = "MatchingPursuit" ) # +-------------------------------------------------------------+ # | Step 3: Compare boundary conventions | # +-------------------------------------------------------------+ # Generate only atoms whose complete support lies within # the signal boundaries. atoms_full <- read_gabor_dict( xml_file = xml_file, sampling_frequency = sampling_frequency, duration = duration, full_atoms_in_signal = TRUE, verbose = TRUE ) # Allow atom support to extend beyond the signal boundaries. # Atom centres still remain within the signal. atoms_overstep <- read_gabor_dict( xml_file = xml_file, sampling_frequency = sampling_frequency, duration = duration, full_atoms_in_signal = FALSE, verbose = TRUE ) # Allowing boundary overstep increases the number of dictionary atoms. nrow(atoms_full) nrow(atoms_overstep) # With full_atoms_in_signal = TRUE, atom start positions # are always non-negative. range(atoms_full[, "time_sample"]) # With full_atoms_in_signal = FALSE, atoms centred near the beginning # of the signal may have negative start positions. range(atoms_overstep[, "time_sample"])# +-------------------------------------------------------------+ # | Step 1: Read signal | # +-------------------------------------------------------------+ sig_file <- system.file( "extdata", "sample3.csv", package = "MatchingPursuit" ) sample3 <- read_csv_signals( sig_file, col_names_in_csv = TRUE ) sampling_frequency <- sample3$sampling_frequency duration <- nrow(sample3$signal) / sampling_frequency # +-------------------------------------------------------------+ # | Step 2: Read dictionary | # +-------------------------------------------------------------+ xml_file <- system.file( "extdata", "sample3.xml", package = "MatchingPursuit" ) # +-------------------------------------------------------------+ # | Step 3: Compare boundary conventions | # +-------------------------------------------------------------+ # Generate only atoms whose complete support lies within # the signal boundaries. atoms_full <- read_gabor_dict( xml_file = xml_file, sampling_frequency = sampling_frequency, duration = duration, full_atoms_in_signal = TRUE, verbose = TRUE ) # Allow atom support to extend beyond the signal boundaries. # Atom centres still remain within the signal. atoms_overstep <- read_gabor_dict( xml_file = xml_file, sampling_frequency = sampling_frequency, duration = duration, full_atoms_in_signal = FALSE, verbose = TRUE ) # Allowing boundary overstep increases the number of dictionary atoms. nrow(atoms_full) nrow(atoms_overstep) # With full_atoms_in_signal = TRUE, atom start positions # are always non-negative. range(atoms_full[, "time_sample"]) # With full_atoms_in_signal = FALSE, atoms centred near the beginning # of the signal may have negative start positions. range(atoms_overstep[, "time_sample"])
WFDB (WaveForm DataBase) is a standard file format for storing, reading, and analyzing physiological time-series signals. It is widely used for signals such as ECG, EEG, blood pressure, respiration, and other biomedical waveforms. It is the file format used by the PhysioNet project and is commonly used in research datasets.
read_wfdb_signals(file)read_wfdb_signals(file)
file |
Path to the WFDB record to be read. |
A WFDB record typically consists of two main files:
.dat - binary signal samples (waveform values), and .hea - a header
file describing how to interpret the data. In some cases, additional annotation
files such as .atr may be present, containing beat labels or rhythm annotations.
An object of class wfdb. The returned value is a list containing:
Matrix of signals stored in the WFDB file.
Sampling frequency.
Time vector corresponding to signal samples.
Names of the WFDB leads (channels).
Name of the file.
The function EGM::read_wfdb() from version 0.2.0 of the
EGM package does not support multi-frequency signals. Consequently,
records containing different numbers of samples per frame, as indicated by
the 16x2, 16x4, and 16x1 specifications below, cannot
be read correctly.
multi_freq_test 3 100 1000
multi_freq_test.dat 16x2 200.0(0)/mV 16 0 0 258 0 ECG
multi_freq_test.dat 16x4 400.0(0)/mmHg 16 0 400 57824 0 ABP
multi_freq_test.dat 16x1 100.0(0)/pm 16 0 0 18204 0 RESP
# ECG data comes from https://physionet.org/content/ptb-xl/1.0.3/ file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") out <- read_wfdb_signals(file) head(out$signal) out$sampling_frequency out$lead_names plot(out, begin = 0, end = 10, panel_height = 1.5)# ECG data comes from https://physionet.org/content/ptb-xl/1.0.3/ file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") out <- read_wfdb_signals(file) head(out$signal) out$sampling_frequency out$lead_names plot(out, begin = 0, end = 10, panel_height = 1.5)
Resamples one or more dimensional numeric signals using
signal::resample().
resample_signal(signal, p, q, d = 5)resample_signal(signal, p, q, d = 5)
signal |
A numeric vector, numeric matrix, or data frame containing only numeric columns. For two-dimensional objects, rows correspond to time samples and columns correspond to signal channels. |
p |
A positive integer specifying the interpolation factor. |
q |
A positive integer specifying the decimation factor. |
d |
A positive integer specifying the filter delay. The default is 5. |
The new sampling frequency is determined by the ratio p/q:
For matrices and data frames, resampling is performed independently for each column. Rows are interpreted as time samples and columns as individual signal channels.
The function uses resample internally. The resampling
process includes interpolation, low-pass filtering, and decimation.
A numeric vector, matrix, or data frame containing the resampled signal. The output type matches the input type. Column names are preserved for matrices and data frames.
# Numeric vector signal <- sin(2 * pi * 5 * seq(0, 1, length.out = 400)) signal_resampled <- resample_signal(signal, p = 1, q = 4) old.par <- par("mfrow", "mai") par(mfrow = c(2, 1)) par(mai = c(0.9, 0.5, 0.3, 0.4)) plot(signal, type = "o") plot(signal_resampled, type = "o") par(old.par) # Numeric matrix: samples in rows, channels in columns (256Hz, 10sec., 5 channels) signal <- matrix(rnorm(2560 * 5), nrow = 2560, ncol = 5) colnames(signal) <- paste0("channel_", seq_len(ncol(signal))) # Resample to 64Hz signal_64 <- resample_signal(signal, p = 1, q = 4) dim(signal_64) # Data frame signal_df <- as.data.frame(signal) signal_df_64 <- resample_signal(signal_df, p = 1, q = 4) names(signal_df_64)# Numeric vector signal <- sin(2 * pi * 5 * seq(0, 1, length.out = 400)) signal_resampled <- resample_signal(signal, p = 1, q = 4) old.par <- par("mfrow", "mai") par(mfrow = c(2, 1)) par(mai = c(0.9, 0.5, 0.3, 0.4)) plot(signal, type = "o") plot(signal_resampled, type = "o") par(old.par) # Numeric matrix: samples in rows, channels in columns (256Hz, 10sec., 5 channels) signal <- matrix(rnorm(2560 * 5), nrow = 2560, ncol = 5) colnames(signal) <- paste0("channel_", seq_len(ncol(signal))) # Resample to 64Hz signal_64 <- resample_signal(signal, p = 1, q = 4) dim(signal_64) # Data frame signal_df <- as.data.frame(signal) signal_df_64 <- resample_signal(signal_df, p = 1, q = 4) names(signal_df_64)
Methods for printing, summarizing, and plotting objects of class
"sig", together with a print method for objects returned by
summary().
## S3 method for class 'sig' print(x, ...) ## S3 method for class 'sig' summary(object, ...) ## S3 method for class 'summary.sig' print(x, ...) ## S3 method for class 'sig' plot( x, begin = NULL, end = NULL, panel_height = NULL, zero_line = TRUE, main = NULL, mar = c(4, 7, 2, 1), col = "black", lwd = 1, lty = 1, ... )## S3 method for class 'sig' print(x, ...) ## S3 method for class 'sig' summary(object, ...) ## S3 method for class 'summary.sig' print(x, ...) ## S3 method for class 'sig' plot( x, begin = NULL, end = NULL, panel_height = NULL, zero_line = TRUE, main = NULL, mar = c(4, 7, 2, 1), col = "black", lwd = 1, lty = 1, ... )
x |
An object of class |
... |
Additional arguments. For |
object |
An object of class |
begin |
Beginning of the displayed interval in seconds. |
end |
End of the displayed interval in seconds. |
panel_height |
Vertical distance between signal channels. If |
zero_line |
Logical. If |
main |
Optional plot title. |
mar |
Numeric vector of length four specifying the plot margins in the
form |
col |
Colour used to draw the signal traces. |
lwd |
Line width used to draw the signal traces. |
lty |
Line type used to draw the signal traces. |
Objects of class "sig" represent a single- or multi-channel signal
together with its sampling frequency and corresponding time vector.
print.sig() and print.summary.sig() return their input
object invisibly.
summary.sig() returns an object of class "summary.sig"
containing signal dimensions, sampling information, channel names,
and basic descriptive statistics for each channel.
plot.sig() is called for its side effect and returns x invisibly.
file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") x <- read_csv_signals( file, col_names_in_csv = TRUE ) print(x) summary(x) plot(x) plot(x, mar = c(4, 12, 2, 1)) plot(x, mar = c(4, 12, 2, 1), col = "blue") plot(x, col = "red", lwd = 2, lty = 4) plot(x, begin = 0, end = 1, main = "Signal")file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") x <- read_csv_signals( file, col_names_in_csv = TRUE ) print(x) summary(x) plot(x) plot(x, mar = c(4, 12, 2, 1)) plot(x, mar = c(4, 12, 2, 1), col = "blue") plot(x, col = "red", lwd = 2, lty = 4) plot(x, begin = 0, end = 1, main = "Signal")
Converts a numeric matrix or data frame containing one or more signals to the binary format required by EMPI. Rows correspond to samples and columns to channels. Values are stored as 4-byte floating-point numbers using little-endian byte order.
For multichannel signals, samples are written in time order, with all channel values
for a given time point stored consecutively: first all channels at t = 0,
then all channels at t = , and so on.
signal_to_bin(data, write_to_file = FALSE, path = NULL, file_name = NULL)signal_to_bin(data, write_to_file = FALSE, path = NULL, file_name = NULL)
data |
Data frame containing the input signal(s). |
write_to_file |
If |
path |
Directory in which the binary file will be saved.
If |
file_name |
Name of the file to create if |
A raw vector containing the binary representation of the signal.
If write_to_file = TRUE, a .bin file is additionally created.
The .bin files generated by this function are not intended for direct
user manipulation. They are used internally by empi_execute(). The external
program Enhanced Matching Pursuit Implementation (EMPI) requires binary input
data. This conversion utility may also be useful for users who wish to run EMPI
outside of the R environment.
file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") out <- read_csv_signals(file, col_names_in_csv = TRUE) signal_bin <- signal_to_bin(data = out$signal, write_to_file = FALSE) # We have 3 channels. The first 4 time points. head(out$signal, 4) # The same elements of the signal in binary (floats are stored in 4 bytes). head(signal_bin, 48) # After decoding to numeric. # Of course we get the same values as in out$signal. readBin(signal_bin[1:4], what = "numeric", size = 4, endian = "little") readBin(signal_bin[5:8], what = "numeric", size = 4, endian = "little") readBin(signal_bin[41:44], what = "numeric", size = 4, endian = "little") readBin(signal_bin[45:48], what = "numeric", size = 4, endian = "little")file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") out <- read_csv_signals(file, col_names_in_csv = TRUE) signal_bin <- signal_to_bin(data = out$signal, write_to_file = FALSE) # We have 3 channels. The first 4 time points. head(out$signal, 4) # The same elements of the signal in binary (floats are stored in 4 bytes). head(signal_bin, 48) # After decoding to numeric. # Of course we get the same values as in out$signal. readBin(signal_bin[1:4], what = "numeric", size = 4, endian = "little") readBin(signal_bin[5:8], what = "numeric", size = 4, endian = "little") readBin(signal_bin[41:44], what = "numeric", size = 4, endian = "little") readBin(signal_bin[45:48], what = "numeric", size = 4, endian = "little")
Creates a time-frequency map using atoms from the Matching Pursuit algorithm.
The resulting map can be: 1) displayed on the screen, 2) saved as a .png file,
or 3) saved as an .RData object.
tf_map( x = NULL, channel, mode = "sqrt", display_scale = "linear", db_range = 20, freq_divide = NULL, increase_factor = 4, shortening_factor_x = 2, shortening_factor_y = 2, atom_centers = "crosses", display_grid = FALSE, color = "white", palette = "my custom palette", reverse_palette = TRUE, out_mode = "plot", path = NULL, file_name = NULL, size = c(512, 512), draw_ellipses = FALSE, plot_signals = TRUE, write_atoms = FALSE, verbose = FALSE )tf_map( x = NULL, channel, mode = "sqrt", display_scale = "linear", db_range = 20, freq_divide = NULL, increase_factor = 4, shortening_factor_x = 2, shortening_factor_y = 2, atom_centers = "crosses", display_grid = FALSE, color = "white", palette = "my custom palette", reverse_palette = TRUE, out_mode = "plot", path = NULL, file_name = NULL, size = c(512, 512), draw_ellipses = FALSE, plot_signals = TRUE, write_atoms = FALSE, verbose = FALSE )
x |
An object of class |
channel |
Channel from the SQLite file to process. |
mode |
|
display_scale |
|
db_range |
Positive number specifying the displayed dynamic range
in dB (default 20); used only if |
freq_divide |
Specifies how many times the displayed frequency range in the T-F map
should be reduced. At high sampling rates, especially when a low-pass filter with
a cut-off frequency much lower than the sampling frequency is used, a large part of
the T-F map may contain no blobs. If the sampling frequency is |
increase_factor |
Factor controlling the increase in the number of pixels along the frequency axis. Non-negative integers such as 2, 4, 5, or 8 are usually appropriate. |
shortening_factor_x |
Positive factor narrowing the Gaussian blobs along time; the default of 2 is a visualization choice, not an estimated physical uncertainty. |
shortening_factor_y |
Positive factor narrowing the Gaussian blobs along frequency; the default of 2 is a visualization choice, not an estimated physical uncertainty. |
atom_centers |
|
display_grid |
Whether grid lines should be drawn. |
color |
Color of the small crosses or atom numbers. |
palette |
Palette from the list returned by the |
reverse_palette |
Value of the |
out_mode |
One of the following:
|
path |
Path where |
file_name |
Name of the |
size |
Size of the |
draw_ellipses |
Intended for testing only. Can be set to |
plot_signals |
Whether the original and reconstructed signals should also be displayed. |
write_atoms |
If |
verbose |
Logical flag indicating whether progress information should be printed. |
The function also computes basic reconstruction-quality measures for the selected channel, including signal energy, residual energy, and the proportion of explained signal energy.
Depending on the out_mode parameter, the function:
displays the time-frequency map on the screen
saves the time-frequency map as a .png file
saves the time-frequency map as a .RData file
Regardless of the output mode, the function also returns:
gabor_functions |
All Gabor functions. |
reconstruction |
Reconstructed signal. |
signal |
Original signal. |
signal_energy |
Energy of the original signal for the selected channel. |
reconstruction_energy |
Energy of the reconstructed signal for the selected channel. |
residual_energy |
Energy of the reconstruction residual. |
explained_energy |
Proportion of the original signal energy explained by the reconstruction,
|
sampling_frequency |
Sampling frequency. |
grid_size_t |
Grid size along the time axis. |
grid_size_f |
Grid size along the frequency axis. |
epochSize |
Epoch size in samples. |
number_of_secs |
Signal length in seconds. |
tf_map |
Time-frequency map. |
tf_map_resampled |
Resampled time-frequency map
(if |
channel |
Processed channel number. |
freq_divide |
Frequency division factor. |
For an exploratory, visually balanced map, start with
mode = "sqrt", display_scale = "linear".
This reduces the contrast between weak and strong atoms; the map is not
an energy-normalized time-frequency density.
To represent assigned atom energies by the integrals of Gaussian
blobs, use mode = "energy". The normalization holds for
each complete blob; cropping at time or frequency boundaries can remove
part of its displayed integral. For MP/OMP, the interpretation of the
supplied atom energies depends on how they were computed upstream.
Use display_scale = "db" to make weak structures
more visible. It computes 10 * log10(tf_map / max(tf_map))
and clips values below -db_range dB. Try 20 dB for a
selective display and 40 dB to reveal more weak structures.
db_range has no effect with display_scale = "linear".
mode = "linear" is a legacy amplitude rule proportional
to atom energy. At fixed shortening factors it differs from
mode = "energy" only by a global multiplier.
When comparing MP, OMP, signals, or recordings, keep the mode, Gaussian widths, frequency range, and palette fixed. The dB display is normalized separately to each map's maximum, so colors across different maps do not indicate equal absolute intensities.
The returned tf_map contains the summed, untransformed
Gaussian map for the chosen mode; it is not a spectrogram.
Saved RData matrices are additionally resized and scaled to [0, 1].
# Read signal and XML dictionary file <- system.file( "extdata", "sample1.csv", package = "MatchingPursuit" ) signal <- read_csv_signals(file) xml_file <- system.file( "extdata", "sample1.xml", package = "MatchingPursuit" ) # Perform OMP decomposition sample1_empi_out <- mp_omp_execute( mode = "omp", signal = signal, dictionary = xml_file, n_nonzero_coefs = 16, verbose = TRUE ) # Example 1: Default visualization # Square-root amplitude scaling and linear display. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "sqrt", display_scale = "linear", freq_divide = 4 ) # Example 2: Automatic frequency range # The displayed frequency range is determined from the # highest frequency among the selected atoms. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "sqrt", display_scale = "linear", freq_divide = NULL ) # Example 3: Energy-normalized Gaussian blobs # With a linear display, strong atoms dominate; # weak atoms may be less visible. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "energy", display_scale = "linear", freq_divide = 4 ) # Example 4: Logarithmic display # Enhances the visibility of weaker structures. # Values below -20 dB are mapped to the background color. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "energy", display_scale = "db", db_range = 20, freq_divide = 4 ) # Example 5: Wider dynamic range and alternative palette # Larger shortening factors produce more compact blobs. # Atom numbers identify the selected dictionary elements. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "energy", display_scale = "db", db_range = 40, freq_divide = 4, shortening_factor_x = 4, shortening_factor_y = 4, palette = "Inferno", reverse_palette = FALSE, atom_centers = "numbers" )# Read signal and XML dictionary file <- system.file( "extdata", "sample1.csv", package = "MatchingPursuit" ) signal <- read_csv_signals(file) xml_file <- system.file( "extdata", "sample1.xml", package = "MatchingPursuit" ) # Perform OMP decomposition sample1_empi_out <- mp_omp_execute( mode = "omp", signal = signal, dictionary = xml_file, n_nonzero_coefs = 16, verbose = TRUE ) # Example 1: Default visualization # Square-root amplitude scaling and linear display. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "sqrt", display_scale = "linear", freq_divide = 4 ) # Example 2: Automatic frequency range # The displayed frequency range is determined from the # highest frequency among the selected atoms. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "sqrt", display_scale = "linear", freq_divide = NULL ) # Example 3: Energy-normalized Gaussian blobs # With a linear display, strong atoms dominate; # weak atoms may be less visible. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "energy", display_scale = "linear", freq_divide = 4 ) # Example 4: Logarithmic display # Enhances the visibility of weaker structures. # Values below -20 dB are mapped to the background color. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "energy", display_scale = "db", db_range = 20, freq_divide = 4 ) # Example 5: Wider dynamic range and alternative palette # Larger shortening factors produce more compact blobs. # Atom numbers identify the selected dictionary elements. out <- tf_map( x = sample1_empi_out, channel = 1, mode = "energy", display_scale = "db", db_range = 40, freq_divide = 4, shortening_factor_x = 4, shortening_factor_y = 4, palette = "Inferno", reverse_palette = FALSE, atom_centers = "numbers" )
Methods for printing, summarizing, and plotting objects of class
"wfdb", together with a print method for objects returned by
summary().
## S3 method for class 'wfdb' plot( x, begin = NULL, end = NULL, panel_height = 3, small_squares = TRUE, zero_line = FALSE, ... ) ## S3 method for class 'wfdb' print(x, ...) ## S3 method for class 'wfdb' summary(object, ...) ## S3 method for class 'summary.wfdb' print(x, ...)## S3 method for class 'wfdb' plot( x, begin = NULL, end = NULL, panel_height = 3, small_squares = TRUE, zero_line = FALSE, ... ) ## S3 method for class 'wfdb' print(x, ...) ## S3 method for class 'wfdb' summary(object, ...) ## S3 method for class 'summary.wfdb' print(x, ...)
x |
An object of class |
begin |
Time point (in seconds) at which to start plotting.
If |
end |
Time point (in seconds) at which to stop plotting.
If |
panel_height |
Height of each ECG lead panel (in mV). |
small_squares |
Logical. If |
zero_line |
Logical. If |
... |
Additional arguments. Currently ignored. |
object |
An object of class |
Objects of class "wfdb" represent multi-channel physiological
signals imported from WFDB records, together with their sampling frequency,
time vector, lead names, and record name.
WFDB (WaveForm DataBase) is a widely used format and software framework for storing, reading, and analyzing physiological time-series signals. It is widely used for signals such as ECG, EEG, blood pressure, respiration, and other biomedical waveforms. It is the file format used by the PhysioNet project and is commonly used in research datasets.
A WFDB record typically consists of two main files:
.dat, containing binary signal samples, and .hea, a header
file describing how to interpret the data. Additional annotation files,
such as .atr, may also be present and may contain beat labels or
rhythm annotations.
The plotting method is designed primarily for ECG signals and displays individual leads in a layout resembling standard ECG paper. The small grid corresponds to 0.04 s by 0.1 mV and the large grid to 0.20 s by 0.5 mV.
print.wfdb() and print.summary.wfdb() return their input
object invisibly.
summary.wfdb() returns an object of class "summary.wfdb"
containing record information, signal dimensions, sampling information,
lead names, and basic descriptive statistics for each lead.
plot.wfdb() is called for its side effect and returns no value.
# ECG data from the PTB-XL database file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") x <- read_wfdb_signals(file) print(x) summary(x) plot( x, begin = 0, end = 10, panel_height = 1, zero_line = FALSE, small_squares = TRUE )# ECG data from the PTB-XL database file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") x <- read_wfdb_signals(file) print(x) summary(x) plot( x, begin = 0, end = 10, panel_height = 1, zero_line = FALSE, small_squares = TRUE )