Exemple #1
0
        /**
         * Handler function for raw event emitter.
         * Converts EEG events into lines of CSV and writes data to the rawLogFile
         */

        internal void OnRawEEGData(EEGEvent evt)
        {
            var csv = new StringBuilder();

            csv.Append(evt.timestamp.ToString("o"));
            csv.Append(",");
            csv.Append(evt.type.ToString());
            if (evt.extra != null)
            {
                csv.Append(evt.extra.ToString());
            }
            csv.Append(",");
            for (int i = 0; i < evt.data.Length; i++)
            {
                csv.Append(",");
                csv.Append(evt.data[i].ToString());
            }
            if (file == null)
            {
                file = new AsyncStreamWriter(rawLogFile, true);
            }
            var writableCsv = csv.ToString();

            file.WriteLine(writableCsv);
        }
Exemple #2
0
        protected override bool Process(object item)
        {
            EEGEvent evt = (EEGEvent)item;

            self.EmitRawEvent(evt);
            return(true);
        }
Exemple #3
0
 /**
  * Puts EEGEvents into the eventQueue to wait; events are flushed and handlers operate on the events
  */
 protected void EmitData(EEGEvent evt)
 {
     //Logger.Log("EmitData type=" + evt.type);
     lock (eventQueue) {
         //Logger.Log("EmitData lock obtained");
         eventQueue.Enqueue(evt);
         //Logger.Log("EmitData lock released");
     }
 }
Exemple #4
0
        protected override bool Process(object item)
        {
            EEGEvent evt = (EEGEvent)item;
            var      n   = evt.data.Length;

            for (int i = 0; i < n; i++)
            {
                buffer[i] = signalFilters[i].Filter(evt.data[i]);
            }
            Add(new EEGEvent(evt.timestamp, evt.type, buffer, evt.extra));
            return(true);
        }
Exemple #5
0
 /**
  * Thread safe function that removes events from the event queue and calls FlushEvent (without a s) on each event to send data through pipelines
  */
 public void FlushEvents()
 {
     //Logger.Log("FlushEvents()");
     lock (eventQueue) {
         //Logger.Log("FlushEvents lock obtained");
         while (eventQueue.Count > 0)
         {
             EEGEvent evt = eventQueue.Dequeue();
             FlushEvent(evt);
         }
         //Logger.Log("FlushEvents lock released");
     }
 }
Exemple #6
0
        protected override bool Process(object item)
        {
            EEGEvent evt = (EEGEvent)item;

            for (int i = 0; i < detectors.Length; i++)
            {
                if (detectors[i].Detect(evt.data[i]))
                {
                    return(true);
                }
            }

            Add(evt);
            return(true);
        }
Exemple #7
0
 /**
  * Runs the handler functions for each type of event on the events being flushed by the FlushEvents (with a s) in the public function
  */
 private void FlushEvent(EEGEvent evt)
 {
     if (handlers.ContainsKey(evt.type))
     {
         //Debug.Log("FlushEvent type=" + evt.type);
         List <DataHandler> h = handlers[evt.type];
         foreach (DataHandler dh in h)
         {
             //try {
             dh(evt);
             //} catch (Exception e) {
             //	Logger.Error(e);
             //}
         }
     }
 }
Exemple #8
0
        protected override bool Process(object item)
        {
            EEGEvent evt = (EEGEvent)item;

            if (evt.type != EEGDataType.EEG)
            {
                throw new Exception("FFTPipeable recieved invalid EEGEvent: " + evt);
            }

            if (evt.data.Length != channels)
            {
                throw new Exception("FFTPipeable recieved malformed EEGEvent: " + evt);
            }

            // normal case: just append data to sample buffer
            for (int i = 0; i < channels; i++)
            {
                var v = evt.data[i];
                //v = signalFilters[i].Filter(v);
                samples[i].Enqueue(v);
            }
            nSamples++;

            if (nSamples > windowSize)
            {
                foreach (var channelSamples in samples)
                {
                    channelSamples.Dequeue();
                    //channelSamples.Dequeue();
                }
                nSamples--;
            }

            lastFFT++;
            //Logger.Log("nSamples={0}, lastFFT={1}", nSamples, lastFFT);
            // sample buffer is full, do FFT then reset for next round
            if (nSamples >= windowSize && lastFFT % fftRate == 0)
            {
                DoFFT(evt);
            }

            return(true);
        }
