/// <summary> /// After the channel models (gmm's) have been created and trained, this function /// is used to classifty newly detected spikes for which a valide channel model exisits. /// </summary> /// <param name="newSpikes"> An EventBuffer conataining spikes to be classified</param> public void Classify(ref EventBuffer <SpikeEvent> newSpikes) { // Make sure the channel models are trained. if (!trained) { throw new InvalidOperationException("The channel models were not yet trained so classification is not possible."); } // Sort the channels that need sorting for (int i = 0; i < channelsToSort.Count; ++i) { // Current channel int currentChannel = channelsToSort[i]; // Get the spikes that belong to this channel List <SpikeEvent> spikesOnChan = newSpikes.Buffer.Where(x => x.Channel == currentChannel).ToList(); // If there are no spikes on this channel if (spikesOnChan.Count == 0) { continue; } // Get the channel model for this channel ChannelModel thisChannelModel = channelModels[channelsToSort.IndexOf(currentChannel)]; // Project the spikes if (this.projectionType == "Maximum Voltage Inflection") { thisChannelModel.MaxInflectProject(spikesOnChan.ToList(), inflectionSample); } else if (this.projectionType == "Double Voltage Inflection") { thisChannelModel.DoubleInflectProject(spikesOnChan.ToList(), inflectionSample, secondInflectionIndex); } else if (this.projectionType == "PCA") { thisChannelModel.PCProject(spikesOnChan.ToList()); } else if (this.projectionType == "Haar Wavelet") { thisChannelModel.HaarProject(spikesOnChan.ToList()); } // Sort the spikes thisChannelModel.ClassifyThresh(); // Update the newSpikes buffer for (int j = 0; j < spikesOnChan.Count; ++j) { if (thisChannelModel.classes[j] < 0) { spikesOnChan[j].SetUnit((Int16)0); } else { spikesOnChan[j].SetUnit((Int16)(thisChannelModel.classes[j] + thisChannelModel.unitStartIndex + 1)); } } } }
/// <summary> /// Trains a classifier for each channel so long as (int)minSpikes worth of spikes have been collected /// for that channel in the training buffer /// </summary> private void Train() { // Clear old channel models channelsToSort = new List <int>(); channelModels.Clear(); trained = false; totalNumberOfUnits = 0; // Clear old unit dictionary unitDictionary = new Hashtable(); // Add the zero unit to the dictionary unitDictionary.Add(0, 0); // Clear the old unit2channel map unit2Channel = new Dictionary <int, int>(); // Make sure we have something in the training matrix if (trainingSpikes.Buffer.Count == 0) { throw new InvalidOperationException("The training data set was empty"); } for (int i = 0; i < numberChannels; ++i) { // Current channel int currentChannel = i; // Get the spikes that belong to this channel List <SpikeEvent> spikesOnChan = trainingSpikes.Buffer.Where(x => x.Channel == currentChannel).ToList(); // Project channel data if (spikesOnChan.Count >= minSpikes) { // Train a channel model for this channel ChannelModel thisChannelModel = new ChannelModel(currentChannel, maxK, totalNumberOfUnits, pValue, projectionDimension); // Project Data if (projectionType == "PCA") { thisChannelModel.PCCompute(spikesOnChan.ToList()); } else { thisChannelModel.HaarCompute(spikesOnChan.ToList()); } // Train Classifier thisChannelModel.Train(); // If there was a training failure (e.g. convergence) if (!thisChannelModel.trained) { continue; } // Note that we have to sort spikes on this channel channelsToSort.Add(currentChannel); // Update the unit dicationary and increment the total number of units for (int k = 1; k <= thisChannelModel.K; ++k) { unitDictionary.Add(totalNumberOfUnits + k, k); unit2Channel.Add(totalNumberOfUnits + k, i); } totalNumberOfUnits += thisChannelModel.K; // Add the channel model to the list channelModels.Add(thisChannelModel); } } }
/// <summary> /// Trains a classifier for each channel so long as (int)minSpikes worth of spikes have been collected /// for that channel in the training buffer /// </summary> private void Train() { // Clear old channel models channelsToSort = new List<int>(); channelModels.Clear(); trained = false; totalNumberOfUnits = 0; // Clear old unit dictionary unitDictionary = new Hashtable(); // Add the zero unit to the dictionary unitDictionary.Add(0, 0); // Clear the old unit2channel map unit2Channel = new Dictionary<int, int>(); // Make sure we have something in the training matrix if (trainingSpikes.Buffer.Count == 0) { throw new InvalidOperationException("The training data set was empty"); } for (int i = 0; i < numberChannels; ++i) { // Current channel int currentChannel = i; // Get the spikes that belong to this channel List<SpikeEvent> spikesOnChan = trainingSpikes.Buffer.Where(x => x.Channel == currentChannel).ToList(); // Project channel data if (spikesOnChan.Count >= minSpikes) { // Train a channel model for this channel ChannelModel thisChannelModel = new ChannelModel(currentChannel, maxK, totalNumberOfUnits, pValue, projectionDimension); // Project Data if (projectionType == "PCA") thisChannelModel.PCCompute(spikesOnChan.ToList()); else thisChannelModel.HaarCompute(spikesOnChan.ToList()); // Train Classifier thisChannelModel.Train(); // If there was a training failure (e.g. convergence) if (!thisChannelModel.trained) continue; // Note that we have to sort spikes on this channel channelsToSort.Add(currentChannel); // Update the unit dicationary and increment the total number of units for (int k = 1; k <= thisChannelModel.K; ++k) { unitDictionary.Add(totalNumberOfUnits + k, k); unit2Channel.Add(totalNumberOfUnits + k, i); } totalNumberOfUnits += thisChannelModel.K; // Add the channel model to the list channelModels.Add(thisChannelModel); } } }
/// <summary> /// Trains a classifier for each channel so long as (int)minSpikes worth of spikes have been collected /// for that channel in the training buffer. This uses to time points as the projection: The peak sample /// of the waveform and sample at some fixed (mSecToSecondSample) delay from the peak sample. Preferably, /// this should be in the middle of the AHP. /// </summary> /// <param name="peakSample"> Sample that the peak of the waveform occured at </param> /// <param name="mSecToSecondSample">Delay, in msec, to get the second data point</param> private void Train(int peakSample, double mSecToSecondSample, int sampleFreqHz) { // Clear old channel models channelsToSort = new List <int>(); channelModels.Clear(); trained = false; totalNumberOfUnits = 0; // Clear old unit dictionary unitDictionary = new Hashtable(); // Add the zero unit to the dictionary unitDictionary.Add(0, 0); // Clear the old unit2channel map unit2Channel = new Dictionary <int, int>(); // Set the inflection sample inflectionSample = peakSample; secondInflectionIndex = peakSample + (int)(sampleFreqHz * (mSecToSecondSample / 1000)); // Make sure we have something in the training matrix if (trainingSpikes.Buffer.Count == 0) { throw new InvalidOperationException("The training data set was empty"); } for (int i = 0; i < numberChannels; ++i) { // Current channel int currentChannel = i; // Get the spikes that belong to this channel List <SpikeEvent> spikesOnChan = trainingSpikes.Buffer.Where(x => x.Channel == currentChannel).ToList(); // Project channel data if (spikesOnChan.Count >= minSpikes) { // Train a channel model for this channel ChannelModel thisChannelModel = new ChannelModel(currentChannel, maxK, totalNumberOfUnits, pValue); // Project Data thisChannelModel.DoubleInflectProject(spikesOnChan.ToList(), inflectionSample, secondInflectionIndex); // Train Classifier thisChannelModel.Train(); // If there was a training failure (e.g. convergence) if (!thisChannelModel.trained) { continue; } // Note that we have to sort spikes on this channel channelsToSort.Add(currentChannel); // Update the unit dicationary and increment the total number of units for (int k = 1; k <= thisChannelModel.K; ++k) { unitDictionary.Add(totalNumberOfUnits + k, k); unit2Channel.Add(totalNumberOfUnits + k, i); } totalNumberOfUnits += thisChannelModel.K; // Add the channel model to the list channelModels.Add(thisChannelModel); } } // All finished trained = true; }
/// <summary> /// Trains a classifier for each channel so long as (int)minSpikes worth of spikes have been collected /// for that channel in the training buffer. This uses to time points as the projection: The peak sample /// of the waveform and sample at some fixed (mSecToSecondSample) delay from the peak sample. Preferably, /// this should be in the middle of the AHP. /// </summary> /// <param name="peakSample"> Sample that the peak of the waveform occured at </param> /// <param name="mSecToSecondSample">Delay, in msec, to get the second data point</param> private void Train(int peakSample, double mSecToSecondSample, int sampleFreqHz) { // Clear old channel models channelsToSort = new List<int>(); channelModels.Clear(); trained = false; totalNumberOfUnits = 0; // Clear old unit dictionary unitDictionary = new Hashtable(); // Add the zero unit to the dictionary unitDictionary.Add(0, 0); // Clear the old unit2channel map unit2Channel = new Dictionary<int, int>(); // Set the inflection sample inflectionSample = peakSample; secondInflectionIndex = peakSample + (int)(sampleFreqHz * (mSecToSecondSample / 1000)); // Make sure we have something in the training matrix if (trainingSpikes.Buffer.Count == 0) { throw new InvalidOperationException("The training data set was empty"); } for (int i = 0; i < numberChannels; ++i) { // Current channel int currentChannel = i; // Get the spikes that belong to this channel List<SpikeEvent> spikesOnChan = trainingSpikes.Buffer.Where(x => x.Channel == currentChannel).ToList(); // Project channel data if (spikesOnChan.Count >= minSpikes) { // Train a channel model for this channel ChannelModel thisChannelModel = new ChannelModel(currentChannel, maxK, totalNumberOfUnits, pValue); // Project Data thisChannelModel.DoubleInflectProject(spikesOnChan.ToList(), inflectionSample, secondInflectionIndex); // Train Classifier thisChannelModel.Train(); // If there was a training failure (e.g. convergence) if (!thisChannelModel.trained) continue; // Note that we have to sort spikes on this channel channelsToSort.Add(currentChannel); // Update the unit dicationary and increment the total number of units for (int k = 1; k <= thisChannelModel.K; ++k) { unitDictionary.Add(totalNumberOfUnits + k, k); unit2Channel.Add(totalNumberOfUnits + k, i); } totalNumberOfUnits += thisChannelModel.K; // Add the channel model to the list channelModels.Add(thisChannelModel); } } // All finished trained = true; }