Skip to content

Commit

Permalink
Examples:ECG-Analysis+EEGSynth (#309)
Browse files Browse the repository at this point in the history
* ecg analysis script

* eegsynth application example

---------

Co-authored-by: caurnhammer <christoph@mentalab.com>
  • Loading branch information
caurnhammer and caurnhammer authored Dec 9, 2024
1 parent 0af8e32 commit 26fc1c4
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 0 deletions.
Binary file added examples/eegsynth_demo/MentalabEEGSynth.vcv
Binary file not shown.
10 changes: 10 additions & 0 deletions examples/eegsynth_demo/buffer.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[general]
debug=2
delay=0.010

[redis]
hostname=localhost
port=6379

[fieldtrip]
port=1972,1973,1974
17 changes: 17 additions & 0 deletions examples/eegsynth_demo/historycontrol.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[general]
debug=2

[redis]
hostname=localhost
port=6379

[history]
window=10
; window length for smoothing (s)
stepsize=0.05
; update time (s)

[input]
; control values to plot, separated by comma
freeze=0
channels=spectral.channel1.alpha,spectral.channel2.theta,spectral.channel2.beta
16 changes: 16 additions & 0 deletions examples/eegsynth_demo/lsl2ft.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[general]
debug=1

[fieldtrip]
hostname=localhost
port=1972

[redis]
hostname=localhost
port=6379

[lsl]
; this can be used to select the desired stream (in case there are multiple)
name=
type=ExG
timeout=30 ; in seconds
33 changes: 33 additions & 0 deletions examples/eegsynth_demo/outputmidi_loopback.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[general]
debug=1
delay=0.05
monophonic=1 ; boolean

[redis]
hostname=localhost
port=6379

[midi]
device=IAC Driver Bus 1
channel=1

[control]
; you can specify different MIDI message types here: controlXXX, noteXXX, polytouchXXX, aftertouch, pitchwheel, start, continue, stop, reset, note

[trigger]
; you can specify different MIDI message types here: controlXXX, noteXXX, polytouchXXX, aftertouch, pitchwheel, start, continue, stop, reset, note
note=post.channel1.alpha
start=post.channel1.alpha

[duration]
note=0.5 ; the note will be switched off after the specified time (in seconds)

[velocity]

[scale]
; scale and offset can be used to map Redis values to MIDI values between 0 to 127
; the default scale for all channels is 127

[offset]
; the default offset for all channels is 0
note=40
33 changes: 33 additions & 0 deletions examples/eegsynth_demo/outputmidi_loopback_2.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[general]
debug=1
delay=0.05
monophonic=1 ; boolean

[redis]
hostname=localhost
port=6379

[midi]
device=IAC Driver Bus 2
channel=1

[control]
; you can specify different MIDI message types here: controlXXX, noteXXX, polytouchXXX, aftertouch, pitchwheel, start, continue, stop, reset, note

[trigger]
; you can specify different MIDI message types here: controlXXX, noteXXX, polytouchXXX, aftertouch, pitchwheel, start, continue, stop, reset, note
note=post.channel2.thetabetaratio
start=post.channel2.thetabetaratio

[duration]
note=0.5 ; the note will be switched off after the specified time (in seconds)

[velocity]

[scale]
; scale and offset can be used to map Redis values to MIDI values between 0 to 127
; the default scale for all channels is 127

[offset]
; the default offset for all channels is 0
note=40
23 changes: 23 additions & 0 deletions examples/eegsynth_demo/postprocessing.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[general]
delay=0.05
debug=2

[redis]
hostname=localhost
port=6379

[initial]
; here you can specify the initial values of some control values

[input]
; the keys here can have an arbitrary name, but should map those in the output section
; the keys must be lower-case. values should not contain an equation, only one-to-one mappings
alpha_1=spectral.channel1.alpha
theta_2=spectral.channel2.theta
beta_2=spectral.channel2.beta

[output]
; besides +, -, /, *, the equations also support log, log2, log10, exp, power from numpy
; and compress, limit, rescale, normalizerange, normalizestandard from EEGsynth
post.channel1.alpha = limit(alpha_1 / 1750, 0, 0.8)
post.channel2.thetabetaratio = limit(theta_2/beta_2 / 6, 0, 0.9)
36 changes: 36 additions & 0 deletions examples/eegsynth_demo/preprocessing.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[general]
delay=0.10
debug=1

[redis]
hostname=localhost
port=6379

[input_fieldtrip]
hostname=localhost
port=1972
timeout=30

[output_fieldtrip]
hostname=localhost
port=1973

[processing]
window=0.12
;smoothing=0.2
reference=none
lowpassfilter=45
highpassfilter=2
filterorder=511
;downsample=1
notchfilter=50

[scale]
highpassfilter=1
lowpassfilter=1
notchfilter=1

[offset]
highpassfilter=0
lowpassfilter=0
notchfilter=0
5 changes: 5 additions & 0 deletions examples/eegsynth_demo/push2lsl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import explorepy

expdev = explorepy.Explore()
expdev.connect("Explore_AAAI")
expdev.push2lsl()
47 changes: 47 additions & 0 deletions examples/eegsynth_demo/spectral.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[general]
debug=2
delay=0.1

[redis]
hostname=localhost
port=6379

[fieldtrip]
hostname=localhost
port=1973
timeout=30

[input]
; this specifies the channels from the FieldTrip buffer
; the channel names (on the left) can be specified as you like
channel1=1
channel2=2
; channel3=3
; channel4=4
; channel5=5
; channel6=6
; channel7=7
; channel8=8

[processing]
; the sliding window is specified in seconds
window=5.0

[scale]
window=1

[offset]
window=0

[band]
; the frequency bands can be specified as you like, but must be all lower-case
; you should give the lower and upper range of each band
delta=2-5
theta=5-8
alpha=8-12
beta=12-30
gamma=35-45

[output]
; the results will be written to Redis as "spectral.channel1.alpha" etc.
prefix=spectral
46 changes: 46 additions & 0 deletions examples/wiki-ecg-analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import neurokit2 as nk
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import pyedflib

def edf_to_arr(edf_path):
f = pyedflib.EdfReader(edf_path)
n = f.signals_in_file
signal_labels = f.getSignalLabels()
sigbufs = np.zeros((n, f.getNSamples()[0]))
for i in np.arange(n):
sigbufs[i, :] = f.readSignal(i)

return sigbufs

data = edf_to_arr("../data/wiki-ECG-resting_ExG.bdf") # read in bdf file
data = data[1] # channel 1 holds ECG data
data *= 1e-3 # scale uV to mV for ECG analysis in neurokit
ecg_signals, info = nk.ecg_process(data[5000:25000], sampling_rate=250) # convert

rpeaks = info["ECG_R_Peaks"]
cleaned_ecg = ecg_signals["ECG_Clean"]

intervalrelated = nk.ecg_intervalrelated(ecg_signals)
intervalrelated.iloc[0,1:83]

nk.ecg_plot(ecg_signals, info)
fig = plt.gcf()
fig.set_size_inches(20, 12, forward=True)
fig.savefig("../plots/resting_ecg.png")

ecg_signals, info = nk.ecg_process(data[18000:20000] , sampling_rate=250) # take a subset from the middle of recording and apply neurokit
rpeaks = info["ECG_R_Peaks"]
cleaned_ecg = ecg_signals["ECG_Clean"]
plot = nk.events_plot(rpeaks, cleaned_ecg[0:cleaned_ecg.shape[0]])
fig = plt.gcf()
fig.set_size_inches(20, 12, forward=True)
fig.savefig("../plots/resting_rpeaks.png")

peaks, info = nk.ecg_peaks(data[5000:25000], sampling_rate=250)
hrv_time = nk.hrv_time(peaks, sampling_rate=250, show=True)
hrv_time
fig = plt.gcf()
fig.set_size_inches(20, 12, forward=True)
fig.savefig("../plots/sv_ecg_time.png")

0 comments on commit 26fc1c4

Please sign in to comment.