Exemple #9
0
        /**
         * Thread safe helper function for running raw event handlers on each raw event
         */
        internal void EmitRawEvent(EEGEvent evt)
        {
            lock (rawHandlers)
            {
                if (!rawHandlers.ContainsKey(evt.type))
                {
                    return;
                }

                // Logger.Log("Emitting evt: " + evt.type);
                foreach (var handler in rawHandlers[evt.type])
                {
                    try
                    {
                        handler(evt);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Handler " + handler + " encountered exception: " + e);
                    }
                }
            }
        }
        /**
         * Collects incoming EEGEvents (one per type), and stores them in buffer. If the incoming
         * event's timestamp is new, attempt to send the buffer onto the IPredictor<EEGEvent[]>
         * If the current trainingId is non-zero, the data will be used for training on the trainingId label
         * If the current trainingId is zero, the data will be predicted on
         * @see Pipeable
         */
        protected override bool Process(object item)
        {
            //Incoming objects must be EEGEvent
            EEGEvent evt = (EEGEvent)item;

            //Also must be a type we care about
            if (!types.Contains(evt.type))
            {
                return(true);
            }

            //If we start getting data from a new time, send it to the predictor
            if (evt.timestamp != currentTimeStep)
            {
                CheckBufferAndPredict();
                currentTimeStep = evt.timestamp;
            }

            //Add the new event into the buffer
            buffer[indexMap[evt.type]] = evt;

            return(true);
        }
