private void button_computeGain_Click(object sender, EventArgs e) { double startFreq = Convert.ToDouble(numericUpDown_startFreq.Value); double stopFreq = Convert.ToDouble(numericUpDown_stopFreq.Value); double numPeriods = Convert.ToDouble(numericUpDown_numPeriods.Value); double[] freqs = new double[1 + Convert.ToInt32(Math.Floor(Math.Log(stopFreq / startFreq) / Math.Log(Convert.ToDouble(textBox_diagnosticsMult.Text))))]; //This determines the number of frequencies counting by doublings radioButton_stimVoltageControlled.Checked = true; radioButton_stimVoltageControlled_Click(null, null); //Populate freqs vector freqs[0] = startFreq; for (int i = 1; i < freqs.GetLength(0); ++i) { freqs[i] = freqs[i - 1] * Convert.ToDouble(textBox_diagnosticsMult.Text); } spikeSamplingRate = Properties.Settings.Default.RawSampleFrequency; buttonStart.Enabled = false; //So users can't try to get data from the same card button_computeGain.Enabled = false; button_computeGain.Refresh(); buttonStart.Refresh(); spikeTask = new List <Task>(Properties.Settings.Default.AnalogInDevice.Count); diagnosticsReaders = new List <AnalogMultiChannelReader>(Properties.Settings.Default.AnalogInDevice.Count); for (int i = 0; i < Properties.Settings.Default.AnalogInDevice.Count; ++i) { spikeTask.Add(new Task("spikeTask_Diagnostics_" + i)); int numChannelsPerDevice = (numChannels < 32 ? numChannels : 32); for (int j = 0; j < numChannelsPerDevice; ++j) { spikeTask[i].AIChannels.CreateVoltageChannel(Properties.Settings.Default.AnalogInDevice[0] + "/ai" + j.ToString(), "", AITerminalConfiguration.Nrse, -10.0, 10.0, AIVoltageUnits.Volts); } //Change gain based on comboBox values (1-100) setGain(spikeTask[i], Properties.Settings.Default.A2Dgain); //Verify the Task spikeTask[i].Control(TaskAction.Verify); spikeTask[i].Timing.ConfigureSampleClock("", spikeSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples); diagnosticsReaders.Add(new AnalogMultiChannelReader(spikeTask[i].Stream)); } spikeTask[0].Timing.ReferenceClockSource = "OnboardClock"; for (int i = 1; i < spikeTask.Count; ++i) { spikeTask[i].Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource; spikeTask[i].Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate; } stimPulseTask.Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource; stimPulseTask.Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate; stimDigitalTask.Dispose(); stimDigitalTask = new Task("stimDigitalTask"); if (Properties.Settings.Default.StimPortBandwidth == 32) { stimDigitalTask.DOChannels.CreateChannel(Properties.Settings.Default.StimulatorDevice + "/Port0/line0:31", "", ChannelLineGrouping.OneChannelForAllLines); //To control MUXes } else if (Properties.Settings.Default.StimPortBandwidth == 8) { stimDigitalTask.DOChannels.CreateChannel(Properties.Settings.Default.StimulatorDevice + "/Port0/line0:7", "", ChannelLineGrouping.OneChannelForAllLines); //To control MUXes } stimDigitalWriter = new DigitalSingleChannelWriter(stimDigitalTask.Stream); stimPulseTask.Timing.ConfigureSampleClock("/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/SampleClock", spikeSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples); stimPulseTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/StartTrigger", DigitalEdgeStartTriggerEdge.Rising); stimDigitalTask.Control(TaskAction.Verify); stimPulseTask.Control(TaskAction.Verify); switch (Properties.Settings.Default.NumChannels) { case 0: numChannels = 16; break; case 1: numChannels = 32; break; case 2: numChannels = 48; break; case 3: numChannels = 64; break; } //gains = new double[numChannels, freqs.GetLength(0)]; //numChannels = 1; gains = new double[numChannels][]; for (int i = 0; i < numChannels; ++i) { gains[i] = new double[freqs.GetLength(0)]; } scatterGraph_diagnostics.ClearData(); scatterGraph_diagnostics.Plots.Clear(); textBox_diagnosticsResults.Clear(); if (!checkBox_diagnosticsBulk.Checked) { //for (int c = 1; c <= numChannels; ++c) for (int c = 13; c < 14; ++c) { textBox_diagnosticsResults.Text += "Channel " + c.ToString() + "\r\n\tFrequency (Hz)\tGain (dB)\r\n"; scatterGraph_diagnostics.Plots.Add(new ScatterPlot()); UInt32 data = StimPulse.channel2MUX((double)c); //Get data bits lined up to control MUXes //Setup digital waveform stimDigitalWriter.WriteSingleSamplePort(true, data); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); for (int f = 0; f < freqs.GetLength(0); ++f) { double numSeconds = 1 / freqs[f]; if (numSeconds * numPeriods < 0.1) { numPeriods = Math.Ceiling(0.1 * freqs[f]); } int size = Convert.ToInt32(numSeconds * spikeSamplingRate); SineSignal testWave = new SineSignal(freqs[f], Convert.ToDouble(numericUpDown_diagnosticsVoltage.Value)); //Generate a 100 mV sine wave at 1000 Hz double[] testWaveValues = testWave.Generate(spikeSamplingRate, size); double[,] analogPulse = new double[2, size]; for (int i = 0; i < size; ++i) { analogPulse[0, i] = testWaveValues[i]; } for (int i = 0; i < spikeTask.Count; ++i) { spikeTask[i].Timing.SamplesPerChannel = (long)(numPeriods * size); } stimPulseTask.Timing.SamplesPerChannel = (long)(numPeriods * size); //Do numperiods cycles of sine wave stimPulseWriter.WriteMultiSample(true, analogPulse); double[] stateData = new double[4]; stateData[0] = (double)c; stateData[1] = freqs[f]; stateData[2] = (double)f; for (int i = diagnosticsReaders.Count - 1; i >= 0; --i) { stateData[3] = (double)i; diagnosticsReaders[i].BeginReadMultiSample((int)(numPeriods * size), analogInCallback_computeGain, (Object)stateData); //Get 5 seconds of "noise" } stimPulseTask.WaitUntilDone(); for (int i = 0; i < spikeTask.Count; ++i) { spikeTask[i].WaitUntilDone(); spikeTask[i].Stop(); } stimPulseTask.Stop(); } stimDigitalWriter.WriteSingleSamplePort(true, 0); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); //DEBUGGING c = 1; scatterGraph_diagnostics.Plots[c - 1].PlotXY(freqs, gains[c - 1]); for (int f = 0; f < freqs.GetLength(0); ++f) { textBox_diagnosticsResults.Text += "\t" + freqs[f].ToString() + "\t" + gains[c - 1][f] + "\r\n"; } textBox_diagnosticsResults.Text += "\r\n"; scatterGraph_diagnostics.Refresh(); //DEBUGGING c = 100; } } else { for (int f = 0; f < freqs.GetLength(0); ++f) { double numSeconds = 1 / freqs[f]; if (numSeconds * numPeriods < 0.1) { numPeriods = Math.Ceiling(0.1 * freqs[f]); } int size = Convert.ToInt32(numSeconds * spikeSamplingRate); SineSignal testWave = new SineSignal(freqs[f], Convert.ToDouble(numericUpDown_diagnosticsVoltage.Value)); //Generate a 100 mV sine wave at 1000 Hz double[] testWaveValues = testWave.Generate(spikeSamplingRate, size); double[,] analogPulse = new double[2, size]; for (int i = 0; i < size; ++i) { analogPulse[0, i] = testWaveValues[i]; } for (int i = 0; i < spikeTask.Count; ++i) { spikeTask[i].Timing.SamplesPerChannel = (long)(numPeriods * size); } stimPulseTask.Timing.SamplesPerChannel = (long)(numPeriods * size); //Do numperiods cycles of sine wave stimPulseWriter.WriteMultiSample(true, analogPulse); double[] stateData = new double[4]; stateData[0] = -1.0; stateData[1] = freqs[f]; stateData[2] = (double)f; //Frequency of interest for (int i = diagnosticsReaders.Count - 1; i >= 0; --i) { stateData[3] = (double)i; //Keeps track of which device called the reader diagnosticsReaders[i].BeginReadMultiSample((int)(numPeriods * size), analogInCallback_computeGain, (Object)stateData); //Get 5 seconds of "noise" } stimPulseTask.WaitUntilDone(); for (int i = 0; i < spikeTask.Count; ++i) { spikeTask[i].WaitUntilDone(); spikeTask[i].Stop(); } stimPulseTask.Stop(); } for (int c = 0; c < numChannels; ++c) { scatterGraph_diagnostics.Plots.Add(new ScatterPlot()); scatterGraph_diagnostics.Plots[c].PlotXY(freqs, gains[c]); textBox_diagnosticsResults.Text += "Channel " + (c + 1).ToString() + "\r\n\tFrequency (Hz)\tGain (dB)\r\n"; for (int f = 0; f < freqs.GetLength(0); ++f) { textBox_diagnosticsResults.Text += "\t" + freqs[f].ToString() + "\t" + gains[c][f].ToString() + "\r\n"; } textBox_diagnosticsResults.Text += "\r\n"; } scatterGraph_diagnostics.Refresh(); } buttonStart.Enabled = true; button_computeGain.Enabled = true; //Now, destroy the objects we made updateSettings(); gains = null; diagnosticsReaders = null; }
private double[] CreateSignal() { //Try catch untuk semua parameter yang akan digunakan (freq,amp,phase,sampleSize,samplingRate) double[] signal = new double[sampleSize]; switch (signalType) { case "Sine": SineSignal _sineSignal = new SineSignal(frequency, amplitude, phase); signal = _sineSignal.Generate(samplingRate, sampleSize); break; case "Noise": WhiteNoiseSignal _whiteNoise = new WhiteNoiseSignal(amplitude, DateTime.Now.Second); signal = _whiteNoise.Generate(samplingRate, sampleSize); break; case "Square": SquareSignal _squareSignal = new SquareSignal(frequency, amplitude, phase, dutyCycle); signal = _squareSignal.Generate(samplingRate, sampleSize); break; case "Saw": SawtoothSignal _sawSignal = new SawtoothSignal(frequency, amplitude, phase); signal = _sawSignal.Generate(samplingRate, sampleSize); break; } //SignalGenerator generator = new SignalGenerator( SignalData = signal; return signal; }
void bgWorker_DoWork(object sender, DoWorkEventArgs e) { //Measure each channel for (int c = 0; c < numChannels && !bgWorker.CancellationPending; ++c) { UInt32 MuxData = StimPulse.channel2MUX(Convert.ToDouble(startChannel + c)); //Setup digital waveform, open MUX channel stimDigitalWriter.WriteSingleSamplePort(true, MuxData); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); double numPeriodsUsed = numPeriods; for (int f = 0; f < freqs.GetLength(0) && !bgWorker.CancellationPending; ++f) { //Update progress bars bgWorker.ReportProgress(100 * (f + (c * freqs.Length)) / (numChannels * freqs.Length), new double[] { startChannel + c, freqs[f] }); //Create test wave double numSeconds = 1 / freqs[f]; if (numSeconds * numPeriods < 0.1) numPeriodsUsed = Math.Ceiling(0.1 * freqs[f]); SineSignal testWave = new SineSignal(freqs[f], commandVoltage); //Generate a 100 mV sine wave at 1000 Hz double[] testWaveValues = testWave.Generate(IMPEDANCE_SAMPLING_RATE, (long)Math.Round(numSeconds * (double)IMPEDANCE_SAMPLING_RATE)); int size = Convert.ToInt32(numSeconds * IMPEDANCE_SAMPLING_RATE); double[,] analogPulse = new double[4, size]; for (int i = 0; i < size; ++i) analogPulse[0 + 2, i] = testWaveValues[i]; impedanceRecord.Timing.SamplesPerChannel = (long)(numPeriodsUsed * size); stimAnalogTask.Timing.SamplesPerChannel = (long)(numPeriodsUsed * size); //Do numperiods cycles of sine wave //Deliver pulse stimAnalogWriter.WriteMultiSample(true, analogPulse); double[] data = impedanceReader.ReadMultiSample((int)(numPeriodsUsed * size)); #region Calculate Impedance //Remove DC offset double mData = 0.0; for (int i = 0; i < data.Length; ++i) mData += data[i]; mData /= data.Length; for (int i = 0; i < data.Length; ++i) data[i] -= mData; //Filter data with Butterworth, if checked if (useBandpassFilter) { ButterworthBandpassFilter bwfilt = new ButterworthBandpassFilter(1, IMPEDANCE_SAMPLING_RATE, freqs[f] - freqs[f] / 4, freqs[f] + freqs[f] / 4); data = bwfilt.FilterData(data); } //Use matched filter to reduce noise, if checked (slow) if (useMatchedFilter) { SineSignal wave = new SineSignal(freqs[f], 1.0); //Create a sine wave at test frequency of amplitude 1 double[] h; //filter //If data is very long, subsample by an order of magnitude if (data.Length > 1E6) { double[] dataNew = new double[(int)Math.Floor((double)data.Length / 10)]; for (int i = 0; i < dataNew.Length; ++i) dataNew[i] = data[i * 10]; data = dataNew; dataNew = null; h = wave.Generate(IMPEDANCE_SAMPLING_RATE / 10, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / (freqs[f] * 10))); //Generate one period } else { h = wave.Generate(IMPEDANCE_SAMPLING_RATE, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / freqs[f])); //Generate one period } wave = null; //Compute filter power double phh = 0.0; for (int i = 0; i < h.Length; ++i) phh += h[i] * h[i]; //Normalize filter so power is 1 for (int i = 0; i < h.Length; ++i) h[i] /= phh; //sw.Start(); double[] x = NationalInstruments.Analysis.Dsp.SignalProcessing.Convolve(data, h); //sw.Stop(); //TimeSpan ts = sw.Elapsed; //System.Diagnostics.Debug.WriteLine("ms = " + ts.Milliseconds + "\t s = " + ts.Seconds + "\t min = " + ts.Minutes); int offset = (int)(h.Length * 0.5); for (int i = 0; i < data.Length; ++i) data[i] = x[i + offset]; //Take center values } double rms = rootMeanSquared(data); if (isCurrentControlled) //Current-controlled { impedance[c][f] = rms / (0.707106704695506 * commandVoltage / RCurr); //Account for 6.8 MOhm resistor in parallel impedance[c][f] = 1.0 / (1.0 / impedance[c][f] - 1.0 / 6800000.0); } else //Voltage-controlled { double gain = 1.0 + (49400.0 / RGain); //Based on LT in-amp impedance[c][f] = (0.707106704695506 * commandVoltage) / ((rms / gain) / RMeas); } #endregion //Wait until recording and stim are finished stimAnalogTask.WaitUntilDone(); impedanceRecord.WaitUntilDone(); stimAnalogTask.Stop(); impedanceRecord.Stop(); } //De-select channel on mux stimDigitalWriter.WriteSingleSamplePort(true, 0); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); //Notify that channel is done if (alertChannelFinished != null) alertChannelFinished(this, c, startChannel + c, impedance, freqs); } //Reset muxes bool[] fData = new bool[Properties.Settings.Default.StimPortBandwidth]; stimDigitalWriter.WriteSingleSampleMultiLine(true, fData); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); }
private void analogInCallback_impedance(IAsyncResult ar) { double[] state = (double[])ar.AsyncState; int ch = (int)state[0]; double f = state[1]; double[] data = impedanceReader.EndReadMultiSample(ar); //Remove DC offset double mData = 0.0; for (int i = 0; i < data.Length; ++i) mData += data[i]; mData /= data.Length; for (int i = 0; i < data.Length; ++i) data[i] -= mData; //Filter data with Butterworth, if checked if (useBandpassFilter) { ButterworthBandpassFilter bwfilt = new ButterworthBandpassFilter(1, IMPEDANCE_SAMPLING_RATE, f - f / 4, f + f / 4); data = bwfilt.FilterData(data); } //Use matched filter to reduce noise, if checked (slow) if (useMatchedFilter) { //System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); SineSignal wave = new SineSignal(f, 1.0); //Create a sine wave at test frequency of amplitude 1 double[] h; //filter //If data is very long, subsample by an order of magnitude if (data.Length > 1E6) { double[] dataNew = new double[(int)Math.Floor((double)data.Length / 10)]; for (int i = 0; i < dataNew.Length; ++i) dataNew[i] = data[i * 10]; data = dataNew; dataNew = null; h = wave.Generate(IMPEDANCE_SAMPLING_RATE / 10, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / (f * 10))); //Generate one period } else { h = wave.Generate(IMPEDANCE_SAMPLING_RATE, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / f)); //Generate one period } wave = null; //GC.Collect(); //this uses a lot of memory //Compute filter power double phh = 0.0; for (int i = 0; i < h.Length; ++i) phh += h[i] * h[i]; //Normalize filter so power is 1 for (int i = 0; i < h.Length; ++i) h[i] /= phh; //sw.Start(); double[] x = NationalInstruments.Analysis.Dsp.SignalProcessing.Convolve(data, h); //sw.Stop(); //TimeSpan ts = sw.Elapsed; //System.Diagnostics.Debug.WriteLine("ms = " + ts.Milliseconds + "\t s = " + ts.Seconds + "\t min = " + ts.Minutes); int offset = (int)(h.Length * 0.5); for (int i = 0; i < data.Length; ++i) data[i] = x[i + offset]; //Take center values } double rms = rootMeanSquared(data); if (Convert.ToBoolean(state[3])) //Current-controlled { impedance[ch][(int)state[2]] = rms / (0.707106704695506 * commandVoltage / RCurr); //Account for 6.8 MOhm resistor in parallel impedance[ch][(int)state[2]] = 1.0 / (1.0 / impedance[ch][(int)state[2]] - 1.0 / 6800000.0); } else //Voltage-controlled { double gain = 1.0 + (49400.0 / RGain); //Based on LT in-amp impedance[ch][(int)state[2]] = (0.707106704695506 * commandVoltage) / ((rms / gain) / RMeas); } }
private void button_computeGain_Click(object sender, EventArgs e) { double startFreq = Convert.ToDouble(numericUpDown_startFreq.Value); double stopFreq = Convert.ToDouble(numericUpDown_stopFreq.Value); double numPeriods = Convert.ToDouble(numericUpDown_numPeriods.Value); double[] freqs = new double[1 + Convert.ToInt32(Math.Floor(Math.Log(stopFreq / startFreq) / Math.Log(Convert.ToDouble(textBox_diagnosticsMult.Text))))]; //This determines the number of frequencies counting by doublings radioButton_stimVoltageControlled.Checked = true; radioButton_stimVoltageControlled_Click(null, null); //Populate freqs vector freqs[0] = startFreq; for (int i = 1; i < freqs.GetLength(0); ++i) freqs[i] = freqs[i - 1] * Convert.ToDouble(textBox_diagnosticsMult.Text); spikeSamplingRate = Properties.Settings.Default.RawSampleFrequency; buttonStart.Enabled = false; //So users can't try to get data from the same card button_computeGain.Enabled = false; button_computeGain.Refresh(); buttonStart.Refresh(); spikeTask = new List<Task>(Properties.Settings.Default.AnalogInDevice.Count); diagnosticsReaders = new List<AnalogMultiChannelReader>(Properties.Settings.Default.AnalogInDevice.Count); for (int i = 0; i < Properties.Settings.Default.AnalogInDevice.Count; ++i) { spikeTask.Add(new Task("spikeTask_Diagnostics_" + i)); int numChannelsPerDevice = (numChannels < 32 ? numChannels : 32); for (int j = 0; j < numChannelsPerDevice; ++j) spikeTask[i].AIChannels.CreateVoltageChannel(Properties.Settings.Default.AnalogInDevice[0] + "/ai" + j.ToString(), "", AITerminalConfiguration.Nrse, -10.0, 10.0, AIVoltageUnits.Volts); //Change gain based on comboBox values (1-100) setGain(spikeTask[i], Properties.Settings.Default.A2Dgain); //Verify the Task spikeTask[i].Control(TaskAction.Verify); spikeTask[i].Timing.ConfigureSampleClock("", spikeSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples); diagnosticsReaders.Add(new AnalogMultiChannelReader(spikeTask[i].Stream)); } spikeTask[0].Timing.ReferenceClockSource = "OnboardClock"; for (int i = 1; i < spikeTask.Count; ++i) { spikeTask[i].Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource; spikeTask[i].Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate; } stimPulseTask.Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource; stimPulseTask.Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate; stimDigitalTask.Dispose(); stimDigitalTask = new Task("stimDigitalTask"); if (Properties.Settings.Default.StimPortBandwidth == 32) stimDigitalTask.DOChannels.CreateChannel(Properties.Settings.Default.StimulatorDevice + "/Port0/line0:31", "", ChannelLineGrouping.OneChannelForAllLines); //To control MUXes else if (Properties.Settings.Default.StimPortBandwidth == 8) stimDigitalTask.DOChannels.CreateChannel(Properties.Settings.Default.StimulatorDevice + "/Port0/line0:7", "", ChannelLineGrouping.OneChannelForAllLines); //To control MUXes stimDigitalWriter = new DigitalSingleChannelWriter(stimDigitalTask.Stream); stimPulseTask.Timing.ConfigureSampleClock("/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/SampleClock", spikeSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples); stimPulseTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/StartTrigger", DigitalEdgeStartTriggerEdge.Rising); stimDigitalTask.Control(TaskAction.Verify); stimPulseTask.Control(TaskAction.Verify); switch (Properties.Settings.Default.NumChannels) { case 0: numChannels = 16; break; case 1: numChannels = 32; break; case 2: numChannels = 48; break; case 3: numChannels = 64; break; } //gains = new double[numChannels, freqs.GetLength(0)]; //numChannels = 1; gains = new double[numChannels][]; for (int i = 0; i < numChannels; ++i) gains[i] = new double[freqs.GetLength(0)]; scatterGraph_diagnostics.ClearData(); scatterGraph_diagnostics.Plots.Clear(); textBox_diagnosticsResults.Clear(); if (!checkBox_diagnosticsBulk.Checked) { //for (int c = 1; c <= numChannels; ++c) for (int c = 13; c < 14; ++c) { textBox_diagnosticsResults.Text += "Channel " + c.ToString() + "\r\n\tFrequency (Hz)\tGain (dB)\r\n"; scatterGraph_diagnostics.Plots.Add(new ScatterPlot()); UInt32 data = StimPulse.channel2MUX((double)c); //Get data bits lined up to control MUXes //Setup digital waveform stimDigitalWriter.WriteSingleSamplePort(true, data); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); for (int f = 0; f < freqs.GetLength(0); ++f) { double numSeconds = 1 / freqs[f]; if (numSeconds * numPeriods < 0.1) { numPeriods = Math.Ceiling(0.1 * freqs[f]); } int size = Convert.ToInt32(numSeconds * spikeSamplingRate); SineSignal testWave = new SineSignal(freqs[f], Convert.ToDouble(numericUpDown_diagnosticsVoltage.Value)); //Generate a 100 mV sine wave at 1000 Hz double[] testWaveValues = testWave.Generate(spikeSamplingRate, size); double[,] analogPulse = new double[2, size]; for (int i = 0; i < size; ++i) analogPulse[0, i] = testWaveValues[i]; for (int i = 0; i < spikeTask.Count; ++i) spikeTask[i].Timing.SamplesPerChannel = (long)(numPeriods * size); stimPulseTask.Timing.SamplesPerChannel = (long)(numPeriods * size); //Do numperiods cycles of sine wave stimPulseWriter.WriteMultiSample(true, analogPulse); double[] stateData = new double[4]; stateData[0] = (double)c; stateData[1] = freqs[f]; stateData[2] = (double)f; for (int i = diagnosticsReaders.Count - 1; i >= 0; --i) { stateData[3] = (double)i; diagnosticsReaders[i].BeginReadMultiSample((int)(numPeriods * size), analogInCallback_computeGain, (Object)stateData); //Get 5 seconds of "noise" } stimPulseTask.WaitUntilDone(); for (int i = 0; i < spikeTask.Count; ++i) { spikeTask[i].WaitUntilDone(); spikeTask[i].Stop(); } stimPulseTask.Stop(); } stimDigitalWriter.WriteSingleSamplePort(true, 0); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); //DEBUGGING c = 1; scatterGraph_diagnostics.Plots[c - 1].PlotXY(freqs, gains[c - 1]); for (int f = 0; f < freqs.GetLength(0); ++f) { textBox_diagnosticsResults.Text += "\t" + freqs[f].ToString() + "\t" + gains[c - 1][f] + "\r\n"; } textBox_diagnosticsResults.Text += "\r\n"; scatterGraph_diagnostics.Refresh(); //DEBUGGING c = 100; } } else { for (int f = 0; f < freqs.GetLength(0); ++f) { double numSeconds = 1 / freqs[f]; if (numSeconds * numPeriods < 0.1) { numPeriods = Math.Ceiling(0.1 * freqs[f]); } int size = Convert.ToInt32(numSeconds * spikeSamplingRate); SineSignal testWave = new SineSignal(freqs[f], Convert.ToDouble(numericUpDown_diagnosticsVoltage.Value)); //Generate a 100 mV sine wave at 1000 Hz double[] testWaveValues = testWave.Generate(spikeSamplingRate, size); double[,] analogPulse = new double[2, size]; for (int i = 0; i < size; ++i) analogPulse[0, i] = testWaveValues[i]; for (int i = 0; i < spikeTask.Count; ++i) spikeTask[i].Timing.SamplesPerChannel = (long)(numPeriods * size); stimPulseTask.Timing.SamplesPerChannel = (long)(numPeriods * size); //Do numperiods cycles of sine wave stimPulseWriter.WriteMultiSample(true, analogPulse); double[] stateData = new double[4]; stateData[0] = -1.0; stateData[1] = freqs[f]; stateData[2] = (double)f; //Frequency of interest for (int i = diagnosticsReaders.Count - 1; i >= 0; --i) { stateData[3] = (double)i; //Keeps track of which device called the reader diagnosticsReaders[i].BeginReadMultiSample((int)(numPeriods * size), analogInCallback_computeGain, (Object)stateData); //Get 5 seconds of "noise" } stimPulseTask.WaitUntilDone(); for (int i = 0; i < spikeTask.Count; ++i) { spikeTask[i].WaitUntilDone(); spikeTask[i].Stop(); } stimPulseTask.Stop(); } for (int c = 0; c < numChannels; ++c) { scatterGraph_diagnostics.Plots.Add(new ScatterPlot()); scatterGraph_diagnostics.Plots[c].PlotXY(freqs, gains[c]); textBox_diagnosticsResults.Text += "Channel " + (c + 1).ToString() + "\r\n\tFrequency (Hz)\tGain (dB)\r\n"; for (int f = 0; f < freqs.GetLength(0); ++f) { textBox_diagnosticsResults.Text += "\t" + freqs[f].ToString() + "\t" + gains[c][f].ToString() + "\r\n"; } textBox_diagnosticsResults.Text += "\r\n"; } scatterGraph_diagnostics.Refresh(); } buttonStart.Enabled = true; button_computeGain.Enabled = true; //Now, destroy the objects we made updateSettings(); gains = null; diagnosticsReaders = null; }
private void analogInCallback_impedance(IAsyncResult ar) { double[] state = (double[])ar.AsyncState; int ch = (int)state[0]; double f = state[1]; double[] data = impedanceReader.EndReadMultiSample(ar); //Remove DC offset double mData = 0.0; for (int i = 0; i < data.Length; ++i) { mData += data[i]; } mData /= data.Length; for (int i = 0; i < data.Length; ++i) { data[i] -= mData; } //Filter data with Butterworth, if checked if (useBandpassFilter) { ButterworthBandpassFilter bwfilt = new ButterworthBandpassFilter(1, IMPEDANCE_SAMPLING_RATE, f - f / 4, f + f / 4); data = bwfilt.FilterData(data); } //Use matched filter to reduce noise, if checked (slow) if (useMatchedFilter) { //System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); SineSignal wave = new SineSignal(f, 1.0); //Create a sine wave at test frequency of amplitude 1 double[] h; //filter //If data is very long, subsample by an order of magnitude if (data.Length > 1E6) { double[] dataNew = new double[(int)Math.Floor((double)data.Length / 10)]; for (int i = 0; i < dataNew.Length; ++i) { dataNew[i] = data[i * 10]; } data = dataNew; dataNew = null; h = wave.Generate(IMPEDANCE_SAMPLING_RATE / 10, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / (f * 10))); //Generate one period } else { h = wave.Generate(IMPEDANCE_SAMPLING_RATE, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / f)); //Generate one period } wave = null; //GC.Collect(); //this uses a lot of memory //Compute filter power double phh = 0.0; for (int i = 0; i < h.Length; ++i) { phh += h[i] * h[i]; } //Normalize filter so power is 1 for (int i = 0; i < h.Length; ++i) { h[i] /= phh; } //sw.Start(); double[] x = NationalInstruments.Analysis.Dsp.SignalProcessing.Convolve(data, h); //sw.Stop(); //TimeSpan ts = sw.Elapsed; //System.Diagnostics.Debug.WriteLine("ms = " + ts.Milliseconds + "\t s = " + ts.Seconds + "\t min = " + ts.Minutes); int offset = (int)(h.Length * 0.5); for (int i = 0; i < data.Length; ++i) { data[i] = x[i + offset]; //Take center values } } double rms = rootMeanSquared(data); if (Convert.ToBoolean(state[3])) //Current-controlled { impedance[ch][(int)state[2]] = rms / (0.707106704695506 * commandVoltage / RCurr); //Account for 6.8 MOhm resistor in parallel impedance[ch][(int)state[2]] = 1.0 / (1.0 / impedance[ch][(int)state[2]] - 1.0 / 6800000.0); } else //Voltage-controlled { double gain = 1.0 + (49400.0 / RGain); //Based on LT in-amp impedance[ch][(int)state[2]] = (0.707106704695506 * commandVoltage) / ((rms / gain) / RMeas); } }
void bgWorker_DoWork(object sender, DoWorkEventArgs e) { //Measure each channel for (int c = 0; c < numChannels && !bgWorker.CancellationPending; ++c) { UInt32 MuxData = StimPulse.channel2MUX(Convert.ToDouble(startChannel + c)); //Setup digital waveform, open MUX channel stimDigitalWriter.WriteSingleSamplePort(true, MuxData); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); double numPeriodsUsed = numPeriods; for (int f = 0; f < freqs.GetLength(0) && !bgWorker.CancellationPending; ++f) { //Update progress bars bgWorker.ReportProgress(100 * (f + (c * freqs.Length)) / (numChannels * freqs.Length), new double[] { startChannel + c, freqs[f] }); //Create test wave double numSeconds = 1 / freqs[f]; if (numSeconds * numPeriods < 0.1) { numPeriodsUsed = Math.Ceiling(0.1 * freqs[f]); } SineSignal testWave = new SineSignal(freqs[f], commandVoltage); //Generate a 100 mV sine wave at 1000 Hz double[] testWaveValues = testWave.Generate(IMPEDANCE_SAMPLING_RATE, (long)Math.Round(numSeconds * (double)IMPEDANCE_SAMPLING_RATE)); int size = Convert.ToInt32(numSeconds * IMPEDANCE_SAMPLING_RATE); double[,] analogPulse = new double[4, size]; for (int i = 0; i < size; ++i) { analogPulse[0 + 2, i] = testWaveValues[i]; } impedanceRecord.Timing.SamplesPerChannel = (long)(numPeriodsUsed * size); stimAnalogTask.Timing.SamplesPerChannel = (long)(numPeriodsUsed * size); //Do numperiods cycles of sine wave //Deliver pulse stimAnalogWriter.WriteMultiSample(true, analogPulse); double[] data = impedanceReader.ReadMultiSample((int)(numPeriodsUsed * size)); #region Calculate Impedance //Remove DC offset double mData = 0.0; for (int i = 0; i < data.Length; ++i) { mData += data[i]; } mData /= data.Length; for (int i = 0; i < data.Length; ++i) { data[i] -= mData; } //Filter data with Butterworth, if checked if (useBandpassFilter) { ButterworthBandpassFilter bwfilt = new ButterworthBandpassFilter(1, IMPEDANCE_SAMPLING_RATE, freqs[f] - freqs[f] / 4, freqs[f] + freqs[f] / 4); data = bwfilt.FilterData(data); } //Use matched filter to reduce noise, if checked (slow) if (useMatchedFilter) { SineSignal wave = new SineSignal(freqs[f], 1.0); //Create a sine wave at test frequency of amplitude 1 double[] h; //filter //If data is very long, subsample by an order of magnitude if (data.Length > 1E6) { double[] dataNew = new double[(int)Math.Floor((double)data.Length / 10)]; for (int i = 0; i < dataNew.Length; ++i) { dataNew[i] = data[i * 10]; } data = dataNew; dataNew = null; h = wave.Generate(IMPEDANCE_SAMPLING_RATE / 10, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / (freqs[f] * 10))); //Generate one period } else { h = wave.Generate(IMPEDANCE_SAMPLING_RATE, (long)Math.Round((double)IMPEDANCE_SAMPLING_RATE / freqs[f])); //Generate one period } wave = null; //Compute filter power double phh = 0.0; for (int i = 0; i < h.Length; ++i) { phh += h[i] * h[i]; } //Normalize filter so power is 1 for (int i = 0; i < h.Length; ++i) { h[i] /= phh; } //sw.Start(); double[] x = NationalInstruments.Analysis.Dsp.SignalProcessing.Convolve(data, h); //sw.Stop(); //TimeSpan ts = sw.Elapsed; //System.Diagnostics.Debug.WriteLine("ms = " + ts.Milliseconds + "\t s = " + ts.Seconds + "\t min = " + ts.Minutes); int offset = (int)(h.Length * 0.5); for (int i = 0; i < data.Length; ++i) { data[i] = x[i + offset]; //Take center values } } double rms = rootMeanSquared(data); if (isCurrentControlled) //Current-controlled { impedance[c][f] = rms / (0.707106704695506 * commandVoltage / RCurr); //Account for 6.8 MOhm resistor in parallel impedance[c][f] = 1.0 / (1.0 / impedance[c][f] - 1.0 / 6800000.0); } else //Voltage-controlled { double gain = 1.0 + (49400.0 / RGain); //Based on LT in-amp impedance[c][f] = (0.707106704695506 * commandVoltage) / ((rms / gain) / RMeas); } #endregion //Wait until recording and stim are finished stimAnalogTask.WaitUntilDone(); impedanceRecord.WaitUntilDone(); stimAnalogTask.Stop(); impedanceRecord.Stop(); } //De-select channel on mux stimDigitalWriter.WriteSingleSamplePort(true, 0); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); //Notify that channel is done if (alertChannelFinished != null) { alertChannelFinished(this, c, startChannel + c, impedance, freqs); } } //Reset muxes bool[] fData = new bool[Properties.Settings.Default.StimPortBandwidth]; stimDigitalWriter.WriteSingleSampleMultiLine(true, fData); stimDigitalTask.WaitUntilDone(); stimDigitalTask.Stop(); }