Skip to content

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:

  1. Mirror your data (add padding)

  2. Filter (artifacts now occur in padding region)

  3. Remove padding (discard corrupted edges, keep clean data)

Padding Options

The mirror() function accepts three padding modes:

ModeDescription
:preMirror before the start
:postMirror after the end
:bothMirror 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:

  1. Load and preprocess continuous data

  2. Extract epochs (-200 to 1000 ms)

  3. Apply mirror padding with different modes (:pre, :post, :both)

  4. Visualize padded epochs to see the effect

  5. Average to ERPs and apply padding

  6. Visualize padded ERPs

The visual comparison clearly shows how padding extends the time interval while maintaining smooth edges.

Code Examples

Show Code
julia
# 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]))

See Also