npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@neurosity/pipes

v5.2.1

Published

Digital signal processing utilities as RxJS operators for working with EEG data in Node and the Browser

Downloads

395

Readme

EEG Pipes

By Neurosity

Blazing fast EEG transformers implemented as "Pipeable" RxJS operators for Node and the Browser.

Features include:

  • FFT
  • PSD and Power Bands
  • Buffering and Epoching
  • IIR Filters
  • Signal Quality (new)
  • and more.

Read full documentation

Get started by installing the library:

npm install @neurosity/pipes

Getting started

npm install @neurosity/pipes

Then import the module

ESM
import { epoch } from "@neurosity/pipes";
Node
const { epoch } = require("@neurosity/pipes");
Browser
<script type="module">
  import { epoch } from "./node_modules/neurosity/pipes/esm/eeg-pipes.mjs";
</script>
<script nomodule src="./node_modules/neurosity/pipes/browser/eeg-pipes.js">
Electron
import { epoch } from "@neurosity/pipes/dist/electron";

Usage

An Observable of EEG data is required to work with pipes. This can be done by using fromEvent from RxJS in order to push callback events into an Observable stream.

Given a callback-driven API such as:

bci.on("data", () => { ... });

Then...

import { fromEvent } from "rxjs";

const eeg$ = fromEvent(bci, "data");

Now we have an Observable of EEG data that support Pipeable operators.

eeg$.pipe().subscribe();

The following are some libraries that provide EEG as RxJS observables out of the box:

Pipes can be added to an EEG observable of EEG data samples with the following data structure:

{
  data: [Number, Number, Number, Number], // channels
  timestamp: Date,
  info?: {
  	samplingRate?: Number,
  	channelNames?: [String, String, String, String],
  	..
  }
};

Individual samples of EEG data contain an array of values for each EEG channel as well as a timestamp. An additional info object containing metadata about the EEG stream such as sampling rate and channel names can also be included or added with the addInfo operator.

Import the pipes from the module:

import { epoch, fft, alphaPower } from "@neurosity/pipes";

Add to RxJS observable pipe:

eeg$
  .pipe(
    epoch({ duration: 256, interval: 100 }),
    fft({ bins: 256 }),
    alphaPower()
  )
  .subscribe((alphaPower) => console.log(alphaPower));

Pipes

Filtering (IIR)

Filter pipes can be applied to both samples or buffers of samples. Filters are linear IIR filters using a digital biquad implementation.

  • lowpassFilter({ nbChannels, cutoffFrequency })
  • highpassFilter({ nbChannels, cutoffFrequency })
  • bandpassFilter({ nbChannels, cutoffFrequencies: [lowBound, highBound] })
  • notchFilter({ nbChannels, cutoffFrequency })

Optional Parameters:
characteristic: 'butterworth' or 'bessel'. Default is butterworth characteristic because of its steeper cutoff
order: the number of 2nd order biquad filters applied to the signal. Default is 2.
samplingRate: should match the samplingRate of your EEG device. Default is 250

Frequency

  • bufferFFT({ bins, window, samplingRate })
  • alphaPower()
  • betaPower()
  • deltaPower()
  • gammaPower()
  • thetaPower()
  • averagePower()
  • sliceFFT([ min, max ])
  • powerByBand()

Unit conversion

  • voltToMicrovolts({ useLog })

Utility

  • epoch({ duration, interval, samplingRate })
  • bufferCount()
  • bufferTime()
  • bufferToEpoch({ samplingRate })
  • pickChannels({ channels: [c1, c2, c3] })
  • removeChannels({ channels: [c1, c2, c3] })
  • addInfo()
  • addSignalQuality()
    • signal quality is represented as standard deviation value for each channel
  • samples() // epoch to samples
  • concatEpochs()
  • dynamicBuffer({ minSamples: number, maxSamples: number, incrementCountBy: number })

Coming soon

Filtering

  • vertScaleFilter()
  • vertAgoFilter()
  • smoothFilter()
  • polarityFilter()
  • maxFrequencyFilter()

Data Structures

Sample

This is the simplest, core data structure for individual samples of EEG data. Samples have a data array containing a single reading from a number of different EEG electrodes along with a single timestamp. Samples can also contain optional other parameters added by the addInfo operator. The design for this comes directly from the discussion on the EEG stream data models repo.

{
    data: [Number, ..., Number], // length == nbChannels
    timestamp: <Number>,
    info?: {
  	  samplingRate?: Number,
  	  channelNames?: [String, String, String, String],
  	...
  }
}

Epoch

An Epoch represents the EEG data that has been collected over a specific period of time. They can be produced by using either the epoch operator or by using a standard RxJS buffering operator such as bufferTime followed by the bufferToEpoch operator. Collecting data in this way is necessary for performing frequency-based analyses and, in many cases, will improve performance of filtering and other downstream operations. Epochs contain a 2D data array (channels x samples) and an info object that always includes samplingRate and startTime data so that the timestamps of individual samples can be derived.

{
    data: [
        [Number, ... , Number], // length == duration
        [Number, ... , Number]
    ], // length == nbChannels
    info: {
        samplingRate: Number,
        startTime: Number,
        channelNames?: [String, ..., String ]
    }
}

Power Spectral Density or PSD: Proposed Work in Progress

A PSD represents the absolute power of different frequency bins in an Epoch of EEG data. PSDs are produced by applying the fft operator to Epochs or using the bufferFFT operator directly on a stream of EEG Samples. PSDs contain an array of frequencies and a corresponding array of spectral power at each of those frequencies, as well as an info object that contains samplingRate and startTime info similarly to Epochs.

{
    psd: [
        [Number, ... , Number] // spectral power; length = freqs.length
    ], // length = numChannels
    freqs: [Number, ... , Number], // length = fftLength / 2
    info: {
        samplingRate: Number,
        startTime: Number,
        channelNames?: [String, ..., String ]
    }
}

Generating documentation

To generate the docs, run npm run build:docs