From BCI2000 Wiki
Revision as of 09:00, 5 June 2023 by Nluczak (talk | contribs) (→‎2023-01-31: BCPy2000 2.1)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


BCPy2000 takes the C++ out of BCI2000 programming. It is aimed at developers of new applications and new signal processing methods, providing a platform for rapid, flexible development of experimental Brain-Computer Interface systems in Python. It takes advantage of various high-level Python packages: PsychoPy[1] for stimulus presentation, NumPy[2] and SciPy[3] for signal processing and classification. You can program a python-based application module, signal processing module, or even a signal source module for generating custom test signals and playing back data files. Each module can open an IPython shell in which you can inspect and interact with every aspect of the running system. If you're using a BCPy2000-implemented source module, you can slow the system right down or even step through packet-by-packet, which can help you while you're interactively debugging your python code in one of your other modules with pdb.

BCPy2000 implements a lot of infrastructure that allows you to get an application module running quickly. It also contains a set of optional tools, which are still a work in progress, but which are rapidly turning into a kind of "standard library" of Pythonic signal-processing algorithms and stimulus widgets.

The source code is available under the terms of the GNU General Public License v3.

To learn more, see the BCPy2000 wiki[4]




Nicholas Luczak, Jeremy Hill, Thomas Schreiner, Christian Puzicha, Jason Farquhar

Version History

2023-01-31: BCPy2000 2.1

BCPy2000 now includes a portable installer and an overhaul of the BCPy2000 state machine to enable by-sample access to states and events.

2021-02-9: BCPy2000 2.0

Sixth build release. A complete restructuring of the original BcPy2000 build to support Python 3.6.8. VisionEgg is now deprecated and was replaced with PsychoPy[5]. This version has also been built using a new portable python release[6]. You can find the full documentation here. [7]

2011-07-10: BCPy2000 33960

Fifth build release. Various small bugfixes and improvements, and the downloads now contain BCI2000 v.3.0 binaries

2010-07-08: BCPy2000 17374

Fourth build release. Various bugfixes and tuneups, a few new API methods in the core classes, and lots of new things in the "optional and patchily-documented tools" section.

2009-09-22: BCPy2000 13637

Third build release: Numerous small bugfixes and improvements, and a refactoring of the code to allow the VisionEgg/PyOpenGL back-end to be replaced more easily. Now distributed together with a portable Python distribution.

2009-03-16: BCPy2000 11336

Second release of demo build. The three Python-related core modules are now gnu-compilable and can run on non-Windows platforms. A number of accumulated enhancements, optimizations and bug fixes, including improved precision of sound stimulus timing, and playback of older-style .dat files (bug reported by Marco Rotonda)

2008-09-30: BCPy2000 8570 (also known as 1.0)

Fully integrated framework, with documentation. Higher-level tools are still somewhat patchily documented.

Source Code Revisions

  • Initial development: 2148
  • Tested under: 3396
  • Known to compile under: 3396
  • Broken since: ----


BCPy2000 has whatever parameters you want to define in your own python module implementations. There are a few that it implements in the framework already, however:


This boolean, defined by the application framework, determines whether a signal-packet clock should be shown in the bottom right corner of the screen.


Your experiment need not be trial-based, but there's a flexible and automatic way of keeping track of trials within blocks, and blocks within runs, if you choose to design it that way. The application API method helps you set this up, and this parameter, defined by the application module, specifies the number of trials in a block.


This defaults to 1, so we usually consider a "block" to be the same thing as a "run". However, we once designed an experiment where multiple blocks of trials where recorded continuously in one file, along with the inter-block rest periods. So that had multiple BlocksPerRun. The application API method allows you to configure this.


The default speed at which the Python source module sends its artificial signals through the system. The default value of this parameter, 1.0, means real time.


If you check this, then the PythonSignalProcessing and PythonApplication modules will be rendered unable to change the state variables, and PythonApplication's phase transitions will follow the PresentationPhase state instead of allowing the phase machine to run on its own. This allows recorded experiments to be played back, if you're careful about how they're programmed. Type self.doc('Replay') from one of the IPython prompts for more details.


An arbitrary string describing your Python application module's behaviour, filled in by the self.Description() hook in your BciApplication class implementation.


An arbitrary string describing your Python signal-processing module's behaviour, filled in by the self.Description() hook in your BciSignalProcessing class implementation.


An arbitrary string describing your Python source module's behaviour, filled in by the self.Description() hook in your BciSource class implementation.


BCPy2000 modules have whatever states you want to define for them in your Python implementation. However, the application module framework defines one or two already:


Records the state of the application's "phase machine" as a number. You probably should not rely on the numerical value of this state variable to interpret what was happening, when you read the file back. Instead, define your own state variables with more transparent names, and ensure that your BciApplication.Transition method sets these states accordingly when a transition occurs. Type self.doc('Phase Machine') at one of the modules' IPython prompts for more details.


This is used as a poor substitute for stimulus timing information when a physical synchronization signal is not available. It is set automatically whenever a phase transition occurs, and its value lets you localize that event in the data stream with reasonable precision. Type self.doc('Timing') at one of the BCPy2000 modules' shell prompts for more info.


If you have chosen to implement a trial-based experimental design, this state variable keeps track of the trial number.


If you have chosen to implement multiple blocks per run in your experimetnal design (see the parameter BlocksPerRun) then this keeps track of the block number.