# Event Classification Processor, Version 2.4
#
# This classifier detects high-frequency activity in EEG. It is designed to ignore
# the low-frequency activity and pick out high-frequency oscillations, bursts, hiss
# or spikes. The event band should include the spectrum of the high frequency events
# with some room to spare. If the hiss is at 100 Hz, put the lower edge of the event
# band no higher than 80 Hz. The event-band filtering is like a high-pass filter at
# its lower end, and high-pass filters produce ringing when excited by spikes. We do
# not want to confuse the ringing of a spike with a high-frequency oscillation. The
# processor includes a baseline power calibrator, which we can run on the EEG recording
# for a while before we go back and start storing characteristics to disk.
#
# The processor produces three metrics. The event power metric is a measure of the
# ratio of the event-band power to the baseline power. Purity is a measure of how
# concentrated the high-frequency power is around a center frequency. A pure sinusoid
# will be concentrated in only one component. A high-frequency oscillation can be
# concentrated in a half-width of ten percent of its center frequency.
#
# Intermittencyis a measure of the power of the demodulated high-frequency signal.
# If we look at the amplitude envelope of the high-frequency signal, and take its
# fourier transform so as to filter the envelope, we obtain the intermittency signal.
# The power of this signal compared to the power of the original high-frequency signal
# is an indication of how intermittent the high-frequency power is in the interval.
#
# Set up the Neuroarchiver's fourier transform and playback interval. Remove or alter
# this code if you want to change the interval the processor looks at.
set config(window_fraction) "0.1"
set config(play_interval) "0.5"
set config(glitch_threshold) "2500"
set config(default_frequency) "512 1024"
set config(match_limit) "0.1"
# We set up the Neuroclassifier.
set config(classifier_types) "HFO orange Other purple"
set config(classifier_metrics) "event_pwr purity intermittency"
# Maximum signal loss we can tolerate and still consider the interval
# an event.
set max_loss 20.0
# Define the event band in Hertz.
set event_lo 80.0
set event_hi 260.0
# After rectifying the event-band signal, which amounts to a demodulation
# of its amplitude envelope, we take the fourier transform of the de-modulated
# signal and calculate the power of this transform in a range of frequencies.
# We define this range below, in Hertz.
set int_lo 2.0
set int_hi 10.0
# Obtain the event-band power. At the same time, replace the existing
# signal values with the inverse transform of the filtered signal. To
# turn on plotting of the event-band power, set the first constant
# parameter to some n >= 1 if you want the filtered signal to be amplified
# by n before plotting. Make sure the second constant parameter remains 1.
set event_pwr [expr 0.001*[ \
Neuroarchiver_band_power $event_lo $event_hi 0 1]]
# Make a list of the spectrum components in the event band.
set a_list [list]
set f 0
foreach {a p} $info(spectrum) {
if {($f >= $event_lo) && ($f <= $event_hi)} {
lappend a_list "$f $a"
}
set f [expr $f + $info(f_step)]
}
# Find the maximum amplitude and use it to obtain an amplitude
# threshold.
set a_max 0.0
foreach e $a_list {
scan $e %f%f f a
if {$a > $a_max} {
set a_max $a
}
}
set cut [expr $a_max / 5.0]
# Using the net amplitude above the threshold, obtain the centroid
# and width of the event-band spectrum.
set a_sum 0.0
set fa_sum 0.0
set ffa_sum 0.0
foreach e $a_list {
scan $e %f%f f a
set net_a [expr $a - $cut]
if {$net_a > 0} {
set a_sum [expr $a_sum + $a]
set fa_sum [expr $fa_sum + $f*$a]
set ffa_sum [expr $ffa_sum + $f*$f*$a]
}
}
set f_center [expr $fa_sum / $a_sum]
set f_stdev [expr sqrt($ffa_sum / $a_sum - $f_center*$f_center)]
# The purity of the event-band signal is the ratio of the centroid
# frequency to the centroid width.
if {$f_stdev > 0} {
set purity [expr $f_center / $f_stdev]
} {
set purity [expr $f_center / $info(f_step)]
}
# Intermittency is a measure of how much the high-frequency content in
# the signal varies in the interval.
set rectified_values ""
set rectified_signal ""
set ts 0
foreach v $info(values) {
append rectified_values "[expr abs($v)] "
append rectified_signal "[incr ts] [expr abs($v)] "
}
# Neuroarchiver_plot_signal $info(channel_num) $rectified_signal
set spectrum [lwdaq_fft $rectified_values]
set f 0
set intermittency_pwr 0.0
foreach {a p} $spectrum {
if {$f >= $int_lo} {
set intermittency_pwr [expr $intermittency_pwr + 0.001*$a*$a]
}
set f [expr $f + $info(f_step)]
if {$f > $int_hi} {break}
}
# Here we perform baseline power calibration, which works by finding the
# minimum event band power. We increase the baseline power by a small
# fraction every interval, in order to accommodate an increase in electrode
# sensitivity. We take care to avoid using corrupted intervals for our
# baseline. We won't use an interval with poor reception. We go to some
# effort to avoid being fooled by the glitch filter, which can happen
# under rare circumstances with bad messages.
upvar #0 Neuroarchiver_info(bp_$info(channel_num)) baseline_pwr
set baseline_pwr [expr 1.0001*$baseline_pwr]
if {($event_pwr < $baseline_pwr) && ($event_pwr > 0.0) && ($info(loss) < $max_loss)} {
set info(values) [Neuroarchiver_values $info(signal)]
set info(spectrum) [lwdaq_fft $info(values) -glitch 0 \
-window [expr round([llength $info(values)] * $config(window_fraction))]]
set pwr [expr 0.001*[Neuroarchiver_band_power $event_lo $event_hi 0 0]]
if {$pwr < $baseline_pwr} {
set baseline_pwr $event_pwr
}
}
# Calculate the characteristics we use for determining similarity
# of events. If we have signal loss, we set these metrics to zero.
if {($info(loss)<$max_loss) && ($event_pwr>0.0)} {
set event_pwr_m [expr 1.0 / (1.0 + pow(10.0/($event_pwr/$baseline_pwr),1.0))]
set purity_m [expr 1.0 / (1.0 + pow(8.0/$purity,3.0))]
set intermittency_m [expr 1.0 / (1.0 + pow(0.2/($intermittency_pwr/$event_pwr),2.0))]
} {
foreach a $config(classifier_metrics) {set $a\_m 0.0}
}
# We begin this channel's section of the characteristics line with the
# channel number.
append result "$info(channel_num) "
# We add a single-letter code that indicates the type of the interval, so
# far as this processor can deduce it. We have L for loss, U for unclassified
# and N for no event.
if {($info(loss)>=$max_loss)} {
append result "L "
} elseif {$event_pwr_m>=0.5} {
append result "U "
} else {
append result "N "
}
# We add the baseline power to the characteristics. If we calculate
# the baseline power later, when looking through an archive, we could miss
# the defining low-power interval that sets the baseline.
append result "[format %.3f $baseline_pwr] "
# We record in the result line all the characteristics of the playback
# interval. The first one we record is the one we will use as a threshold
# for the occurance of an event, this threshold being 0.5 by default.
foreach a $config(classifier_metrics) {append result "[format %.3f [set $a\_m]] "}