BCPy2000 is a software project for rapid and flexible development of brain-computer interface systems. It is based on the BCI2000 project and uses Python v3.6.8 for the 32-bit version and v3.8.6 for the 64-bit version. It leverages high-level packages such as Psychopy for stimulus presentation and NumPy and SciPy for signal processing and classification.
The project is modular, with three independent modules: application, signal source, and signal processing. You can use BCI2000's Signal Source module, which supports a wide range of EEG acquisition modules, or run the modules as Python modules.
BCPy2000 is designed for developers and clinicians with some Python experience. It lets you build your own experiments and modules based on your own code. The demo implementation showcases higher-level Python tools to give you a starting point. BCPy2000 offers a flexible platform for customizing your brain-computer interface system.
Here is a high-level overview of why you should consider BCPy2000:
Supported Source Devices
You can find our new convenient installer for BCPy2000 here. The installer configures your system to work with any recent 64 bit distribution of BCI2000. This includes the distributed binaries and the compiled version.
For this project you will need two things, our portable Python package, and BCI2000. If you'd like to set up the environment yourself and not use the provided installer, you can find the 32 bit version of our portable Python here and the 64 version here. BCPy2000 will be compiled automatically with other BCI2000 programs. Compilation is only supported in BCI2000 with the Visual Studio or MinGW compilers. You can find these instructions at Programming_Howto:Building_BCI2000. One consideration when building BCPy2000 is that you must choose a Qt_5 installation which corresponds to whatever version of BCPy2000 you are build, for example, if you are building a 32 bit version of BCPy2000 make sure that you have downloaded and select a 32 bit version of Qt. You also need to make sure that when you are configuring BCI2000 in CMake, you choose the "BUILD_BCPY2000" and "BUILD_CONTRIB" flags. Once you have done this you can configure and generate your BCI2000 solution.
|64x Qt installation
|64x Visual Studio
In this video we go over what BCPy2000 is, how to install it, a demonstration of our Triangle application, a section on how you can create your own BCPy2000 experiments, and a demonstration of a P300 task involving a live subject:
BCPy2000 source modules
Once you are in Visual Studio, you can edit the Python Application, Signal Processing, and Source modules and build them individually or all together (note that when you first open this project you will want to build the entire solution first). All three modules share filter and wrapper classes which allow Python functions to be loaded dynamically from a DLL at runtime. These files are where you will be able to make any necessary customization of the interface between the BCI2000 C++ code and the Python code should you want to. After building the application, source, and signal processing modules, then, from your main BCI home directory you will need to navigate to src\contrib\BCPy2000\demo and copy the contents of the batch, data, parms, prog, and python folders into each corresponding folder in the main directory.
We recently released an executable installer for BCPy2000. After downloading, open the executable and let the setup wizard guide you through the installation process. Here you can specify where to install BCPy2000; the default installation location is under Program Files. After installation, you'll find a new System environment variable under your user's Path, pointing to the new Python environment.
Portable Python Installation
Use the provided executable installer or follow these steps to configure Python as a system variable:
- Set the PATH of the unzipped package's file directory in System Variables, accessible through the Windows search bar.
- Create a new Path named "PYTHONHOME_BCI2000" to avoid interference with other Python installations.
- The portable Python package contains all Python dependencies, including the BCPy2000 and Psychopy code, as well as other high-level packages.
- (Optional)Customize your Python environment by adding new packages using pip in the command prompt.
With the necessary components installed, you can now implement your own experiment.
Once you have set up your portable Python package and have compiled, built, and copied the executables to each corresponding folder you can run a batch file. We included a demonstration called "triangle application" which asks the user to imagine moving their hands or feet in order to guide a cursor into one of three corners of a triangle while simultaneously giving the user color and sound feedback which corresponds to an imagination task and a sound. To open the triangle application you need to open the Triangle application batch file "PythonDemo1_Triangle_p3.bat." Once opened you should first see the operator window which allows you to set configurations, run, and suspend the running of the application. You can edit a myriad of variables and customize the experiment in the configuration menu. Under the visualize you can allow for the BCI2000 operator do show timing and raw brain signal. Another important section is the source section in which you can define number of channels, sampling rate, and block size along with many other important source generation configurations. Under data you can edit the specifics of how data is stored and where it is stored. You can also change how the Python application and signal processing modules are configured. One useful flag is the "show signal time" modifier which allows for developers to monitor several states during runtime. You can also save any changes that you made to the configuration by hitting "save configuration" and saving it into the /parms/ folder. Once you are happy with your configuration you can hit "set config" which will initialize the application, and then "start run" which will start the stimuli.
self.params is a dictionary of parameters, indexed by parameter name. Parameter values are stored as strings, or as lists of strings (for list parameters) or nested lists of strings (for matrix parameters). Numeric values can be obtained by the appropriate call to int or float -- for example: ch_ind = map(int, self.params['TransmitChList'])
self.states is a dictionary of the current values of the BCI2000 state variables, indexed by name and returning values of type int.
These are the methods of a framework object which you can override when you implement a subclass. The framework then calls these methods automatically at the appropriate times. Hooks are identifiable by their initial character being capitalized. They also comprise many of the definitions which you will build on in your own application/ source implementation. default implementations exist for all of these hooks and do nothing by default. This is where you customize the functionality of your modules.
This is simply there for you to give a short description of what the application is.
The construct defines all of the parameters and states which you want to record and store for your application. Parameters are the things which comprise our application’s functionality. States are essentially event markers. Each state reflects important events during our real-time system operation and are saved to the data file with each associated sample.
Here we set up our screen with which we will later create our visual stimuli on. We also specify things like our screen size, screen ID, and instantiate the actual screen. This is called when "Set Config" is pressed.
This is where we set up stimuli. First we import psychopy and the BCPy2000/Psychopy renderer. This is important to import here so that openGL, which is how psychopy renders stimuli, is executed in the correct thread. We also draw any stimuli(visual, and auditory) and then register all of those stimuli in this definition. We also can add state monitors here which allow for us to have the option for developers to ensure that the application is doing what they want it to do. Developers can use these statemonitors to check a myriad of internal components (states) such as the current block of data that is being written, the current trial, the samples per second, and the frames per second.
This starts the visual stimulus and is called when the "Start" or "Resume" button is pressed. This is where you want to set your stimuli's on state to true.
This is where we define phases using calls to self.phase and self.design. These phases correspond to the states which we set up in the constructor definition. Here we can set the duration and name of each phase as well as what the next phase is supposed to be.
This presents stimuli and updates state variables to record what is going on.
This processes each new signal packet. Which will be recorded in the experiment’s data file.
This is called when we either close the application or reconfigure it. This is where you set all of your states to their off state.