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.
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.
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.
Figure 14: Slow drift removed via highpass filtering.
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.
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.
Figure 16: Measurement noise eliminated via lowpass filtering.
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.
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.
Figure 18: Alpha wave isolated via bandpass filtering.
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.
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.
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.
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.py – View 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.py – View 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.py – View 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.py – View 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()