Skip to main content

Signal Analysis Framework For You

Project description

Saffy

Signal Analysis Framework For You

A simple signal analysis framework, which aims at clarity of code and reproducibility of solutions. The plugin architecture aims to encourage building modular code among scientists and data analysts. It provides a basic structure for signal storage and a pipeline for analysis.

Install

pip3 install saffy

From Source

Using a virtualenv is recommended!

Download the package to your project directory

git clone https://github.com/PPierzc/saffy.git

Install dependencies

pip3 install -r ./saffy/requirements.txt

Usage

import saffy
sig = saffy.SignalManager(generator=signal_data)

Basic SignalManager instance structure

field description
fs sampling frequency
num_channels number of channels
channel_names name for each channel
data the signal in the structure of (epoch x channel x signal)
t time vector
epochs number of epochs
tags position of tags in signal
spectrum matrix of spectrum
spectrum_freqs vector of frequencies
phase matrix of phase

SignalManager init function

It takes one labelled argument: generator or filename.

Generator

A dictionary of the structure

data = {
      'fs': # float,
      'num_channels': # integer,
      'channel_names': # list of strings,
      'epochs': # integer,
      't': # time array,
      'tags': # list,
      'data': # Signal Matrix
  }
saffy.SignalManager(generator=data)
Filename

The name of the file generated by Svarog. 3 files eg. data.raw, data.xml, data.tag

saffy.SignalManager(filename='data')

Plugins

Plugins are classes that inherit from the PluginManager. They extend the functionality of the basic Signal Manager. Some plugins are provided out of the box

Filters

Adds basic filters

Graphics

Adds functions to display the signal data

Welch

Calculating the Welch Spectrum

Hilbert

Calculating the Hilbert Transform

Creating Custom Plugins

You might want to add some custom features.

The proposed convention for plugin development is the following. All data that is to be stored extra, should be stored in the form of a dictionary assigned to a variable of the same name as the plugin.

Plugin functions should be preceded by the plugin name.

import saffy

class CustomPlugin(saffy.PluginManager):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.custom = {
            'param': 'some value'
        }

    def custom_function(self):
        # do something
        pass

saffy.SignalManager.register_plugin(CustomPlugin)

sig = saffy.SignalManager(generator=signal_data)

sig.custom_function()

Example

A short example of how to use saffy for EEG data analysis.

def generate_signal():
  data = {
      'fs': 512,
      'num_channels': 3,
      'channel_names': ['C3', 'C4', 'd1'],
      'epochs': 1
  }

  T = 20
  t = np.arange(0, T, 1 / data['fs'])

  mu_freq = 10
  beta_freq = 23
  net_freq = 50

  data['data'] = np.zeros((data['epochs'], data['num_channels'], len(t)))

  for epoch in range(data['epochs']):
    data['data'][epoch][0] += (0.1 * t + 0.1) * sin(t, mu_freq)
    data['data'][epoch][0] += (0.1 * t + 0.1) * sin(t, beta_freq)
    data['data'][epoch][0] += sin(t, net_freq)
    data['data'][epoch][0] += 0.3 * noise(t)

    data['data'][epoch][1] += (0.1 * t + 0.1) * sin(t, mu_freq)
    data['data'][epoch][1] += (0.1 * t + 0.1) * sin(t, beta_freq)
    data['data'][epoch][1] += sin(t, net_freq)
    data['data'][epoch][1] += 0.3 * noise(t)

    data['data'][epoch][2][::5*data['fs']] = 1
    data['data'][epoch][2][0] = 0

  data['t'] = t
  data['tags'] = []

  return data

EEG = saffy.SignalManager(generator=generate_signal())

EEG.set_tags_from_channel('d1')
EEG.remove_channel('d1')

PRE_EEG = EEG.copy('pre')
PRE_EEG.set_epochs_from_tags(-4, -2)

PRE_EEG.welch_spectrum()
PRE_EEG.spectrum = np.mean(PRE_EEG.spectrum, axis=0)
PRE_EEG.spectrum = np.reshape(PRE_EEG.spectrum, (1, *PRE_EEG.spectrum.shape))

POST_EEG = EEG.copy('post')
POST_EEG.set_epochs_from_tags(0.5, 2.5)

POST_EEG.welch_spectrum()
POST_EEG.spectrum = np.mean(POST_EEG.spectrum, axis=0)
POST_EEG.spectrum = np.reshape(POST_EEG.spectrum, (1, *POST_EEG.spectrum.shape))

fig, ax = plt.subplots(
    nrows=max([PRE_EEG.num_channels, POST_EEG.num_channels]),
    ncols=1,
    sharex=True,
    sharey=True,
    figsize=(10, 10)
)

PRE_EEG.graphics_spectrum_plot(
    fig,
    ax,
    'Change',
    label='Pre'
)

POST_EEG.graphics_spectrum_plot(
    fig,
    ax,
    color='#0000ff',
    label='Post'
)

for a in ax:
  a.legend()

plt.show()
plt.close()

alt text

Contributing

If you like the project and want to add something to it then please create a pull request.

  • The title should shortly summarize the goal of your addition
  • In the description go in depth with the changes you have made and why.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for saffy, version 0.1.12
Filename, size File type Python version Upload date Hashes
Filename, size saffy-0.1.12-py3-none-any.whl (11.1 kB) File type Wheel Python version py3 Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page