The rLifting package provides a unified high-performance
framework for wavelet lifting transforms in R. Uniquely, it bridges the
gap between traditional offline statistical analysis and real-time
signal processing.
This vignette demonstrates the three core modes of operation using a Doppler signal:
We utilize the doppler_example dataset included in the
package.
library(rLifting)
if (!requireNamespace("dplyr", quietly = TRUE) ||
!requireNamespace("ggplot2", quietly = TRUE)) {
knitr::opts_chunk$set(eval = FALSE)
message("Required packages 'dplyr' and 'ggplot2' are missing. Vignette code will not run.")
} else {
library(dplyr)
library(ggplot2)
}
data("doppler_example", package = "rLifting")
# Visualize the noisy input
ggplot(doppler_example, aes(x = index, y = noisy)) +
geom_line(color = "grey60", alpha = 0.8) +
geom_line(aes(y = original), color = "black", alpha = 0.5, linetype = "dashed") +
theme_minimal() +
labs(title = "Input signal (Doppler + noise)")In offline mode, the algorithm has access to the entire signal (past and future). This allows it to compute global thresholding statistics and perform non-causal lifting steps, resulting in the smoothest possible reconstruction.
Use case: historical data analysis, post-processing.
# Define the Wavelet Scheme (Haar for this example)
scheme = lifting_scheme("haar")
# Denoise using strict offline mode
# levels = floor(log2(n)) ensures maximum decomposition depth
offline_clean = denoise_signal_offline(
doppler_example$noisy,
scheme,
levels = floor(log2(nrow(doppler_example))),
method = "semisoft"
)In causal mode, we process the history as if we were receiving it sequentially. The estimate at time \(t\) depends only on \(x_1, \dots, x_t\). We use a sliding window of size \(W\) to calculate local statistics (see Liu et al 2014).
Use case: backtesting trading strategies, simulating real-time systems on historical data.
Online mode allows you to process data point-by-point as it arrives
from a sensor or API. It uses a C++ ring buffer to maintain
the sliding window state efficiently (amortized constant time per
update).
Use case: IoT sensors, live financial feeds, monitoring systems.
# Initialize the Stream Processor
processor = new_wavelet_stream(
scheme,
window_size = 256,
levels = floor(log2(256)),
method = "semisoft"
)
# Simulate streaming (vectorized loop for demonstration)
online_clean = numeric(nrow(doppler_example))
for (i in 1:nrow(doppler_example)) {
online_clean[i] = processor(doppler_example$noisy[i])
}Combining all three views illustrates the trade-off. The offline method provides better smoothing (lower variance) because it “sees the future”. The causal/online methods are reactive but naturally exhibit a slight phase lag.
# Combine results
df_plot = doppler_example |>
mutate(
Offline = offline_clean,
Causal = causal_clean,
Online = online_clean
)
# Plot focusing on a specific section to see the lag
ggplot(df_plot, aes(x = index)) +
# Add Truth curve
geom_line(aes(y = original, color = "Truth"), linewidth = 0.8, alpha = 0.6) +
geom_line(aes(y = Offline, color = "Offline"), alpha = 0.8) +
geom_line(aes(y = Causal, color = "Causal"), alpha = 0.8) +
scale_color_manual(values = c("Truth" = "black", "Offline" = "blue", "Causal" = "red")) +
theme_minimal() +
labs(title = "Trade-off: smoothness vs. causality") +
coord_cartesian(xlim = c(500, 1000)) # Zoom in