public ARArtifactDetector(ARModel model) { if (model == null) { throw new ArgumentException(); } this.model = model; errorDist = new OnlineVariance(); confusionDist = new OnlineVariance(); }
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); }