Skip to content

Commit

Permalink
- Remove unused methods, remove unnecessary virtual identifiers
Browse files Browse the repository at this point in the history
- Ensure that stimulus timings are correctly saved and applied automatically
  • Loading branch information
bparks13 committed Nov 18, 2024
1 parent d7d9b1d commit 955de67
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 109 deletions.
79 changes: 43 additions & 36 deletions OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ namespace OpenEphys.Onix1.Design
/// </summary>
public partial class Rhs2116StimulusSequenceDialog : Form
{
/// <summary>
/// Double defining the length of a single time sample, in milliseconds.
/// </summary>
const double SamplePeriodMilliSeconds = 1e3 / Rhs2116.SampleFrequencyHz;

internal Rhs2116StimulusSequencePair Sequence { get; set; }

private readonly Rhs2116StimulusSequencePair SequenceCopy = new();

private readonly double[] RequestedAnodicAmplitudeuA;
private readonly double[] RequestedCathodicAmplitudeuA;

/// <summary>
/// Holds the step size that is displayed in the text box of the GUI. This is not the step size that is saved for the stimulus sequence object.
/// </summary>
Expand All @@ -37,18 +45,13 @@ public Rhs2116StimulusSequenceDialog(Rhs2116StimulusSequencePair sequence, Rhs21
Shown += FormShown;

Sequence = new Rhs2116StimulusSequencePair(sequence);
RequestedAnodicAmplitudeuA = new double[Sequence.Stimuli.Length];
RequestedCathodicAmplitudeuA = new double[Sequence.Stimuli.Length];

foreach (var stimulus in Sequence.Stimuli)
for (int i = 0; i < Sequence.Stimuli.Length; i++)
{
if (stimulus.RequestedAnodicAmplitudeuA == 0.0 && stimulus.AnodicAmplitudeSteps > 0)
{
stimulus.RequestedAnodicAmplitudeuA = GetAmplitudeFromSample(stimulus.AnodicAmplitudeSteps, Sequence.CurrentStepSize);
}

if (stimulus.RequestedCathodicAmplitudeuA == 0.0 && stimulus.CathodicAmplitudeSteps > 0)
{
stimulus.RequestedCathodicAmplitudeuA = GetAmplitudeFromSample(stimulus.CathodicAmplitudeSteps, Sequence.CurrentStepSize);
}
RequestedAnodicAmplitudeuA[i] = Sequence.Stimuli[i].AnodicAmplitudeSteps * Sequence.CurrentStepSizeuA;
RequestedCathodicAmplitudeuA[i] = Sequence.Stimuli[i].CathodicAmplitudeSteps * Sequence.CurrentStepSizeuA;
}

StepSize = Sequence.CurrentStepSize;
Expand Down Expand Up @@ -382,31 +385,31 @@ private PointPairList CreateStimulusWaveform(Rhs2116Stimulus stimulus, double yO
PointPairList points = new()
{
{ 0, yOffset },
{ stimulus.DelaySamples * Rhs2116Stimulus.SamplePeriodMilliSeconds, yOffset }
{ stimulus.DelaySamples * SamplePeriodMilliSeconds, yOffset }
};

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) * Rhs2116Stimulus.SamplePeriodMilliSeconds;
double width = (stimulus.AnodicFirst ? stimulus.AnodicWidthSamples : stimulus.CathodicWidthSamples) * SamplePeriodMilliSeconds;

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.Add(points[points.Count - 1].X + stimulus.DwellSamples * Rhs2116Stimulus.SamplePeriodMilliSeconds, yOffset);
points.Add(points[points.Count - 1].X + stimulus.DwellSamples * SamplePeriodMilliSeconds, yOffset);

amplitude = (stimulus.AnodicFirst ? -stimulus.CathodicAmplitudeSteps : stimulus.AnodicAmplitudeSteps) * Sequence.CurrentStepSizeuA / peakToPeak + yOffset;
width = (stimulus.AnodicFirst ? stimulus.CathodicWidthSamples : stimulus.AnodicWidthSamples) * Rhs2116Stimulus.SamplePeriodMilliSeconds;
width = (stimulus.AnodicFirst ? stimulus.CathodicWidthSamples : stimulus.AnodicWidthSamples) * SamplePeriodMilliSeconds;

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.Add(points[points.Count - 1].X + stimulus.InterStimulusIntervalSamples * Rhs2116Stimulus.SamplePeriodMilliSeconds, yOffset);
points.Add(points[points.Count - 1].X + stimulus.InterStimulusIntervalSamples * SamplePeriodMilliSeconds, yOffset);
}

points.Add(Sequence.SequenceLengthSamples * Rhs2116Stimulus.SamplePeriodMilliSeconds, yOffset);
points.Add(Sequence.SequenceLengthSamples * SamplePeriodMilliSeconds, yOffset);

return points;
}
Expand Down Expand Up @@ -642,20 +645,20 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)
.Where(s => s.Stimulus.Valid
&& (s.Stimulus.AnodicAmplitudeSteps != 0
|| s.Stimulus.CathodicAmplitudeSteps != 0
|| (s.Stimulus.AnodicAmplitudeSteps == 0 && s.Stimulus.RequestedAnodicAmplitudeuA != 0.0)
|| (s.Stimulus.CathodicAmplitudeSteps == 0 && s.Stimulus.RequestedCathodicAmplitudeuA != 0.0))
|| (s.Stimulus.AnodicAmplitudeSteps == 0 && RequestedAnodicAmplitudeuA[s.Index] != 0.0)
|| (s.Stimulus.CathodicAmplitudeSteps == 0 && RequestedCathodicAmplitudeuA[s.Index] != 0.0))
&& !ChannelDialog.SelectedContacts[s.Index])
.Select(s =>
{
GetSampleFromAmplitude(s.Stimulus.RequestedAnodicAmplitudeuA, out var requestedAnodicSteps);
GetSampleFromAmplitude(RequestedAnodicAmplitudeuA[s.Index], out var requestedAnodicSteps);
var requestedAnodicError = s.Stimulus.AnodicAmplitudeSteps == 0
? GetAmplitudeFromSample(requestedAnodicSteps, StepSize)
: CalculateAmplitudePercentError(s.Stimulus.RequestedAnodicAmplitudeuA, StepSize);
: CalculateAmplitudePercentError(RequestedAnodicAmplitudeuA[s.Index], StepSize);

GetSampleFromAmplitude(s.Stimulus.RequestedCathodicAmplitudeuA, out var requestedCathodicSteps);
GetSampleFromAmplitude(RequestedCathodicAmplitudeuA[s.Index], out var requestedCathodicSteps);
var requestedCathodicError = s.Stimulus.CathodicAmplitudeSteps == 0
? GetAmplitudeFromSample(requestedCathodicSteps, StepSize)
: CalculateAmplitudePercentError(s.Stimulus.RequestedCathodicAmplitudeuA, StepSize);
: CalculateAmplitudePercentError(RequestedCathodicAmplitudeuA[s.Index], StepSize);

return (s.Index,
ErrorAnodic: requestedAnodicError,
Expand Down Expand Up @@ -702,15 +705,15 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)
{
if (Sequence.Stimuli[Index].AnodicAmplitudeSteps != 0 && Sequence.Stimuli[Index].CathodicAmplitudeSteps != 0)
{
SequenceCopy.Stimuli[Index].CopyStimulus(Sequence.Stimuli[Index]); // NB: Store the current pulse pattern before clearing
Sequence.Stimuli[Index].Clear(clearRequestedAmplitudes: false);
SequenceCopy.UpdateStimulus(Sequence.Stimuli[Index], Index); // NB: Store the current pulse pattern before clearing
Sequence.Stimuli[Index].Clear();
}
}
else
{
if (Sequence.Stimuli[Index].NumberOfStimuli == 0 && SequenceCopy.Stimuli[Index].IsValid() && SequenceCopy.Stimuli[Index].NumberOfStimuli != 0)
{
Sequence.Stimuli[Index].CopyStimulus(SequenceCopy.Stimuli[Index]); // NB: Restore pulse timings before adding amplitude steps
Sequence.UpdateStimulus(SequenceCopy.Stimuli[Index], Index); // NB: Restore pulse timings before adding amplitude steps
}
else if (Sequence.Stimuli[Index].NumberOfStimuli == 0 && SequenceCopy.Stimuli[Index].NumberOfStimuli != 0) continue;

Expand All @@ -719,6 +722,8 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)
}
}

