Episode 1: Standard Filtering

Learn how to clean and shape your EEG data with standard filtering nodes. This episode demonstrates the use of high-, low-, band-, and notch filters to remove drifts, noise, and power-line interference or to isolate specific frequency bands.

g.Pype offers four standard filters commonly used in EEG processing pipelines: Highpass, Lowpass, Bandstop (notch), and Bandpass. Below, we demonstrate how to use each of them in to serve typical use cases. These filters are implemented as second-order Butterworth IIR filters.

Highpass

The Highpass filter attenuates frequencies below a chosen cutoff, allowing higher-frequency activity to pass while removing slow drifts and trends. In EEG processing, highpass filtering is used to suppress slow baseline shifts and focus on faster brain activity. Start with the script below, where the Generator illustrates this behavior by producing a slow pseudo-drift at 0.05 Hz overlaid with white noise simulating EEG activity.

 1import gpype as gp
 2
 3if __name__ == "__main__":
 4
 5    app = gp.MainApp()
 6    p = gp.Pipeline()
 7
 8    source = gp.Generator(signal_frequency=0.05,
 9                          signal_amplitude=75,
10                          noise_amplitude=15)
11
12    scope = gp.TimeSeriesScope()
13
14    p.connect(source, scope)
15
16    app.add_widget(scope)
17
18    p.start()
19    app.run()  # blocking until window is closed
20    p.stop()

Run the script and observe the slow drift in the signal.

S2E1 example screenshot

Figure 13: Slow drift example.

To remove the drift while preserving higher-frequency EEG, add a Highpass filter highpass with cutoff frequency f_c=1 Hz between the Generator and TimeSeriesScope:

 8    source = gp.Generator(signal_frequency=0.05,
 9                          signal_amplitude=75,
10                          noise_amplitude=15)
11
12    highpass = gp.Highpass(f_c=1)
13
14    scope = gp.TimeSeriesScope()
15
16    p.connect(source, highpass)
17    p.connect(highpass, scope)
18
19    app.add_widget(scope)

Run the script again and confirm the slow drift is gone, while the higher frequencies remain.

S2E1 example screenshot

Figure 14: Slow drift removed via highpass filtering.

Lowpass

The Lowpass filter attenuates frequencies above a chosen cutoff, allowing lower-frequency components to pass while attenuating higher-frequency components. In EEG processing, lowpass filters are commonly applied to suppress high-frequency measurement noise and focus on slower brain rhythms. Use the script below to demonstrate this scenario. Here, the Generator produces a 4 Hz sinusoid mimicking Theta activity, embedded in white measurement noise.

 1import gpype as gp
 2
 3if __name__ == "__main__":
 4
 5    app = gp.MainApp()
 6    p = gp.Pipeline()
 7
 8    source = gp.Generator(signal_frequency=4,
 9                          signal_amplitude=25,
10                          noise_amplitude=25)
11
12    scope = gp.TimeSeriesScope()
13
14    p.connect(source, scope)
15
16    app.add_widget(scope)
17
18    p.start()
19    app.run()  # blocking until window is closed
20    p.stop()

Run the script and observe the noisy signal.

S2E1 example screenshot

Figure 15: Slow waves embedded in measurement noise.

To suppress the noise while preserving the low-frequency sinusoid, add a Lowpass filter lowpass with cutoff frequency f_c=6 Hz between the Generator and TimeSeriesScope:

 8    source = gp.Generator(signal_frequency=4,
 9                          signal_amplitude=25,
10                          noise_amplitude=25)
11
12    lowpass = gp.Lowpass(f_c=6)
13
14    scope = gp.TimeSeriesScope()
15
16    p.connect(source, lowpass)
17    p.connect(lowpass, scope)
18
19    app.add_widget(scope)

Run the script again and confirm the noise is substantially reduced, with the low-frequency component intact.

S2E1 example screenshot

Figure 16: Measurement noise eliminated via lowpass filtering.

Bandpass

