diff --git a/Directory.Build.props b/Directory.Build.props index d12448f..6266d68 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ LICENSE true icon.png - 0.4.0 + 0.4.1 10.0 strict diff --git a/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs b/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs index 34de646..b1fb528 100644 --- a/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs +++ b/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using ZedGraph; using System.IO; +using System.Collections.Generic; namespace OpenEphys.Onix1.Design { @@ -258,22 +259,24 @@ private void DrawStimulusWaveform() if (ChannelDialog.SelectedContacts[i] || plotAllContacts) { - PointPairList pointPairs = CreateStimulusWaveform(stimuli[i], channelOffset, peakToPeak); + List pulses = CreatePulses(stimuli[i], channelOffset, peakToPeak); - Color color; - if (stimuli[i].IsValid()) - { - color = Color.CornflowerBlue; - } - else + foreach (var pulse in pulses) { - color = Color.Red; + var pulseCurve = zedGraphWaveform.GraphPane.AddCurve("", pulse, Color.Red, SymbolType.None); + + pulseCurve.Label.IsVisible = false; + pulseCurve.Line.Width = 4; } - var curve = zedGraphWaveform.GraphPane.AddCurve("", pointPairs, color, SymbolType.None); + PointPairList pointPairs = CreateStimulusWaveform(stimuli[i], channelOffset, peakToPeak); + + Color color = stimuli[i].IsValid() ? Color.CornflowerBlue : Color.DarkRed; + + var waveformCurve = zedGraphWaveform.GraphPane.AddCurve("", pointPairs, color, SymbolType.None); - curve.Label.IsVisible = false; - curve.Line.Width = 3; + waveformCurve.Label.IsVisible = false; + waveformCurve.Line.Width = 2; maxLength = pointPairs.Last().X > maxLength ? pointPairs.Last().X : maxLength; } @@ -296,7 +299,7 @@ private void DrawStimulusWaveform() SetZoomOutBoundaries(zedGraphWaveform); - ZoomInBoundaryX = (ZoomOutBoundaryRight - ZoomOutBoundaryLeft) * 0.05; + ZoomInBoundaryX = (ZoomOutBoundaryRight - ZoomOutBoundaryLeft) * 0.01; dataGridViewStimulusTable.Refresh(); @@ -375,23 +378,19 @@ private PointPairList CreateStimulusWaveform(Rhs2116Stimulus stimulus, double yO for (int i = 0; i < stimulus.NumberOfStimuli; i++) { - double amplitude = (stimulus.AnodicFirst ? stimulus.AnodicAmplitudeSteps : -stimulus.CathodicAmplitudeSteps) * Sequence.CurrentStepSizeuA / peakToPeak + yOffset; - double width = (stimulus.AnodicFirst ? stimulus.AnodicWidthSamples : stimulus.CathodicWidthSamples) * SamplePeriodMilliSeconds; + double amplitude = CalculateFirstPulseAmplitude(stimulus.AnodicFirst, stimulus.AnodicAmplitudeSteps, stimulus.CathodicAmplitudeSteps, peakToPeak, yOffset); + double width = CalculateFirstPulseWidth(stimulus.AnodicFirst, stimulus.AnodicWidthSamples, stimulus.CathodicWidthSamples); - points.Add(points[points.Count - 1].X, amplitude); - points.Add(points[points.Count - 1].X + width, amplitude); - points.Add(points[points.Count - 1].X, yOffset); + points.AddRange(CreatePulse(points[points.Count - 1].X, amplitude, width, yOffset)); - points.Add(points[points.Count - 1].X + stimulus.DwellSamples * SamplePeriodMilliSeconds, yOffset); + points.Add(points.Last().X + stimulus.DwellSamples * SamplePeriodMilliSeconds, yOffset); - amplitude = (stimulus.AnodicFirst ? -stimulus.CathodicAmplitudeSteps : stimulus.AnodicAmplitudeSteps) * Sequence.CurrentStepSizeuA / peakToPeak + yOffset; - width = (stimulus.AnodicFirst ? stimulus.CathodicWidthSamples : stimulus.AnodicWidthSamples) * SamplePeriodMilliSeconds; + amplitude = CalculateSecondPulseAmplitude(stimulus.AnodicFirst, stimulus.AnodicAmplitudeSteps, stimulus.CathodicAmplitudeSteps, peakToPeak, yOffset); + width = CalculateSecondPulseWidth(stimulus.AnodicFirst, stimulus.AnodicWidthSamples, stimulus.CathodicWidthSamples); - points.Add(points[points.Count - 1].X, amplitude); - points.Add(points[points.Count - 1].X + width, amplitude); - points.Add(points[points.Count - 1].X, yOffset); + points.AddRange(CreatePulse(points[points.Count - 1].X, amplitude, width, yOffset)); - points.Add(points[points.Count - 1].X + stimulus.InterStimulusIntervalSamples * SamplePeriodMilliSeconds, yOffset); + points.Add(points.Last().X + stimulus.InterStimulusIntervalSamples * SamplePeriodMilliSeconds, yOffset); } points.Add(Sequence.SequenceLengthSamples * SamplePeriodMilliSeconds, yOffset); @@ -399,6 +398,76 @@ private PointPairList CreateStimulusWaveform(Rhs2116Stimulus stimulus, double yO return points; } + /// + /// Only create the pulses, so that they can be plotted as an overlay on top of the full waveform to highlight individual pulses + /// + /// + /// + /// + /// + private List CreatePulses(Rhs2116Stimulus stimulus, double yOffset, double peakToPeak) + { + yOffset /= peakToPeak; + + var pulses = new List(); + + for (int i = 0; i < stimulus.NumberOfStimuli; i++) + { + PointPairList pulse = new(); + + if (i == 0) + pulse.Add(stimulus.DelaySamples * SamplePeriodMilliSeconds, yOffset); + else + pulse.Add(pulses.Last().Last().X + stimulus.InterStimulusIntervalSamples * SamplePeriodMilliSeconds, yOffset); + + double amplitude = CalculateFirstPulseAmplitude(stimulus.AnodicFirst, stimulus.AnodicAmplitudeSteps, stimulus.CathodicAmplitudeSteps, peakToPeak, yOffset); + double width = CalculateFirstPulseWidth(stimulus.AnodicFirst, stimulus.AnodicWidthSamples, stimulus.CathodicWidthSamples); + + pulse.AddRange(CreatePulse(pulse[pulse.Count - 1].X, amplitude, width, yOffset)); + + pulse.Add(pulse[pulse.Count - 1].X + stimulus.DwellSamples * SamplePeriodMilliSeconds, yOffset); + + amplitude = CalculateSecondPulseAmplitude(stimulus.AnodicFirst, stimulus.AnodicAmplitudeSteps, stimulus.CathodicAmplitudeSteps, peakToPeak, yOffset); + width = CalculateSecondPulseWidth(stimulus.AnodicFirst, stimulus.AnodicWidthSamples, stimulus.CathodicWidthSamples); + + pulse.AddRange(CreatePulse(pulse[pulse.Count - 1].X, amplitude, width, yOffset)); + + pulses.Add(pulse); + } + + return pulses; + } + + private double CalculateSecondPulseWidth(bool anodicFirst, uint anodicWidthSamples, uint cathodicWidthSamples) + { + return (anodicFirst ? cathodicWidthSamples : anodicWidthSamples) * SamplePeriodMilliSeconds; + } + + private double CalculateSecondPulseAmplitude(bool anodicFirst, byte anodicAmplitudeSteps, byte cathodicAmplitudeSteps, double peakToPeak, double yOffset) + { + return (anodicFirst ? -cathodicAmplitudeSteps : anodicAmplitudeSteps) * Sequence.CurrentStepSizeuA / peakToPeak + yOffset; + } + + private List CreatePulse(double x, double amplitude, double width, double yOffset) + { + return new List() + { + { new PointPair(x, amplitude) }, + { new PointPair(x + width, amplitude) }, + { new PointPair(x + width, yOffset) }, + }; + } + + private double CalculateFirstPulseWidth(bool anodicFirst, uint anodicWidthSamples, uint cathodicWidthSamples) + { + return (anodicFirst ? anodicWidthSamples : cathodicWidthSamples) * SamplePeriodMilliSeconds; + } + + private double CalculateFirstPulseAmplitude(bool anodicFirst, byte anodicAmplitudeSteps, byte cathodicAmplitudeSteps, double peakToPeak, double yOffset) + { + return (anodicFirst ? anodicAmplitudeSteps : -cathodicAmplitudeSteps) * Sequence.CurrentStepSizeuA / peakToPeak + yOffset; + } + private void InitializeZedGraphWaveform() { zedGraphWaveform.IsZoomOnMouseCenter = true;