Episode 5: Visual Categorization

Learn how to perform and analyze a visual categorization experiment with g.Pype. This episode demonstrates how to run a paradigm presenting visual stimuli such as faces and patterns while recording and analyzing corresponding brain responses.

Note

This page is still under development. Until we have the step-by-step instructions ready, please refer to the code example below.

File example_paradigm_checkerboard_face.pyView file on GitHub

  1from pathlib import Path
  2import os
  3
  4import gpype as gp
  5
  6parent_dir = os.path.dirname(os.path.abspath(__file__))
  7paradigm = os.path.join(parent_dir, "paradigms", "CheckerboardFace.xml")
  8sampling_rate = 250
  9channel_count = 8
 10id_low_freq = 1
 11id_high_freq = 2
 12id_face = 3
 13t_pre = 0.2
 14t_post = 0.7
 15
 16if __name__ == "__main__":
 17
 18    # Create main application & pipeline
 19    app = gp.MainApp()
 20    p = gp.Pipeline()
 21
 22    # Amplifier: BCI Core-8 (uncomment if you want to use it)
 23    # amp = gp.BCICore8()
 24
 25    # Amplifier: g.Nautilus (uncomment if you want to use it)
 26    # amp = gp.GNautilus(sampling_rate=sampling_rate,
 27    #                    channel_count=channel_count)
 28
 29    # Signal generator (uncomment if you want to use it)
 30    amp = gp.Generator(
 31        sampling_rate=sampling_rate,
 32        channel_count=channel_count,
 33        signal_frequency=10,
 34        signal_amplitude=15,
 35        signal_shape="sine",
 36        noise_amplitude=10,
 37    )
 38
 39    # Bandpass from 1 to 30 Hz
 40    bandpass = gp.Bandpass(f_lo=1, f_hi=30)
 41
 42    # Bandstop (notch) filter for 50 and 60 Hz
 43    notch50 = gp.Bandstop(f_lo=48, f_hi=52)
 44    notch60 = gp.Bandstop(f_lo=58, f_hi=62)
 45
 46    # Presenter trigger receiver
 47    trig_receiver = gp.UDPReceiver()
 48
 49    # Trigger data
 50    trig_node_checkerboard = gp.Trigger(
 51        time_pre=t_pre, time_post=t_post, target=[id_low_freq, id_high_freq]
 52    )
 53    trig_node_face = gp.Trigger(
 54        time_pre=t_pre, time_post=t_post, target=id_face
 55    )
 56
 57    # Keyboard capture
 58    key_capture = gp.Keyboard()
 59
 60    # Time series scope
 61    mk = gp.TimeSeriesScope.Markers
 62    markers = [
 63        mk(
 64            color="#00aa00",
 65            label="Low SF",
 66            channel=channel_count,
 67            value=id_low_freq,
 68        ),
 69        mk(
 70            color="#ff0000",
 71            label="High SF",
 72            channel=channel_count,
 73            value=id_high_freq,
 74        ),
 75        mk(
 76            color="#0000ff", label="Face", channel=channel_count, value=id_face
 77        ),
 78        mk(color="m", label="M Key", channel=channel_count + 1, value=77),
 79    ]
 80    scope = gp.TimeSeriesScope(
 81        amplitude_limit=50, time_window=10, markers=markers
 82    )
 83
 84    # Trigger scope
 85    trig_scope = gp.TriggerScope(
 86        amplitude_limit=5, plots=["face", "checkerboard", "face-checkerboard"]
 87    )
 88
 89    # Merge signals for scope and data saving
 90    router_scope = gp.Router(
 91        input_channels=[gp.Router.ALL, gp.Router.ALL, gp.Router.ALL]
 92    )
 93    router_raw = gp.Router(
 94        input_channels=[gp.Router.ALL, gp.Router.ALL, gp.Router.ALL]
 95    )
 96
 97    # File writer
 98    filename = Path(paradigm).stem
 99    writer = gp.CsvWriter(file_name=f"{filename}.csv")
100
101    # connect amplifier to filter nodes
102    p.connect(amp, bandpass)
103    p.connect(bandpass, notch50)
104    p.connect(notch50, notch60)
105
106    # merge scope data
107    p.connect(notch60, router_scope["in1"])
108    p.connect(trig_receiver, router_scope["in2"])
109    p.connect(key_capture, router_scope["in3"])
110
111    # merge raw data
112    p.connect(amp, router_raw["in1"])
113    p.connect(trig_receiver, router_raw["in2"])
114    p.connect(key_capture, router_raw["in3"])
115
116    # connect inputs of time series scope and file writer
117    p.connect(router_scope, scope)
118    p.connect(router_raw, writer)
119
120    # connect trigger node and scope
121    p.connect(notch60, trig_node_checkerboard[gp.Constants.Defaults.PORT_IN])
122    p.connect(trig_receiver, trig_node_checkerboard[gp.Trigger.PORT_TRIGGER])
123    p.connect(notch60, trig_node_face[gp.Constants.Defaults.PORT_IN])
124    p.connect(trig_receiver, trig_node_face[gp.Trigger.PORT_TRIGGER])
125    p.connect(trig_node_checkerboard, trig_scope["checkerboard"])
126    p.connect(trig_node_face, trig_scope["face"])
127
128    # Create main app and add widgets
129    presenter = gp.ParadigmPresenter(paradigm)
130    app.add_widget(presenter)
131    app.add_widget(scope)
132    app.add_widget(trig_scope)
133
134    # start pipeline and main app
135    p.start()
136    app.run()
137    p.stop()