1. Introduction: offline, causal and online analysis

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:

  1. Offline (batch): global denoising using future information.
  2. Causal (batch): batched processing that respects time causality (no lookahead).
  3. Online (stream): point-by-point processing for real-time applications.

Setup and data

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)")

1. Offline denoising (global)

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"
)

2. Causal denoising (batch)

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.

# Causal Denoising with a window of 256 points
causal_clean = denoise_signal_causal(
  doppler_example$noisy,
  scheme,
  window_size = 256,
  levels = floor(log2(256)), 
  method = "semisoft"
)

3. Online denoising (stream)

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])
}

Comparison

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