Exemple #11
0
        void DoFFT(EEGEvent evt)
        {
            // Do an FFT on each channel
            List <double[]> fftOutput = new List <double[]>();

            for (int i = 0; i < samples.Length; i++)
            {
                var channelSamples = samples[i];
                var samplesCopy    = channelSamples.ToArray();

                // apply windowing function to samplesCopy
                DSP.Math.Multiply(samplesCopy, windowConstants);

                var cSpectrum = fft.Execute(samplesCopy);
                // complex side smoothing
                //cSpectrum = complexFilters[i].Smooth(cSpectrum);

                double[] lmSpectrum = DSP.ConvertComplex.ToMagnitude(cSpectrum);
                lmSpectrum = DSP.Math.Multiply(lmSpectrum, scaleFactor);

                fftOutput.Add(lmSpectrum);
            }

            for (int i = 0; i < fftOutput.Count; i++)
            {
                var rawFFT = fftOutput[i];
                Add(new EEGEvent(evt.timestamp, EEGDataType.FFT_RAW, rawFFT, i));

                // magnitude side smoothing
                var smoothedFFT = magSmoothers[i].Smooth(rawFFT);
                Add(new EEGEvent(evt.timestamp, EEGDataType.FFT_SMOOTHED, smoothedFFT, i));
            }

            //var freqSpan = fft.FrequencySpan(sampleRate);

            // find abs powers for each band
            var absolutePowers = new Dictionary <EEGDataType, double[]>();

            for (int i = 0; i < channels; i++)
            {
                var    bins     = fftOutput[i];
                double deltaAbs = AbsBandPower(bins, 1, 4);
                double thetaAbs = AbsBandPower(bins, 4, 8);
                double alphaAbs = AbsBandPower(bins, 7.5, 13);
                double betaAbs  = AbsBandPower(bins, 13, 30);
                double gammaAbs = AbsBandPower(bins, 30, 44);
                //Logger.Log("D={0}, T={1}, A={2}, B={3}, G={4}", deltaAbs, thetaAbs, alphaAbs, betaAbs, gammaAbs);

                GetBandList(absolutePowers, EEGDataType.ALPHA_ABSOLUTE)[i] = (alphaAbs);
                GetBandList(absolutePowers, EEGDataType.BETA_ABSOLUTE)[i]  = (betaAbs);
                GetBandList(absolutePowers, EEGDataType.GAMMA_ABSOLUTE)[i] = (gammaAbs);
                GetBandList(absolutePowers, EEGDataType.DELTA_ABSOLUTE)[i] = (deltaAbs);
                GetBandList(absolutePowers, EEGDataType.THETA_ABSOLUTE)[i] = (thetaAbs);
            }

            // we can emit abs powers immediately
            Add(new EEGEvent(evt.timestamp, EEGDataType.ALPHA_ABSOLUTE, absolutePowers[EEGDataType.ALPHA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.BETA_ABSOLUTE, absolutePowers[EEGDataType.BETA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.GAMMA_ABSOLUTE, absolutePowers[EEGDataType.GAMMA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.DELTA_ABSOLUTE, absolutePowers[EEGDataType.DELTA_ABSOLUTE].ToArray()));
            Add(new EEGEvent(evt.timestamp, EEGDataType.THETA_ABSOLUTE, absolutePowers[EEGDataType.THETA_ABSOLUTE].ToArray()));

            // now calc and emit relative powers
            Add(new EEGEvent(evt.timestamp, EEGDataType.ALPHA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.ALPHA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.BETA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.BETA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.GAMMA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.GAMMA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.DELTA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.DELTA_ABSOLUTE)));
            Add(new EEGEvent(evt.timestamp, EEGDataType.THETA_RELATIVE, RelBandPower(absolutePowers, EEGDataType.THETA_ABSOLUTE)));
        }
Exemple #12
0
 void UpdateConnectionStatus(EEGEvent evt)
 {
     _connectionStatus = evt.data;
 }
Exemple #13
0
        protected override bool Process(object item)
        {
            EEGEvent evt = (EEGEvent)item;

            var n = evt.data.Length;

            double[] buffer = new double[evt.data.Length];
            for (int i = 0; i < n; i++)
            {
                buffer[i] = signalFilters[i].Filter(evt.data[i]);
            }

            // TODO test artifact detection
            if (isLearning)
            {
                // add samples to window and test if window is sufficiently large
                bool stillLearning = false;
                for (int i = 0; i < n; i++)
                {
                    artifactLearningSamples[i].Enqueue(evt.data[i]);
                    stillLearning = artifactLearningSamples[i].Count < artifactLearningSize;
                }
                // sufficient samples to fit AR model
                if (!stillLearning)
                {
                    for (int i = 0; i < n; i++)
                    {
                        double[] x        = artifactLearningSamples[i].ToArray();
                        var      p        = StatsUtils.EstimateAROrder(x, 50);
                        double   mean     = StatsUtils.SampleMean(x);
                        double[] arParams = StatsUtils.FitAR(p, x);
                        Logger.Log("Estimated AR params: p={0}, c={1}, phi={2}", p, mean, string.Join(", ", arParams));
                        arPredictors[i]    = new ARModel(mean, arParams);
                        lastPredictions[i] = arPredictors[i].Predict(evt.data[i]);
                    }
                }
                isLearning = stillLearning;
            }
            else
            {
                bool isArtifact = false;
                for (int i = 0; i < n; i++)
                {
                    var x         = evt.data[i];
                    var error     = x - lastPredictions[i];
                    var errorDist = arError[i];
                    errorDist.Update(error);
                    lastPredictions[i] = arPredictors[i].Predict(x);

                    if (errorDist.isValid)
                    {
                        var errorS       = Math.Sqrt(errorDist.var);
                        var errorMaxCI95 = errorDist.mean + 2 * errorS;
                        var errorMinCI95 = errorDist.mean - 2 * errorS;
                        //Logger.Log("Error={0}, 95% CI = [{1}, {2}]", error, errorMinCI95, errorMaxCI95);
                        isArtifact = error > errorMaxCI95 || error < errorMinCI95;
                    }
                }

                if (isArtifact)
                {
                    Logger.Log("Detected large amplitude artifact via AR model");
                    return(true);
                }
            }

            Add(new EEGEvent(evt.timestamp, evt.type, buffer, evt.extra));

            return(true);
        }