Mirror
This demo demonstrates mirror padding, a technique for extending time-series data by reflecting it at the edges.
What is Mirror Padding?
Mirror padding extends your data at the beginning and/or end by creating a reflected copy:
Original: [A B C D E]
Pre-padding: [E D C B A | A B C D E]
Post-padding: [A B C D E | E D C B A]
Both: [E D C B A | A B C D E | E D C B A]This creates smooth, continuous edges that avoid discontinuities.
Why Use Mirror Padding?
Edge Artifact Reduction:
Filtering operations can introduce artifacts at the edges of your data because:
Filters "see" discontinuities at boundaries
Edge effects propagate inward
Lost information at boundaries
Mirror padding solves this by:
Creating smooth, continuous edges
Allowing filters to process edges naturally
Removing padding after filtering to discard corrupted edge regions
Typical Workflow:
Mirror your data (add padding)
Filter (artifacts now occur in padding region)
Remove padding (discard corrupted edges, keep clean data)
Padding Options
The mirror() function accepts three padding modes:
| Mode | Description |
|---|---|
| :pre | Mirror before the start |
| :post | Mirror after the end |
| :both | Mirror at both ends |
Use Cases
High-pass filtering:
High-pass filters are particularly sensitive to edge effects. Mirror padding helps preserve data near epoch boundaries.
Time-frequency analysis:
Wavelet transforms and spectral analysis benefit from smooth edges.
Concatenated epochs:
When processing multiple epochs sequentially, padding prevents edge artifacts between epochs.
Workflow Summary
This demo shows:
Load and preprocess continuous data
Extract epochs (-200 to 1000 ms)
Apply mirror padding with different modes (:pre, :post, :both)
Visualize padded epochs to see the effect
Average to ERPs and apply padding
Visualize padded ERPs
The visual comparison clearly shows how padding extends the time interval while maintaining smooth edges.
Code Examples
Show Code
# Demo: Mirror Padding
# Shows how to pad epoch and ERP data with mirrored edges (:pre, :post, :both)
# to reduce edge artifacts when filtering.
using EegFun
# Note: EegFun.example_path() resolves bundled example data paths.
# When using your own data, simply pass the file path directly, e.g.:
# dat = EegFun.read_raw_data("/path/to/your/data.bdf")
# read raw data
dat = EegFun.read_raw_data(EegFun.example_path("data/bdf/example1.bdf"));
# read and prepare layout file
layout = EegFun.read_layout(EegFun.example_path("layouts/biosemi/biosemi72.csv"));
EegFun.polar_to_cartesian_xy!(layout)
# create EegFun data structure (EegFun.ContinuousData)
dat = EegFun.create_eegfun_data(dat, layout);
# Some minimal preprocessing (average reference and highpass filter)
EegFun.rereference!(dat, :avg)
EegFun.highpass_filter!(dat, 0.1)
# Create some epoched data
epoch_cfg = [EegFun.EpochCondition(name = "ExampleEpoch1", trigger_sequences = [[1]])]
epochs = EegFun.extract_epochs(dat, epoch_cfg, (-0.2, 1.0)) # -200 to 1000 ms
EegFun.plot_epochs(epochs, channel_selection = EegFun.channels([:Fp1]))
epochs_new = EegFun.mirror(epochs, :pre)
EegFun.plot_epochs(epochs_new, channel_selection = EegFun.channels([:Fp1]))
epochs_new = EegFun.mirror(epochs, :post)
EegFun.plot_epochs(epochs_new, channel_selection = EegFun.channels([:Fp1]))
epochs_new = EegFun.mirror(epochs, :both)
EegFun.plot_epochs(epochs_new, channel_selection = EegFun.channels([:Fp1]))
# ERPs
erps = EegFun.average_epochs(epochs)
EegFun.plot_erp(erps, channel_selection = EegFun.channels([:Fp1]))
erps_new = EegFun.mirror(erps, :pre)
EegFun.plot_erp(erps_new, channel_selection = EegFun.channels([:Fp1]))
erps_new = EegFun.mirror(erps, :post)
EegFun.plot_erp(erps_new, channel_selection = EegFun.channels([:Fp1]))
erps_new = EegFun.mirror(erps, :both)
EegFun.plot_erp(erps_new, channel_selection = EegFun.channels([:Fp1]))