The Bandpass filter attenuates frequencies outside a selected range, allowing only signals within that band to pass. In EEG processing, bandpass filters are commonly used remove both slow drifts and high-frequency noise from EEG data simultaneously, saving the need for separate highpass and lowpass filters. As well, bandpass filters are typically employed to to isolate specific brain rhythms, such as the alpha band (8-12 Hz), for focused analysis. The script below demonstrates such a typical use case, where the Generator produces a composite signal resembling 10 Hz alpha activity embedded in measurement noise.

 1import gpype as gp
 2
 3if __name__ == "__main__":
 4
 5    app = gp.MainApp()
 6    p = gp.Pipeline()
 7
 8    source = gp.Generator(signal_frequency=10,
 9                          signal_amplitude=25,
10                          noise_amplitude=25)
11
12    scope = gp.TimeSeriesScope()
13
14    p.connect(source, scope)
15
16    app.add_widget(scope)
17
18    p.start()
19    app.run()  # blocking until window is closed
20    p.stop()

Run the script and observe the noisy signal.

S2E1 example screenshot

Figure 17: Alpha wave embedded in measurementnoise.

To isolate the alpha component, insert a Bandpass filter bandpass with lower cutoff frequency f_lo=8 Hz and upper cutoff frequency f_hi=12 Hz between the Generator and TimeSeriesScope:

 8    source = gp.Generator(signal_frequency=10,
 9                          signal_amplitude=25,
10                          noise_amplitude=25)
11
12    bandpass = gp.Bandpass(f_lo=8, f_hi=12)
13
14    scope = gp.TimeSeriesScope()
15
16    p.connect(source, bandpass)
17    p.connect(bandpass, scope)
18
19    app.add_widget(scope)

Run the script and observe that only the alpha band remains visible in the output.

S2E1 example screenshot

Figure 18: Alpha wave isolated via bandpass filtering.

Bandstop (Notch)

The Bandstop (notch) filter attenuates a specific frequency band while leaving other frequencies unaffected. In EEG processing, bandstop filtering is essential for eliminating power-line interference from recordings. In the script below, the Generator illustrated this condition, producing a 50 Hz sinusoid combined with white noise to simulate EEG data contaminated by power-line interference.

 8import gpype as gp
 9
10if __name__ == "__main__":
11
12    app = gp.MainApp()
13    p = gp.Pipeline()
14
15    source = gp.Generator(signal_frequency=50,
16                          signal_amplitude=75,
17                          noise_amplitude=15)
18
19    scope = gp.TimeSeriesScope()
20
21    p.connect(source, scope)
22
23    app.add_widget(scope)
24
25    p.start()
26    app.run()  # blocking until window is closed
27    p.stop()

Run the script and observe the power-line interference in the signal.

S2E1 example screenshot

Figure 19: Example signal with power-line interference.

To suppress power-line interference, insert a Bandstop filter with f_low = 48 Hz and f_high = 52 Hz between the Generator and TimeSeriesScope:

 8    source = gp.Generator(signal_frequency=50,
 9                          signal_amplitude=75,
10                          noise_amplitude=15)
11
12    bandstop = gp.Bandstop(f_lo=48, f_hi=52)
13
14    scope = gp.TimeSeriesScope()
15
16    p.connect(source, bandstop)
17    p.connect(bandstop, scope)
18
19    app.add_widget(scope)

Run the script and confirm that the power-line frequency is removed from the signal.

S2E1 example screenshot

Figure 20: Power-line interference removed via bandstop filtering.

Completed! You can now employ typical filters to serve standard purposes in EEG processing in g.Pype.

Summary

In this episode, you learned how to employ standard filters, such as

  • Highpass to remove slow drifts

  • Lowpass to attenuate high-frequency noise

  • Bandpass to isolate specific frequency bands

  • Bandstop (notch) to eliminate power line interference

Note that there is also a MovingAverage filter available, which we will cover specifically in an upcoming episode.

You are now ready to proceed to episode 2, where we will begin with signal routing in g.Pype.

