BrainBit foe developers Subscribe for updates Visit website

Tutorial Swift


Platform requirements

OS: macOS Catalina

Software: Xcode 11

IOS minimal version: 11.0

Framework: neurosdk.framework-

Dependencies: libc++.tbd, CoreBluetooth.framework


Adding Frameworks to Your Xcode Project

  1. Select the project file from the project navigator on the left side of the project window.
  2. Select the target for where you want to add frameworks in the project settings editor.
  3. Select the “Build Phases” tab, and click the small triangle next to “Link Binary With Libraries” to view all of the frameworks in your application.
  4. To Add frameworks, click the “+” below the list of frameworks.
  5. To select multiple frameworks, press and hold the command key while using the mouse to click the desired frameworks.
  6. Copy framework to target. Select "Build Phases" tab, and click "Copy Files", select "Destination to "Framework" and add framework click the "+" below the list of copy files.

Scanning for devices

First of all to find nearby devices you need to create global variable of NTDeviceEnumerator

let scanner = NTDeviceEnumerator(deviceType: .TypeBrainbit)

You can specify which type of device you're looking for by deviceType (TypeBrainbit, TypeCallibri,TypeAny). Instance of NTDeviceEnumerator has subscribeFoundDevice event will hit when a new device appears.

Note:    Make sure your instance lifetime is enough to find new device. For example your enumerator variable is a private field of the class 

Warn:   Searching for device only when object NTDeviceEnumerator exists in memory 

scanner.subscribeFoundDevice { (deviceInfo) in
    self.device = NTDevice(enumerator: self.scanner, deviceInfo: deviceInfo)

 Here we insert closure and if new device will be detected you received NTDeviceInfo

 Note: Remember to create new NTDevice you new NTDeviceInfo and NTDeviceEnumerator

 Warn: All subscribers are run in separate thread. Be careful when call ui-based code

Connecting to the device

To receive data from the device and to send commands to it first you need to connect to it


You could read the device state to check whether it is connected or not. You also could subscribe subscribeParameterChanged event to receive notifications when the device goes out of range.

device?.subscribeParameterChanged(subscriber: { (param) in
    if(param == .state) {
        let state = device.state()
        if( state == .connected) {
        } else {

Note: All possible properties you can find at neurosdk.framework/Headers/NTDevice+Extension.h line 118

When the device is connected you could read lists of supported parameters, signal channels, available commands. You could read the device name and address in string format and firmware version.

let state = device.state()
let name =
let address = device.address()

To get a list of command and channels use appropriate properties.

for ch in device.channels {
for p in device.parameters {
for c in device.commands {

Retrieving signal data

For Brainbit device, actual channels are Signal, Battery and Resistance. To get channel records from the device with a specific type, DeviceTraits class could be used. To subscribe for new data notifications Use subscribeLengthChanged method of channel class. There are four commands for managing device measuring state: StartSignal, StopSignal, StartResist, StopResist.

if NTDeviceTraits.hasChannels(withType: device, channelType: .battery) {
  self.batteryChannel = NTBatteryChannel(device: device)
if NTDeviceTraits.hasChannels(withType: device, channelType: .MEMS) {
 self.memsChannel = NTMEMSChannel(device: device)

if NTDeviceTraits.hasChannels(withType:device, channelType: .signal) {
  self.eegs = NTDeviceTraits.getChannelInfoArray(withType: device, channelType: .signal).map{ it in
  return NTEegChannel(device: device, channelInfo: it)

Battery data channel contains data as int values, Resistance and Signal channels as double values. Write callback methods to handle new data. Information about the channel which triggered a notification.

self.batteryChannel?.subscribeLengthChanged(subscribe: { length in
   let level = self.batteryChannel?.readData(offset: length-1, length: 1).first
self.eegs.forEach { signal in
 signal?.subscribeLengthChanged(subscribe: { (length) in
       let newdata = signal?.readData(offset: length-1, length: 1).first

Channel buffers collection

There is a set of different channel buffers for storing and processing signal data. All channel buffers need to be disposed after work is finished.

//Resistance channel. Receives and stores information about the resistance of electrodes
let resistanceChannel = NTResistanceChannel(device, info)

//Bipolar channel. Calculates the difference between two EEG (or simple signal) channels. 
//Could be used to reduce some types of artifacts
let bipolarChannel = NTBipolarDoubleChannel(eegChannel1, eegChannel2);

//Spectrum channel. Calculates signal spectrum for a selected signal region.
//readData returns array with spectrum samples of length provided in SpectrumLength property
//offset and length parameters relate to source signal channel which was used to make spectrum channel
let spectrumChannel = NTSpectrumChannel(eegChannel1, .WindowBlackman)
let frequencyStep = spectrumChannel.hzPerSpectrumSample

//Spectrum power channel. Calculates and stores a power of spectrum on a selected frequency band
//You could use several spectrum channels for spectrum power calculation. Results will be joined into one
let seconds: Int = 10
let lowFreq: Float = 8.0
let highFreq: Float = 14.0
let spectrumPowerChannel = NTSpectrumPowerDoubleChannel(channel: [spectrumChannel], lowFreq: lowFreq, highFreq: highFreq, duration: Double(seconds))

Emulation of device

If you don’t have Brainbit device yet, you could try all signal processing features using emulation channel. You need to provide spectral components of an emulation signal to create this channel. You could use this channel for all calculations that receive channels of doubles.

let emulationChannel = NTEmulationDoubleChannel(
                                           components: [NTEmulationSine(amplV: 100e-6, freq: 10, phase: 0)],
                                           sample_freq: 250, lendgth: 2000) //8 seconds of
//create eeg channel based on NTEmulationChannel
let eeg = NTEegChannel(baseChannel: emulationEeg)

emulationChannel.startTimer(); //begins emulation of receiving new signal