| Title: | Processing Time Series Data Using the Matching Pursuit Algorithm |
|---|---|
| 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. 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>) |
| Maintainer: | Artur Gramacki <[email protected]> |
| License: | GPL (>= 2) |
| Version: | 1.1.0 |
| Built: | 2026-05-10 22:47:32 UTC |
| Source: | https://github.com/artur-gramacki/matchingpursuit |
Reads atom parameters stored in a SQLite database created by empi.execute() function.
atom.params(db.file)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.
# Example database containing data from 18 channels file <- system.file("extdata", "EEG.db", package = "MatchingPursuit") out <- atom.params(file) out[which(out$channel_id == 1), ] out[which(out$channel_id == 18), ] # Example database containing data from a single channel file <- system.file("extdata", "sample1.db", package = "MatchingPursuit") out <- atom.params(file) out# Example database containing data from 18 channels file <- system.file("extdata", "EEG.db", package = "MatchingPursuit") out <- atom.params(file) out[which(out$channel_id == 1), ] out[which(out$channel_id == 18), ] # Example database containing data from a single channel file <- system.file("extdata", "sample1.db", package = "MatchingPursuit") out <- atom.params(file) out
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() }
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.
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 = c("bipolar"), bipolar.pairs = pairs) signal.ref.mont <- eeg.montage(out, montage.type = c("reference"), ref.channel = "O1") signal.avg.mont <- eeg.montage(out, montage.type = c("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 = c("bipolar"), bipolar.pairs = pairs) signal.ref.mont <- eeg.montage(out, montage.type = c("reference"), ref.channel = "O1") signal.avg.mont <- eeg.montage(out, montage.type = c("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()
If the EMPI program is found, its full path is returned. Otherwise, a message is displayed,
prompting the user to install it using the empi.install() function.
empi.check()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 |
List containing the signal in a data frame together with its sampling frequency.
The data frame should have meaningful column names (channel names).
The list must contain elements named |
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 |
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
empi is returned. If write.to.file = TRUE, the results are also written
to a SQLite file in the path directory.
## Not run: file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") out <- read.csv.signals(file) out.empi <- empi.execute( signal = out, empi.options = NULL, write.to.file = FALSE, path = NULL, file.name = NULL ) plot(out.empi) ## End(Not run)## Not run: file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") out <- read.csv.signals(file) out.empi <- empi.execute( signal = out, empi.options = NULL, write.to.file = FALSE, path = NULL, file.name = NULL ) plot(out.empi) ## End(Not run)
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 x64, 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.
if (interactive()) { empi.install() }if (interactive()) { empi.install() }
Returns Enhanced Matching Pursuit Implementation binary locations for the following operation systems: Windows, Linux, MacOS-x64, MacOS-arm64.
empi.locate()empi.locate()
List with URL of the EMPI binaries and zip file name.
empi.locate()empi.locate()
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.
empi2tf( x = NULL, channel, mode = "sqrt", freq.divide = NULL, increase.factor = 1, shortening.factor.x = 2, shortening.factor.y = 2, display.crosses = TRUE, display.atom.numbers = FALSE, display.grid = FALSE, crosses.color = "white", palette = "my custom palette", rev = TRUE, out.mode = "plot", path = NULL, file.name = NULL, size = c(512, 512), draw.ellipses = FALSE, plot.signals = TRUE, write.atoms = FALSE )empi2tf( x = NULL, channel, mode = "sqrt", freq.divide = NULL, increase.factor = 1, shortening.factor.x = 2, shortening.factor.y = 2, display.crosses = TRUE, display.atom.numbers = FALSE, display.grid = FALSE, crosses.color = "white", palette = "my custom palette", rev = TRUE, out.mode = "plot", path = NULL, file.name = NULL, size = c(512, 512), draw.ellipses = FALSE, plot.signals = TRUE, write.atoms = FALSE )
x |
An object of class |
channel |
Channel from the SQLite file to process. |
mode |
|
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 |
Usually, a value of 2 provides better atom visualization. |
shortening.factor.y |
Usually, a value of 2 provides better atom visualization. |
display.crosses |
Whether small crosses should be displayed at the centres of atoms. |
display.atom.numbers |
Whether atom numbers should be displayed in the canters of atoms. |
display.grid |
Whether grid lines should be drawn. |
crosses.color |
Colour of the small crosses. |
palette |
PPalette from the list returned by the |
rev |
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 |
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:
all Gabor functions
reconstructed signal
original signal
sampling frequency
grid size along the time axis
grid size along the frequency axis
epoch size in samples
signal length in seconds
time-frequency map
resampled time-frequency map
(if out.mode = "RData" or out.mode = "RData2"; otherwise NULL)
processed channel number
frequency division factor
file <- system.file("extdata", "sample1.db", package = "MatchingPursuit") empi.class <- read.empi.db.file(file) # 'freq.divide' is set arbitrarily out <- empi2tf( x = empi.class, channel = 1, mode = "sqrt", freq.divide = 4, increase.factor= 4, display.crosses = TRUE, display.atom.numbers = FALSE, out.mode = "plot", ) # 'freq.divide' is determined based on the atom with the highest frequency out <- empi2tf( x = empi.class, channel = 1, mode = "sqrt", increase.factor= 4, display.crosses = TRUE, display.atom.numbers = FALSE, out.mode = "plot", )file <- system.file("extdata", "sample1.db", package = "MatchingPursuit") empi.class <- read.empi.db.file(file) # 'freq.divide' is set arbitrarily out <- empi2tf( x = empi.class, channel = 1, mode = "sqrt", freq.divide = 4, increase.factor= 4, display.crosses = TRUE, display.atom.numbers = FALSE, out.mode = "plot", ) # 'freq.divide' is determined based on the atom with the highest frequency out <- empi2tf( x = empi.class, channel = 1, mode = "sqrt", increase.factor= 4, display.crosses = TRUE, display.atom.numbers = FALSE, out.mode = "plot", )
signal::butter() functionImplements notch, low-pass, high-pass, band-pass, and band-stop filters with specified frequency ranges and Butterworth filter order.
filters.coeff( fs = 256, notch = c(49, 51), notch.order = 2, lowpass = 30, lowpass.order = 4, highpass = 1, highpass.order = 4, bandpass = c(0.5, 40), bandpass.order = 4, bandstop = c(0.5, 40), bandstop.order = 4 )filters.coeff( fs = 256, notch = c(49, 51), notch.order = 2, lowpass = 30, lowpass.order = 4, highpass = 1, highpass.order = 4, bandpass = c(0.5, 40), bandpass.order = 4, bandstop = c(0.5, 40), bandstop.order = 4 )
fs |
Sampling rate. |
notch |
Vector of two frequencies for notch filter. |
notch.order |
Notch filter order. |
lowpass |
Low-pass filter frequency. |
lowpass.order |
Low-pass filter order. |
highpass |
High-pass filter frequency. |
highpass.order |
High-pass filter order. |
bandpass |
Vector of two frequencies for band-pass filter. |
bandpass.order |
Band-pass filter order. |
bandstop |
Vector of two frequencies for band-stop filter. |
bandstop.order |
Band-stop filter order. |
List with parameters of individual filters.
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out <- read.edf.signals(file, resampling = FALSE) signal <- out$signal sampling.rate <- out$sampling.rate fc <- filters.coeff( fs = sampling.rate, 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.rate) signal::freqz(fc$lowpass, Fs = sampling.rate) signal::freqz(fc$highpass, Fs = sampling.rate) signal::freqz(fc$bandpass, Fs = sampling.rate) signal::freqz(fc$bandstop, Fs = sampling.rate) 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.rate <- out$sampling.rate fc <- filters.coeff( fs = sampling.rate, 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.rate) signal::freqz(fc$lowpass, Fs = sampling.rate) signal::freqz(fc$highpass, Fs = sampling.rate) signal::freqz(fc$bandpass, Fs = sampling.rate) signal::freqz(fc$bandstop, Fs = sampling.rate) 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())
A Gabor function is a sinusoidal wave localized by a Gaussian envelope. In signal processing, it is widely used as a basic building block for representing signals localized in both time and frequency. The Matching Pursuit algorithm uses a redundant dictionary of so-called Gabor atoms. These atoms are particularly suitable because they: 1) provide optimal time–frequency localization, 2) represent oscillatory signals well, 3) enable adaptive time-frequency decomposition.
gabor.fun( number.of.samples, sampling.frequency, mean, phase, sigma, frequency, normalization = TRUE )gabor.fun( number.of.samples, sampling.frequency, mean, phase, sigma, frequency, normalization = TRUE )
number.of.samples |
Number of samples in the generated atom. |
sampling.frequency |
Sampling frequency. |
mean |
Time position of the Gaussian envelope. |
phase |
Phase of the sinusoidal component. |
sigma |
Scale parameter controlling the width of the Gaussian window. |
frequency |
Frequency of the sinusoidal component. |
normalization |
If |
A list containing four numeric vectors of length number.of.samples:
cosine, Gaussian envelope, Gabor function, and time axis.
number.of.samples <- 512 sampling.frequency <- 256.0 mean <- 1 phase <- pi sigma <- 0.5 frequency <- 5.0 normalization = TRUE out <- gabor.fun( number.of.samples, sampling.frequency, mean, phase, sigma, frequency, normalization ) # If normalization = TRUE, norm of atom = 1, we can check it crossprod(out$gabor) plot(out$t, 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.fun( number.of.samples, sampling.frequency, mean, phase, sigma, frequency, normalization ) # If normalization = TRUE, norm of atom = 1, we can check it crossprod(out$gabor) plot(out$t, out$gabor, type = "l", xlab = "t", ylab = "gabor", panel.first = grid())
A typical ECG paper layout was used, with a small grid of 0.04 s × 0.1 mV and a large grid of 0.20 s × 0.5 mV.
## S3 method for class 'ecg' plot( x, begin, end, panel.height = 3, small.squares = TRUE, zero.line = FALSE, ... )## S3 method for class 'ecg' plot( x, begin, end, panel.height = 3, small.squares = TRUE, zero.line = FALSE, ... )
x |
Object of class |
begin |
Time point (in seconds) at which to start plotting. |
end |
Time point (in seconds) at which to stop plotting. |
panel.height |
Number of large squares to display (according to standard ECG paper):
|
small.squares |
If |
zero.line |
If |
... |
Currently ignored. Required for compatibility with the generic |
No return value, called to visualize an ECG graph.
# ECG data comes from https://physionet.org/content/ptb-xl/1.0.3/ file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") dir <- dirname(file) name <- tools::file_path_sans_ext(basename(file)) out <- read.ecg.signals(file) plot( x = out, begin = 0, end = 10, panel.height = 1, zero.line = FALSE, small.squares = TRUE )# ECG data comes from https://physionet.org/content/ptb-xl/1.0.3/ file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") dir <- dirname(file) name <- tools::file_path_sans_ext(basename(file)) out <- read.ecg.signals(file) plot( x = out, begin = 0, end = 10, panel.height = 1, zero.line = FALSE, small.squares = TRUE )
Signals are displayed one below another and may be shown in different colours for improved readability.
## S3 method for class 'edf' plot( x, begin, end, panel.height = NULL, rainbow = TRUE, bg.colour = "black", txt.col = "white", zero.line = TRUE, main = NULL, ... )## S3 method for class 'edf' plot( x, begin, end, panel.height = NULL, rainbow = TRUE, bg.colour = "black", txt.col = "white", zero.line = TRUE, main = NULL, ... )
x |
Object of class |
begin |
Time point (in seconds) at which to start plotting. |
end |
Time point (in seconds) at which to stop plotting. |
panel.height |
Controls the vertical spacing between individual signals.
If |
rainbow |
If |
bg.colour |
Background colour. |
txt.col |
Colour of text elements (axis labels and title). |
zero.line |
If |
main |
The text shown as the plot title. |
... |
Currently ignored. Required for compatibility with the generic |
No return value, called to visualize an EEG graph.
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out <- read.edf.signals(file, resampling = FALSE) plot( x = out, 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 = out, 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") out <- read.edf.signals(file, resampling = FALSE) plot( x = out, 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 = out, 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" )
This function is a wrapper around empi2tf() with out.mode = "plot".
## S3 method for class 'empi' plot( x, channel = 1, mode = "sqrt", freq.divide = NULL, increase.factor = 8, shortening.factor.x = 2, shortening.factor.y = 2, display.crosses = TRUE, display.atom.numbers = FALSE, display.grid = FALSE, crosses.color = "white", palette = "my custom palette", plot.signals = TRUE, ... )## S3 method for class 'empi' plot( x, channel = 1, mode = "sqrt", freq.divide = NULL, increase.factor = 8, shortening.factor.x = 2, shortening.factor.y = 2, display.crosses = TRUE, display.atom.numbers = FALSE, display.grid = FALSE, crosses.color = "white", palette = "my custom palette", plot.signals = TRUE, ... )
x |
An object of class |
channel |
Channel from the SQLite file to process. |
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. |
display.crosses |
Whether small crosses should be displayed at the centres of atoms. |
display.atom.numbers |
Whether atom numbers should be displayed at the centres of atoms. |
display.grid |
Whether grid lines should be drawn. |
crosses.color |
Colour of the small crosses. |
palette |
Palette from the list returned by |
plot.signals |
Whether the original and reconstructed signals should also be displayed. |
... |
Currently ignored. Required for compatibility with the generic |
No return value, called to visualize the empi decomposition.
file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names = "ch1") # Execute the MP algorithm. empi.class <- empi.execute(signal = signal) # Plot a time-frequency map based on MP atoms. plot(empi.class)file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names = "ch1") # Execute the MP algorithm. empi.class <- empi.execute(signal = signal) # Plot a time-frequency map based on MP atoms. plot(empi.class)
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 rate in Hz ( |
col.names |
Optional character vector of column names. If not specified, default names are created. |
col.names.in.csv |
iLogical value. If |
A list containing:
a data frame (rows = samples, columns = channels),
sampling rate.
file <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") # The first line of the file must contain two numbers: # a) the sampling rate 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.rate file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names = c("signal_1", "signal_2", "signal_3")) head(signal$signal) signal$sampling.rate # Now, the csv file contains signal names in the second line file <- system.file("extdata", "EEG.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names.in.csv = TRUE) head(signal$signal) signal$sampling.rate # Now, the csv file contains signal names in the second line # The data here is the same as in the EEG.csv file, but after performing # 'double banana' montages and after applying filtering. file <- system.file("extdata", "EEG_bipolar_filtered.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names.in.csv = TRUE) head(signal$signal) signal$sampling.ratefile <- system.file("extdata", "sample1.csv", package = "MatchingPursuit") # The first line of the file must contain two numbers: # a) the sampling rate 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.rate file <- system.file("extdata", "sample3.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names = c("signal_1", "signal_2", "signal_3")) head(signal$signal) signal$sampling.rate # Now, the csv file contains signal names in the second line file <- system.file("extdata", "EEG.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names.in.csv = TRUE) head(signal$signal) signal$sampling.rate # Now, the csv file contains signal names in the second line # The data here is the same as in the EEG.csv file, but after performing # 'double banana' montages and after applying filtering. file <- system.file("extdata", "EEG_bipolar_filtered.csv", package = "MatchingPursuit") signal <- read.csv.signals(file, col.names.in.csv = TRUE) head(signal$signal) signal$sampling.rate
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 was developed by PhysioNet and is common in research datasets. 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 was developed by PhysioNet and is commonly used in research datasets.
read.ecg.signals(file)read.ecg.signals(file)
file |
Path to the ECG 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 ecg. The returned value is a list containing:
1) a matrix of signals stored in the ECG file,
2) the sampling rate,
3) time stamps,
4) lead names,
5) record name.
# ECG data comes from https://physionet.org/content/ptb-xl/1.0.3/ file <- system.file("extdata", "00001_lr.hea", package = "MatchingPursuit") dir <- dirname(file) name <- tools::file_path_sans_ext(basename(file)) out <- read.ecg.signals(file) head(out$signal) out$sampling.rate 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") dir <- dirname(file) name <- tools::file_path_sans_ext(basename(file)) out <- read.ecg.signals(file) head(out$signal) out$sampling.rate out$lead.names plot(out, begin = 0, end = 10, panel.height = 1.5)
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.
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, f.new = NULL, from = NULL, to = NULL, verbose = FALSE )read.edf.signals( file, resampling = FALSE, f.new = NULL, from = NULL, to = NULL, verbose = FALSE )
file |
Path to the EDF / EDF+ file to be read. |
resampling |
If |
f.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, a list containing:
1) a data frame with all signals stored in the EDF file,
2) sampling rate after optional resampling,
3) time stamps after optional resampling,
4) signal names.
file <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out1 <- read.edf.signals(file, resampling = FALSE) lapply(out1, class) out1$sampling.rate out2 <- read.edf.signals(file, resampling = TRUE, f.new = 128, verbose = TRUE) lapply(out2, class) out2$sampling.ratefile <- system.file("extdata", "EEG.edf", package = "MatchingPursuit") out1 <- read.edf.signals(file, resampling = FALSE) lapply(out1, class) out1$sampling.rate out2 <- read.edf.signals(file, resampling = TRUE, f.new = 128, verbose = TRUE) lapply(out2, class) out2$sampling.rate
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.file(db.file)read.empi.db.file(db.file)
db.file |
SQLite file. |
Object of class empi is returned with the following items:
parameters of all generated atoms,
original input signal(s),
reconstructed signal(s) obtained as the sum of generated atoms,
generated Gabor atoms,
time stamps,
sampling rate.
## Not run: file <- system.file("extdata", "EEG.db", package = "MatchingPursuit") out <- read.empi.db.file(file) n.channels <- ncol(out$original.signal) original.signal <- out$original.signal reconstruction <- out$reconstruction t <- out$t f <- out$f 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( original.signal[,1], type = "l", col = "blue", main = paste("channel: ", 1, " / " , n.channels, " (original signal)", sep = ""), xaxt = "n", ylab = "", xlab = "time [sec]" ) len <- length(original.signal[, 1]) lab <- seq(t[1], t[len] + 1 / f, 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) ## End(Not run)## Not run: file <- system.file("extdata", "EEG.db", package = "MatchingPursuit") out <- read.empi.db.file(file) n.channels <- ncol(out$original.signal) original.signal <- out$original.signal reconstruction <- out$reconstruction t <- out$t f <- out$f 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( original.signal[,1], type = "l", col = "blue", main = paste("channel: ", 1, " / " , n.channels, " (original signal)", sep = ""), xaxt = "n", ylab = "", xlab = "time [sec]" ) len <- length(original.signal[, 1]) lab <- seq(t[1], t[len] + 1 / f, 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) ## End(Not run)
Saves the given data (signals) in binary form. The input signal(s) must be a data frame:
rows correspond to samples for all channels, and columns correspond to channels.
The function is used internally by empi.execute(). The binary data consist of
floating-point values in the byte order of the current machine (no byte-order conversion
is performed).
For multichannel signals, samples are written in time order: first all channels at t = 0,
then all channels at t=t, and so on. In other words, the signal is
stored in column-major order (rows = channels, columns = samples).
sig2bin(data, write.to.file = FALSE)sig2bin(data, write.to.file = FALSE)
data |
Data frame containing the input signal(s). |
write.to.file |
If |
Input signal returned as raw. If write.to.file = TRUE, a .bin file
is additionally created and saved in the current directory.
Users do not work directly with .bin files. Binary files are used only in
empi.execute(). The external program Enhanced Matching Pursuit Implementation
(EMPI), executed inside this function, 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) signal.bin <- sig2bin(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) signal.bin <- sig2bin(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")