File s2e1_highpass.pyView file on GitHub

 1# --------------------------------------------------------------
 2# Example file s2e1_a_highpass.py
 3# For details and usage, see g.Pype Training Season 2, Episode 1
 4# --------------------------------------------------------------
 5
 6import gpype as gp
 7
 8if __name__ == "__main__":
 9
10    # Create main app and pipeline
11    app = gp.MainApp()
12    p = gp.Pipeline()
13
14    # Create signal source
15    source = gp.Generator(signal_frequency=0.05,
16                          signal_amplitude=75,
17                          noise_amplitude=15)
18
19    # Create highpass filter
20    highpass = gp.Highpass(f_c=1)
21
22    # Create scope
23    scope = gp.TimeSeriesScope()
24
25    # Connect nodes
26    p.connect(source, highpass)
27    p.connect(highpass, scope)
28
29    # Add widget to main app
30    app.add_widget(scope)
31
32    # Start pipeline and run application
33    p.start()
34    app.run()  # blocking until window is closed
35    p.stop()

File s2e1_lowpass.pyView file on GitHub

 1# --------------------------------------------------------------
 2# Example file s2e1_b_lowpass.py
 3# For details and usage, see g.Pype Training Season 2, Episode 1
 4# --------------------------------------------------------------
 5
 6import gpype as gp
 7
 8if __name__ == "__main__":
 9
10    # Create main app and pipeline
11    app = gp.MainApp()
12    p = gp.Pipeline()
13
14    # Create signal source
15    source = gp.Generator(signal_frequency=4,
16                          signal_amplitude=25,
17                          noise_amplitude=25)
18
19    # Create lowpass filter
20    lowpass = gp.Lowpass(f_c=6)
21
22    # Create scope
23    scope = gp.TimeSeriesScope()
24
25    # Connect nodes
26    p.connect(source, lowpass)
27    p.connect(lowpass, scope)
28
29    # Add widget to main app
30    app.add_widget(scope)
31
32    # Start pipeline and run application
33    p.start()
34    app.run()  # blocking until window is closed
35    p.stop()

File s2e1_bandpass.pyView file on GitHub

 1# --------------------------------------------------------------
 2# Example file s2e1_c_bandpass.py
 3# For details and usage, see g.Pype Training Season 2, Episode 1
 4# --------------------------------------------------------------
 5
 6import gpype as gp
 7
 8if __name__ == "__main__":
 9
10    # Create main app and pipeline
11    app = gp.MainApp()
12    p = gp.Pipeline()
13
14    # Create signal source
15    source = gp.Generator(signal_frequency=10,
16                          signal_amplitude=25,
17                          noise_amplitude=25)
18
19    # Create bandpass filter
20    bandpass = gp.Bandpass(f_lo=8, f_hi=12)
21
22    # Create scope
23    scope = gp.TimeSeriesScope()
24
25    # Connect nodes
26    p.connect(source, bandpass)
27    p.connect(bandpass, scope)
28
29    # Add widget to main app
30    app.add_widget(scope)
31
32    # Start pipeline and run application
33    p.start()
34    app.run()  # blocking until window is closed
35    p.stop()

File s2e1_bandstop.pyView file on GitHub

 1# --------------------------------------------------------------
 2# Example file s2e1_d_bandstop.py
 3# For details and usage, see g.Pype Training Season 2, Episode 1
 4# --------------------------------------------------------------
 5
 6import gpype as gp
 7
 8if __name__ == "__main__":
 9
10    # Create main app and pipeline
11    app = gp.MainApp()
12    p = gp.Pipeline()
13
14    # Create signal source
15    source = gp.Generator(signal_frequency=50,
16                          signal_amplitude=75,
17                          noise_amplitude=15)
18
19    # Create bandstop filter
20    bandstop = gp.Bandstop(f_lo=48, f_hi=52)
21
22    # Create scope
23    scope = gp.TimeSeriesScope()
24
25    # Connect nodes
26    p.connect(source, bandstop)
27    p.connect(bandstop, scope)
28
29    # Add widget to main app
30    app.add_widget(scope)
31
32    # Start pipeline and run application
33    p.start()
34    app.run()  # blocking until window is closed
35    p.stop()