internal override void read(short[,] data, int numChannelsData, int startChannelData, int length) { unsafe { fixed(short *pdata = &data[0, 0], pbuffer = &_buffer[0, 0]) { for (int c = startChannelData; c < startChannelData + numChannelsData; ++c) { int baseOfDimData = (c - startChannelData) * length; //BaseOfDim is in ref to input data, which has no channel offset int baseOfDimBuffer = (MEAChannelMappings.channel2LinearCR(c) - 1) * BUFFER_LENGTH; //Check to see if we'll loop back to front of buffer here, rather than wasting an if statement in the loop if (_currentLocationRead[c] + length < BUFFER_LENGTH) { //Check for buffer overrun if (_currentLocationWrite[c] > _currentLocationRead[c]) { if (_currentLocationWrite[c] - _currentLocationRead[c] < length) { System.Windows.Forms.MessageBox.Show("Buffer Overrun"); } } //We can copy blithely, without worry of looping back around for (int i = 0; i < length; ++i) { pbuffer[baseOfDimBuffer + _currentLocationRead[c]++] = pdata[baseOfDimData + i]; //if (_currentLocationRead[c] != _currentLocationWrite[c]) { /* do nothing */} //else // System.Windows.Forms.MessageBox.Show("Buffer Overrun"); } } else { //Check for buffer overruns if (_currentLocationWrite[c] > _currentLocationRead[c]) { //Since we're guaranteed to go to end of buffer, if write head is higher, we will overrun System.Windows.Forms.MessageBox.Show("Buffer Overrun"); } int firstDistance = BUFFER_LENGTH - _currentLocationRead[c]; for (int i = 0; i < firstDistance; ++i) { pbuffer[baseOfDimBuffer + _currentLocationRead[c]++] = pdata[baseOfDimData + i]; } _currentLocationRead[c] = 0; //Reset read head if (_currentLocationWrite[c] < length - firstDistance) { System.Windows.Forms.MessageBox.Show("Buffer Overrun"); } for (int i = firstDistance; i < length; ++i) { pbuffer[baseOfDimBuffer + _currentLocationRead[c]++] = pdata[baseOfDimData + i]; } //for (int i = 0; i < length; ++i) //{ // pbuffer[baseOfDimBuffer + _currentLocationRead[c]] = pdata[baseOfDimData + i]; // if (++_currentLocationRead[c] < BUFFER_LENGTH) { /* do nothing */ } // else { _currentLocationRead[c] = 0; } // if (_currentLocationRead[c] != _currentLocationWrite[c]) { /* do nothing */} // else // System.Windows.Forms.MessageBox.Show("Buffer Overrun"); //} } } } } //for (int c = 0; c < numChannelsData; ++c) //{ // //Check to see if we'll loop back to front of buffer here, rather than wasting an if statement in the loop // if (_currentLocationRead[startChannelData + c] + length < BUFFER_LENGTH) // { // //We can copy blithely, without worry of looping back around // for (int i = 0; i < length; ++i) // { // _buffer[startChannelData + c][_currentLocationRead[startChannelData + c]++] = data[c, i]; // if (_currentLocationRead[c] != _currentLocationWrite[c]) { /* do nothing */} // else // System.Windows.Forms.MessageBox.Show("Buffer Overrun"); // } // } // else // { // for (int i = 0; i < length; ++i) // { // _buffer[startChannelData + c][_currentLocationRead[startChannelData + c]] = data[c, i]; // if (++_currentLocationRead[startChannelData + c] < BUFFER_LENGTH) { /* do nothing */ } // else { _currentLocationRead[startChannelData + c] = 0; } // if (_currentLocationRead[c] != _currentLocationWrite[c]) { /* do nothing */} // else // System.Windows.Forms.MessageBox.Show("Buffer Overrun"); // } // } //} }
//DateTime spkClk; private void bwSpikes_DoWork(object sender, DoWorkEventArgs e) { //spkClk = DateTime.Now; Object[] state = (Object[])e.Argument; int taskNumber = (int)state[0]; //Debugger.Write(taskNumber.ToString() + ": dowork begin"); trackingProc[taskNumber]++; //double[][] filtSpikeData; //Copy data into a new buffer for (int i = 0; i < numChannelsPerDev; ++i) { spikeData[taskNumber][i].GetRawData(0, spikeBufferLength, filtSpikeData[taskNumber * numChannelsPerDev + i], 0); } //Debugger.Write(taskNumber.ToString() + ": raw data read"); // Increment the number of times the DAQ has been polled for spike data ++(numSpikeReads[taskNumber]); ulong startTime = (ulong)(numSpikeReads[taskNumber] - 1) * (ulong)spikeBufferLength; //Used to mark spike time for *.spk file //Account for Pre-amp gain double ampdec = (1 / Properties.Settings.Default.PreAmpGain); for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { for (int j = 0; j < spikeBufferLength; ++j) { filtSpikeData[i][j] = ampdec * filtSpikeData[i][j]; } } // Send filtSpikeData to datSrv if (Properties.Settings.Default.useRawDataBuffer) { datSrv.RawElectrodeSrv.WriteToBuffer(filtSpikeData, taskNumber, numChannelsPerDev); } // Debugger.Write(taskNumber.ToString() + ": raw data sent to rawsrv"); #region Write RAW data //Write data to file if (switch_record.Value && recordingSettings.recordRaw && spikeTask != null) { lock (recordingSettings.rawOut) { for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { // Temporary storage for converte data Int16[] tempBuff; // Convert raw data to 16-bit int tempBuff = neuralDataScaler.ConvertSoftRawRowToInt16(ref filtSpikeData[i]); // Send data to file writer for (int j = 0; j < spikeBufferLength; ++j) { recordingSettings.rawOut.read(tempBuff[j], i); } } } } #endregion // Debugger.Write(taskNumber.ToString() + ": raw written"); #region Raw Spike Detection if (recordingSettings.recordRawSpike) { lock (rawSpikeObj) { //newWaveforms: 0 based indexing for internal NR processing (datSrv, plotData) EventBuffer <SpikeEvent> newWaveformsRaw = new EventBuffer <SpikeEvent>(Properties.Settings.Default.RawSampleFrequency); switch (spikeDet.detectorType) { case 0: for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { newWaveformsRaw.Buffer.AddRange(spikeDet.spikeDetectorRaw.DetectSpikes(filtSpikeData[i], i, startTime)); } break; case 1: for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { newWaveformsRaw.Buffer.AddRange(spikeDet.spikeDetectorRaw.DetectSpikesSimple(filtSpikeData[i], i, startTime)); } break; } //Extract waveforms, convert to 1 based indexing EventBuffer <SpikeEvent> toRawsrvRaw = new EventBuffer <SpikeEvent>(spikeSamplingRate); if (Properties.Settings.Default.ChannelMapping != "invitro") //|| numChannels != 64) //check this first, so we don't have to check it for each spike { for (int j = 0; j < newWaveformsRaw.Buffer.Count; ++j) //For each threshold crossing { SpikeEvent tmp = (SpikeEvent)newWaveformsRaw.Buffer[j].DeepClone(); tmp.Channel = InVivoChannelMappings.Channel2LinearCR(tmp.Channel); toRawsrvRaw.Buffer.Add(tmp); } } else //in vitro mappings { for (int j = 0; j < newWaveformsRaw.Buffer.Count; ++j) //For each threshold crossing { SpikeEvent tmp = (SpikeEvent)newWaveformsRaw.Buffer[j].DeepClone(); tmp.Channel = MEAChannelMappings.channel2LinearCR(tmp.Channel); toRawsrvRaw.Buffer.Add(tmp); } } // Record spike waveforms if (switch_record.Value) { for (int j = 0; j < newWaveformsRaw.Buffer.Count; ++j) //For each threshold crossing { SpikeEvent tmp = toRawsrvRaw.Buffer[j]; lock (recordingSettings.spkOutRaw) //Lock so another NI card doesn't try writing at the same time { recordingSettings.spkOutRaw.WriteSpikeToFile((short)tmp.Channel, (int)tmp.SampleIndex, tmp.Threshold, tmp.Waveform, tmp.Unit); } } } } } #endregion // Debugger.Write(taskNumber.ToString() + ": raw spikes filtered"); #region LFP_Filtering //Filter for LFPs if (!Properties.Settings.Default.SeparateLFPBoard && Properties.Settings.Default.UseLFPs) { //Copy to new array for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { for (int j = 0; j < spikeBufferLength; ++j) { filtLFPData[i][j] = filtSpikeData[i][j]; } } #region ArtiFilt (interpolation filtering) if (checkBox_artiFilt.Checked) { artiFilt.filter(ref filtLFPData, stimIndices, taskNumber * numChannelsPerDev, numChannelsPerDev, numStimReads[taskNumber] - 1); } #endregion if (checkBox_LFPsFilter.Checked) { for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { lfpFilter[i].filterData(filtLFPData[i]); } } //Downsample for LFPs double dsFactor = (double)spikeSamplingRate / (double)lfpSamplingRate; if (dsFactor % 1 == 0) //If it's an integer { for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { for (int j = 0; j < lfpBufferLength; ++j) { finalLFPData[i][j] = filtLFPData[i][(int)(dsFactor * j)]; } } } else { for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { for (int j = 0; j < lfpBufferLength; ++j) { finalLFPData[i][j] = filtLFPData[i][(int)(Math.Round(dsFactor * j))]; } } } //Do IISZapper stuff if (IISDetected != null) { IISDetected(this, finalLFPData, numSpikeReads[taskNumber]); } // Send to datSrv if (Properties.Settings.Default.useLFPDataBuffer) { datSrv.LFPSrv.WriteToBuffer(finalLFPData, 0, numChannels); } #region WriteLFPFile if (switch_record.Value && recordingSettings.recordLFP && spikeTask != null) //Convert to 16-bit ints, then write to file { for (int i = taskNumber * numChannelsPerDev; i < (taskNumber + 1) * numChannelsPerDev; ++i) { // Temporary storage for converte data Int16[] tempLFPBuff; // Convert raw data to 16-bit int tempLFPBuff = neuralDataScaler.ConvertSoftRawRowToInt16(ref finalLFPData[i]); // Send data to file writer for (int j = 0; j < lfpBufferLength; ++j) { recordingSettings.lfpOut.read((short)tempLFPBuff[j], i); } } } #endregion //Digital ref LFP signals if (!checkBox_digRefLFPs.Checked) /* Do nothing, since prefetch makes if faster than else */ } {
internal override void read(short data, int channel) { _buffer[MEAChannelMappings.channel2LinearCR(channel) - 1, _currentLocationRead[channel]] = data; if (++_currentLocationRead[channel] < BUFFER_LENGTH) /* do nothing */ } {