dataGridViewStimulusTable.DataSource = Sequence.Stimuli; // NB: Force an update in case pulse timings were restored

for (int i = 0; i < ChannelDialog.SelectedContacts.Length; i++)
{
if (ChannelDialog.SelectedContacts[i])
Expand All @@ -730,7 +735,7 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)

if (textboxAmplitudeAnodicRequested.Tag != null)
{
Sequence.Stimuli[i].RequestedAnodicAmplitudeuA = (double)textboxAmplitudeAnodicRequested.Tag;
RequestedAnodicAmplitudeuA[i] = (double)textboxAmplitudeAnodicRequested.Tag;
}

if (textboxAmplitudeAnodic.Tag != null)
Expand All @@ -750,7 +755,7 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)

if (textboxAmplitudeCathodicRequested.Tag != null)
{
Sequence.Stimuli[i].RequestedCathodicAmplitudeuA = (double)textboxAmplitudeCathodicRequested.Tag;
RequestedCathodicAmplitudeuA[i] = (double)textboxAmplitudeCathodicRequested.Tag;
}

if (textboxAmplitudeCathodic.Tag != null)
Expand Down Expand Up @@ -920,7 +925,7 @@ private void Samples_TextChanged(object sender, EventArgs e)

private bool GetSampleFromTime(double value, out uint samples)
{
var ratio = value / Rhs2116Stimulus.SamplePeriodMilliSeconds;
var ratio = value / SamplePeriodMilliSeconds;
samples = (uint)Math.Round(ratio);

return !(ratio > uint.MaxValue || ratio < uint.MinValue);
Expand Down Expand Up @@ -957,7 +962,7 @@ private bool GetSampleFromAmplitude(double value, out byte samples)

private double GetTimeFromSample(uint value)
{
return value * Rhs2116Stimulus.SamplePeriodMilliSeconds;
return value * SamplePeriodMilliSeconds;
}

private double GetAmplitudeFromSample(byte value, Rhs2116StepSize stepSize)
Expand Down Expand Up @@ -1149,7 +1154,9 @@ private void ButtonClearPulses_Click(object sender, EventArgs e)
{
if (ChannelDialog.SelectedContacts[i])
{
Sequence.Stimuli[i].Clear(clearRequestedAmplitudes: true);
Sequence.Stimuli[i].Clear();
RequestedAnodicAmplitudeuA[i] = 0.0;
RequestedCathodicAmplitudeuA[i] = 0.0;
}
}

Expand Down Expand Up @@ -1195,10 +1202,10 @@ private void ButtonReadPulses_Click(object sender, EventArgs e)
textboxAmplitudeAnodic.Text = GetAmplitudeString(Sequence.Stimuli[index].AnodicAmplitudeSteps);
textboxAmplitudeAnodic.Tag = Sequence.Stimuli[index].AnodicAmplitudeSteps;

if (Sequence.Stimuli[index].RequestedAnodicAmplitudeuA != 0.0)
if (RequestedAnodicAmplitudeuA[index] != 0.0)
{
textboxAmplitudeAnodicRequested.Text = Sequence.Stimuli[index].RequestedAnodicAmplitudeuA.ToString();
textboxAmplitudeAnodicRequested.Tag = Sequence.Stimuli[index].RequestedAnodicAmplitudeuA;
textboxAmplitudeAnodicRequested.Text = RequestedAnodicAmplitudeuA[index].ToString();
textboxAmplitudeAnodicRequested.Tag = RequestedAnodicAmplitudeuA[index];
}
else
{
Expand All @@ -1212,10 +1219,10 @@ private void ButtonReadPulses_Click(object sender, EventArgs e)
textboxAmplitudeCathodic.Text = GetAmplitudeString(Sequence.Stimuli[index].CathodicAmplitudeSteps);
textboxAmplitudeCathodic.Tag = Sequence.Stimuli[index].CathodicAmplitudeSteps;

if (Sequence.Stimuli[index].RequestedCathodicAmplitudeuA != 0.0)
if (RequestedCathodicAmplitudeuA[index] != 0.0)
{
textboxAmplitudeCathodicRequested.Text = Sequence.Stimuli[index].RequestedCathodicAmplitudeuA.ToString();
textboxAmplitudeCathodicRequested.Tag = Sequence.Stimuli[index].RequestedCathodicAmplitudeuA;
textboxAmplitudeCathodicRequested.Text = RequestedCathodicAmplitudeuA[index].ToString();
textboxAmplitudeCathodicRequested.Tag = RequestedCathodicAmplitudeuA[index];
}
else
{
Expand Down
70 changes: 1 addition & 69 deletions OpenEphys.Onix1/Rhs2116Stimulus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ namespace OpenEphys.Onix1
/// </summary>
public class Rhs2116Stimulus
{
/// <summary>
/// Double defining the length of a single time sample, in milliseconds.
/// </summary>
public static readonly double SamplePeriodMilliSeconds = 1e3 / 30.1932367151e3;

/// <summary>
/// Initializes a new instance of the <see cref="Rhs2116Stimulus"/> class.
/// </summary>
Expand All @@ -36,63 +31,6 @@ public Rhs2116Stimulus(Rhs2116Stimulus stimulus)
InterStimulusIntervalSamples = stimulus.InterStimulusIntervalSamples;
}

/// <summary>
/// Construct a new <see cref="Rhs2116Stimulus"/> instance with the same parameters as the given <see cref="Rhs2116Stimulus"/> object.
/// </summary>
/// <param name="numberOfStimuli">Positive integer defining the number of stimuli.</param>
/// <param name="anodicFirst">Boolean defining if the anodic pulse is first.</param>
/// <param name="delaySamples">Positive integer defining the delay before the first pulse is sent, in samples. See <see cref="SamplePeriodMilliSeconds"/> for the conversion to milliseconds.</param>
/// <param name="dwellSamples">Positive integer defining the delay between the first and second pulse (inter-pulse interval) in samples. See <see cref="SamplePeriodMilliSeconds"/> for the conversion to milliseconds.</param>
/// <param name="anodicWidthSamples">Positive integer defining the width of the anodic pulse in samples. See <see cref="SamplePeriodMilliSeconds"/> for the conversion to milliseconds.</param>
/// <param name="anodicAmplitudeSteps">Byte value defining the amplitude of the anodic pulse in steps. Amplitude in microamps is dependent on the <see cref="Rhs2116StepSize"/> chosen.</param>
/// <param name="cathodicWidthSamples">Positive integer defining the width of the cathodic pulse in samples. See <see cref="SamplePeriodMilliSeconds"/> for the conversion to milliseconds.</param>
/// <param name="cathodicAmplitudeSteps">Byte value defining the amplitude of the cathodic pulse in steps. Amplitude in microamps is dependent on the <see cref="Rhs2116StepSize"/> chosen.</param>
/// <param name="interStimIntervalSamples">Positive integer defining the delay between successive stimuli (inter-stimulus interval) in samples. See <see cref="SamplePeriodMilliSeconds"/> for the conversion to milliseconds.</param>
public Rhs2116Stimulus(uint numberOfStimuli, bool anodicFirst, uint delaySamples, uint dwellSamples,
uint anodicWidthSamples, byte anodicAmplitudeSteps, uint cathodicWidthSamples, byte cathodicAmplitudeSteps, uint interStimIntervalSamples)
{
NumberOfStimuli = numberOfStimuli;
AnodicFirst = anodicFirst;
DelaySamples = delaySamples;
DwellSamples = dwellSamples;
AnodicAmplitudeSteps = anodicAmplitudeSteps;
AnodicWidthSamples = anodicWidthSamples;
CathodicAmplitudeSteps = cathodicAmplitudeSteps;
CathodicWidthSamples = cathodicWidthSamples;
InterStimulusIntervalSamples = interStimIntervalSamples;
}

internal void CopyStimulus(Rhs2116Stimulus stimulus)
{
NumberOfStimuli = stimulus.NumberOfStimuli;
AnodicFirst = stimulus.AnodicFirst;
DelaySamples = stimulus.DelaySamples;
DwellSamples = stimulus.DwellSamples;
AnodicAmplitudeSteps = stimulus.AnodicAmplitudeSteps;
AnodicWidthSamples = stimulus.AnodicWidthSamples;
CathodicAmplitudeSteps = stimulus.CathodicAmplitudeSteps;
CathodicWidthSamples = stimulus.CathodicWidthSamples;
InterStimulusIntervalSamples = stimulus.InterStimulusIntervalSamples;
}

/// <summary>
/// Requested amplitude of the anodic pulse in microamps
/// </summary>
[DisplayName("Requested Anodic Amplitude (µA)")]
[XmlIgnore]
[Browsable(false)]
[Externalizable(false)]
public double RequestedAnodicAmplitudeuA { get; set; } = 0.0;

/// <summary>
/// Requested amplitude of the cathodic pulse in microamps
/// </summary>
[DisplayName("Requested Cathodic Amplitude (µA)")]
[XmlIgnore]
[Browsable(false)]
[Externalizable(false)]
public double RequestedCathodicAmplitudeuA { get; set; } = 0.0;

/// <summary>
/// Number of stimuli delivered for each trigger.
/// </summary>
Expand Down Expand Up @@ -212,7 +150,7 @@ public bool IsValid(out string reasonInvalid)
/// <summary>
/// Resets all properties to their default values.
/// </summary>
public void Clear(bool clearRequestedAmplitudes = false)
public void Clear()
{
NumberOfStimuli = 0;
AnodicFirst = true;
Expand All @@ -223,12 +161,6 @@ public void Clear(bool clearRequestedAmplitudes = false)
CathodicAmplitudeSteps = 0;
CathodicWidthSamples = 0;
InterStimulusIntervalSamples = 0;

if (clearRequestedAmplitudes)
{
RequestedAnodicAmplitudeuA = 0;
RequestedCathodicAmplitudeuA = 0;
}
}

[XmlIgnore]
Expand Down
2 changes: 1 addition & 1 deletion OpenEphys.Onix1/Rhs2116StimulusSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public Rhs2116StimulusSequence(Rhs2116StimulusSequence sequence)
/// <summary>
/// Gets or sets the array of <see cref="Rhs2116Stimulus"/> sequences.
/// </summary>
public virtual Rhs2116Stimulus[] Stimuli { get; set; }
public Rhs2116Stimulus[] Stimuli { get; set; }

/// <summary>
/// Gets or sets the <see cref="Rhs2116StepSize"/>.
Expand Down
Loading

0 comments on commit 955de67

Please sign in to comment.