BrainBit for developers Subscribe for updates Visit website

Spectrum

Mathematical library for calculating the signal spectrum

Overview

The main functionality is the calculation of raw spectrum values and the calculation of EEG spectrum values.
Working with the library is possible in iterative mode (adding new data to the internal buffer, calculating spectrum values) and in one-time spectrum calculation mode for a given array. When working in the iterative mode, the spectrum is calculated with the frequency set during initialization.

Install

Download from [GitHub](https://github.com/BrainbitLLC/spectrum-lib-cpp) all folders and add .dll to your project by your preferred way.
            
Download from [GitHub](https://github.com/BrainbitLLC/spectrum-lib-cpp) and add .so from folder `linux_x86_64` to your project by your preferred way.
							   
Library buit on Astra Linux CE 2.12.46, kernel 5.15.0-70-generic. Arch: x86_64 GNU/Linux
							   

```
user@astra:~$ ldd --version
ldd (Debian GLIBC 2.28-10+deb10u1) 2.28
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
```

That library depends from others library, for instance:
```
linux-vdso.so.1
libblkid.so.1
libc++.so.1
libc++abi.so.1 
libc.so.6
libdl.so.2
libffi.so.6
libgcc_s.so.1
libgio-2.0.so.0
libglib-2.0.so.0
libgmodule-2.0.so.0
libgobject-2.0.so.0
libm.so.6
libmount.so.1
libpcre.so.3
libpthread.so.0
libresolv.so.2 
librt.so.1
libselinux.so.1
libstdc++.so.6
libudev.so.1
libuuid.so.1
libz.so.1
ld-linux-x86-64.so.2
```

If you are using a OS other than ours, these dependencies will be required for the library. You can download dependencies from [here](https://github.com/BrainbitLLC/linux_neurosdk2/tree/main/dependencies).
            
The Android version is designed for APIs >= 21.

Neurosdk for android is distributed using JitPack as an aar library. Here is an example of adding SDK to an AndroidStudio project using gradle:

Add to `build.gradle` of project:			   																					  

```
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
```

and to `build.gradle` of app:
																										   
```
dependencies {
    implementation 'com.github.BrainbitLLC:SpectrumLib:version'
}
```

To prevent build errors add to build.gradle this settings:								  

```groovy
android {
    packagingOptions {
        pickFirst 'lib/x86_64/libc++_shared.so'
        pickFirst 'lib/x86_64/libfilters.so'
        pickFirst 'lib/x86/libc++_shared.so'
        pickFirst 'lib/x86/libfilters.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libfilters.so'
        pickFirst 'lib/armeabi-v7a/libfilters.so'
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
    }
    ...
}
```
            
The iOS version is designed for OS >= 12.0.
		 
By Pods:

Add to Podspec file:
																																																								   
```
pod 'spectrumlib', '1.0.1'
```

And run `pod install` command.

You can install framework manually:						   
1. dowload `spectrumlib.xcframework` from [GitHub](https://github.com/BrainbitLLC/apple_spectrumlib)
2. add `spectrumlib.xcframework` to `Frameworks, Libraries, and Embedded Content` section of your project
3. set `Embedded` to `Embed & Sign`

Latest version: `1.0.1`
            
> Python package available only for Windows

By pip:

```
pip install pyspectrum_lib
```

The package has the following structure:
 - spectrum_lib - the main package with the implementation of methods
 - libs - contain dll library files

SpectrumMath - one main module contains all methods of library

```python
from spectrum_lib import SpectrumMath
```
            
Coming soon...
            
Coming soon...
            
Install latest version `SpectrumLib` package from NuGet Gallery in your preferred way.
            

Initialization

Main parameters

  1. Raw signal sampling frequency. Need to be >= 1.
  2. Spectrum calculation frequency. Need to be <= 16 kHz.
  3. Spectrum calculation window length. Need to be <= signal sampling frequency.


Optional parameters

  1. Upper bound of frequencies for spectrum calculation. Default value is sampling_rate / 2.
  2. Normalization of the EEG spectrum by the width of the wavebands. Disabled by default.
  3. Weight coefficients for alpha, beta, theta, gamma, delta waves. By default has 1.0 value.


Creation 

int sampling_rate = 250; // raw signal sampling frequency
int fft_window = 1000; // spectrum calculation window length
int process_win_rate = 5; // spectrum calculation frequency
SpectrumMath* tSpectMathPtr = createSpectrumMath(sampling_rate, fft_window, process_win_rate);
            
int samplingRate = 250; // raw signal sampling frequency
int fftWindow = 1000; // spectrum calculation window length
int processWinRate = 5; // spectrum calculation frequency
SpectrumMath math = new SpectrumMath(samplingRate, fftWindow, processWinRate);
            
int samplingRate = 250; // raw signal sampling frequency
int fftWindow = 1000; // spectrum calculation window length
int processWinRate = 5; // spectrum calculation frequency
SpectrumMath math = new SpectrumMath(samplingRate, fftWindow, processWinRate);
            
sampling_rate = 250 # raw signal sampling frequency
fft_window = sampling_rate * 4 # spectrum calculation window length
process_win_rate = 5 # spectrum calculation frequency
spectrum_math = SpectrumMath(sampling_rate, fft_window, process_win_rate)
            
let samplingRate: Int32 = 250 // raw signal sampling frequency
let fftWindow = samplingRate * 4 // spectrum calculation window length
let processWinRate: Int32 = 10 // spectrum calculation frequency
var math = SMSpectrumMath(sampleRate: samplingRate, andFftWindow: fftWindow, andProcessWinFreq: processWinRate)
            
int sampling_rate = 250; // raw signal sampling frequency
int fft_window = 1000; // spectrum calculation window length
int process_win_rate = 5; // spectrum calculation frequency
SMSpectrumMath* math = [[SMSpectrumMath alloc] initWithSampleRate:sampling_rate andFftWindow:fft_window andProcessWinFreq:process_win_rate];
            

            

            

  

Optional initialization

1. Additional spectrum settings: 

int bord_frequency = 50; // upper bound of frequencies for spectrum calculation
bool normalize_spect_by_bandwidth = true; // normalization of the EEG spectrum by the width of the wavebands
SpectrumMathInitParams(tSpectMathPtr, bord_frequency, normalize_spect_by_bandwidth);
            
int bordFrequency = 50; // upper bound of frequencies for spectrum calculation
bool normalizeSpectByBandwidth = true; // normalization of the EEG spectrum by the width of the wavebands
math.InitParams(bordFrequency, normalizeSpectByBandwidth);
            
int bordFrequency = 50; // upper bound of frequencies for spectrum calculation
boolean normalizeSpectByBandwidth = true; // normalization of the EEG spectrum by the width of the wavebands
math.initParams(bordFrequency, normalizeSpectByBandwidth);
            
bord_frequency = 50 # upper bound of frequencies for spectrum calculation
normalize_spect_by_bandwidth = True # normalization of the EEG spectrum by the width of the wavebands
pectrum_math.init_params(bord_frequency, normalize_spect_by_bandwidth)
            
let bordFrequency = 50 // upper bound of frequencies for spectrum calculation
let normalze = true // normalization of the EEG spectrum by the width of the wavebands
math.initParams(withUpBorderFreq: bordFrequency, andNormilize: normalze)
            
int bord_frequency = 50; // upper bound of frequencies for spectrum calculation
bool normalize_spect_by_bandwidth = true; // normalization of the EEG spectrum by the width of the wavebands
[math initParamsWithUpBorderFreq:bord_frequency andNormilize:normalize_spect_by_bandwidth];
            

            

            

  

2. Waves coefficients:

double delta_coef = 0.0;
double theta_coef = 1.0;
double alpha_coef = 1.0;
double beta_coef = 1.0;
double gamma_coef = 0.0;
SpectrumMathSetWavesCoeffs(tSpectMathPtr, delta_coef, theta_coef, alpha_coef, beta_coef, gamma_coef);
            
double alphaCoef = 1.0;
double betaCoef  = 1.0;
double deltaCoef = 0.0;
double gammaCoef = 0.0;
double thetaCoef = 1.0;
math.SetWavesCoeffs(deltaCoef, thetaCoef, alphaCoef, betaCoef, gammaCoef);
            
double alphaCoef = 1.0;
double betaCoef  = 1.0;
double deltaCoef = 0.0;
double gammaCoef = 0.0;
double thetaCoef = 1.0;
math.setWavesCoeffs(deltaCoef, thetaCoef, alphaCoef, betaCoef, gammaCoef);
            
delta_coef = 0.0
theta_coef = 1.0
alpha_coef = 1.0
beta_coef = 1.0
gamma_coef = 0.0
spectrum_math.set_waves_coeffs(delta_coef, theta_coef, alpha_coef, beta_coef, gamma_coef)
            
let alphaCoeff = 1.0
let betaCoeff = 1.0
let deltaCoeff = 0.0
let thetaCoeff = 1.0
let gammaCoeff = 0.0
math.setWavesCoeffsWithDelta(deltaCoeff, andTheta: thetaCoeff, andAlpha: alphaCoeff, andBeta: betaCoeff, andGamma: gammaCoeff)
            
double delta_coef = 0.0;
double theta_coef = 1.0;
double alpha_coef = 1.0;
double beta_coef = 1.0;
double gamma_coef = 0.0;
[math setWavesCoeffsWithDelta:delta_coef andTheta:theta_coef andAlpha:alpha_coef andBeta:beta_coef andGamma:gamma_coef];
            

            

            

3. Setting the smoothing of the spectrum calculation by Henning (by default) or Hemming window: 

SpectrumMathSetHanningWinSpect(tSpectMathPtr); // by Hanning (by default)

SpectrumMathSetHammingWinSpect(tSpectMathPtr); // by Hamming
            
math.SetHanningWinSpect(); // by Hanning (by default)

math.SetHammingWinSpect(); // by Hamming
            
math.setHanningWinSpect(); // by Hanning (by default)

math.setHammingWinSpect(); // by Hamming
            
spectrum_math.set_hanning_win_spect() # by Hanning (by default)

spectrum_math.set_hamming_win_spect() # by Hamming
            
math.setHammingWinSpect() // by Hanning (by default)
            
math.setHanningWinSpect() // by Hamming
            
[math setHammingWinSpect]; // by Hanning (by default)

[math setHanningWinSpect]; // by Hamming
            

            

            

 

 

Initializing a data array for transfer to the library

Array of double values with length less or equals then 15 * signal sampling frequency.

 

Types

RawSpectrumData

Structure containing the raw spectrum values (with boundary frequency taken into library).

Fields:

  • all_bins_nums - Integer value. Number of FFT bars. Contained only in the C++ interface.
  • all_bins_values - Double array. Raw FFT bars values.
  • total_raw_pow - Double value. Total raw spectrum power.

 

WavesSpectrumData

Structure containing the waves values.

Absolute frequency values (double type):

  • delta_raw
  • theta_raw
  • alpha_raw
  • beta_raw
  • gamma_raw

Relative (percent) values (double type):

  • delta_rel
  • theta_rel
  • alpha_rel
  • beta_rel
  • gamma_rel

 

FFT band resolution

The library automatically matches the optimal buffer length (degree 2) to calculate the FFT during initialization, depending on the specified window length. Receiving resolution for the FFT bands (number of FFT bands per 1 Hz):

double fftBinsFor1Hz = SpectrumMathGetFFTBinsFor1Hz(tSpectMathPtr);
            
double fftBinsFor1Hz = math.GetFFTBinsFor1Hz();
            
double numberBinsFor1Hz = math.getFFTBinsFor1Hz();
            
fft_bins = spectrum_math.get_fft_bins_for_1_hz()
            
let fftBins = math.getFFTBinsFor1Hz()
            
[math getFFTBinsFor1Hz];
            

            

            

   

Spectrum calculation in iterative mode

1. Adding and process data: 

double* raw_data = new double[SIGNAL_SAMPLES_COUNT];
SpectrumMathPushData(tSpectMathPtr, raw_data, SIGNAL_SAMPLES_COUNT);
SpectrumMathProcessData(tSpectMathPtr);
            
double[] samples = new double[SIGNAL_SAMPLES_COUNT];
math.PushData(samples);
// data processing into PushData method
            
double[] samples = new double[SIGNAL_SAMPLES_COUNT];
math.pushData(data);
            
samples = [0 for _ in range(sample_count)]
spectrum_math.push_data(samples)
spectrum_math.process_data()
            
var samples: [NSNumber] = []
math.pushAndProcessData(samples)
            
NSArray<NSNumber*>* samples = [NSArray new];
[math pushAndProcessData:samples];
            

            

            

  

2. Getting the results:

uint32_t arr_sz = SpectrumMathReadSpectrumArrSize(tSpectMathPtr);

RawSpectrumData* raw_spect_data = new RawSpectrumData[arr_sz];
SpectrumMathReadRawSpectrumInfoArr(tSpectMathPtr, raw_spect_data, &arr_sz);

WavesSpectrumData* waves_spect_data = new WavesSpectrumData[arr_sz];
SpectrumMathReadWavesSpectrumInfoArr(tSpectMathPtr, waves_spect_data, &arr_sz);
            
var rawSpectrumData   = _math.ReadRawSpectrumInfoArr();
var wavesSpectrumData = _math.ReadWavesSpectrumInfoArr();
            
RawSpectrumData[] rawSpectrumData = math.readRawSpectrumInfoArr();
WavesSpectrumData[] wavesSpectrumData = math.readWavesSpectrumInfoArr();
            
raw_spectrum_data = spectrum_math.read_raw_spectrum_info_arr()
waves_spectrum_data = spectrum_math.read_waves_spectrum_info_arr()
            
let rawSpectrumData = math.readWavesSpectrumInfoArr()
let wavesSpectrumData = math.readWavesSpectrumInfoArr()
            
NSArray<SMRawSpectrumData*>* rawSpectrumData = [math readRawSpectrumInfoArr];
NSArray<SMWavesSpectrumData*>* wavesSpectrumData = [math readWavesSpectrumInfoArr];
            

            

            

 

3. Updating the number of new samples. Is necessary for correct calculation of elements in the array of obtained structures, if a large portion of data is added to the library all at once.

SpectrumMathSetNewSampleSize(tSpectMathPtr);
            
math.SetNewSampleSize();
            
math.setNewSampleSize();
            
spectrum_math.set_new_sample_size()
            
math.setNewSampleSize()
            
[math setNewSampleSize];
            

            

            

 

Spectrum calculation for a single array

1. Compute spectrum:

double* vals_arr = new double[arr_size];
SpectrumMathComputeSpectrum(tSpectMathPtr, vals_arr, arr_size);
            
double[] samples = new double[SIGNAL_SAMPLES_COUNT];
math.ComputeSpectrum(samples);
            
double[] samples = new double[SIGNAL_SAMPLES_COUNT];
math.computeSpectrum(samples);
            
samples = [0 for _ in range(sample_count)]
spectrum_math.compute_spectrum(samples)
            
var samples: [NSNumber] = []
math.computeSpectrum(samples)
            
NSArray<NSNumber*>* samples = [NSArray new];
[math computeSpectrum:samples];
            

            

            

 

2. Getting the results:

RawSpectrumData raw_spect_data;
SpectrumMathReadRawSpectrumInfo(tSpectMathPtr, &raw_spect_data);

WavesSpectrumData waves_spect_data;
SpectrumMathReadWavesSpectrumInfo(tSpectMathPtr, &waves_spect_data)
            
RawSpectrumData data = math.ReadRawSpectrumInfo();
WavesSpectrumData waves = math.ReadWavesSpectrumInfo();
            
RawSpectrumData rawSpectrumData = math.readRawSpectrumInfo();
WavesSpectrumData wavesSpectrumData = math.readWavesSpectrumInfo();
            
raw_spectrum_data = spectrum_math.read_raw_spectrum_info()
waves_spectrum_data = spectrum_math.read_waves_spectrum_info()
            
let rawSpectrumData = value.readRawSpectrumInfo()
let wavesSpectrumData = value.readWavesSpectrumInfo()
            
SMRawSpectrumData* rawSpectrumData = [math readRawSpectrumInfo];
SMWavesSpectrumData* wavesSpectrumData = [math readWavesSpectrumInfo];
            

            

            

 

Finishing work with the library

SpectrumMathClearData(tSpectMathPtr);
            
math.ClearData();
            
math.clearData();
            
del math
            
math = nil
            
math = nil;