diff --git a/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.Designer.cs b/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.Designer.cs
index a73db59..2b37b51 100644
--- a/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.Designer.cs
+++ b/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.Designer.cs
@@ -41,12 +41,12 @@ private void InitializeComponent()
this.labelAmplitudeCathodic = new System.Windows.Forms.Label();
this.labelPulseWidthCathodic = new System.Windows.Forms.Label();
this.textboxPulseWidthCathodic = new System.Windows.Forms.TextBox();
- this.textboxAmplitudeCathodic = new System.Windows.Forms.TextBox();
+ this.textboxAmplitudeCathodicRequested = new System.Windows.Forms.TextBox();
this.groupBoxAnode = new System.Windows.Forms.GroupBox();
this.labelAmplitudeAnodic = new System.Windows.Forms.Label();
this.labelPulseWidthAnodic = new System.Windows.Forms.Label();
this.textboxPulseWidthAnodic = new System.Windows.Forms.TextBox();
- this.textboxAmplitudeAnodic = new System.Windows.Forms.TextBox();
+ this.textboxAmplitudeAnodicRequested = new System.Windows.Forms.TextBox();
this.buttonClearPulses = new System.Windows.Forms.Button();
this.buttonReadPulses = new System.Windows.Forms.Button();
this.textboxInterPulseInterval = new System.Windows.Forms.TextBox();
@@ -76,6 +76,8 @@ private void InitializeComponent()
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
+ this.textboxAmplitudeAnodic = new System.Windows.Forms.TextBox();
+ this.textboxAmplitudeCathodic = new System.Windows.Forms.TextBox();
this.statusStrip.SuspendLayout();
this.panelParameters.SuspendLayout();
this.groupBoxCathode.SuspendLayout();
@@ -171,7 +173,7 @@ private void InitializeComponent()
this.panelParameters.Location = new System.Drawing.Point(3, 17);
this.panelParameters.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.panelParameters.Name = "panelParameters";
- this.panelParameters.Size = new System.Drawing.Size(439, 251);
+ this.panelParameters.Size = new System.Drawing.Size(439, 285);
this.panelParameters.TabIndex = 0;
//
// textBoxStepSize
@@ -187,15 +189,16 @@ private void InitializeComponent()
//
// groupBoxCathode
//
+ this.groupBoxCathode.Controls.Add(this.textboxAmplitudeCathodic);
this.groupBoxCathode.Controls.Add(this.labelAmplitudeCathodic);
this.groupBoxCathode.Controls.Add(this.labelPulseWidthCathodic);
this.groupBoxCathode.Controls.Add(this.textboxPulseWidthCathodic);
- this.groupBoxCathode.Controls.Add(this.textboxAmplitudeCathodic);
+ this.groupBoxCathode.Controls.Add(this.textboxAmplitudeCathodicRequested);
this.groupBoxCathode.Location = new System.Drawing.Point(231, 94);
this.groupBoxCathode.Margin = new System.Windows.Forms.Padding(4);
this.groupBoxCathode.Name = "groupBoxCathode";
this.groupBoxCathode.Padding = new System.Windows.Forms.Padding(4);
- this.groupBoxCathode.Size = new System.Drawing.Size(195, 69);
+ this.groupBoxCathode.Size = new System.Drawing.Size(195, 101);
this.groupBoxCathode.TabIndex = 3;
this.groupBoxCathode.TabStop = false;
this.groupBoxCathode.Text = "Cathode";
@@ -213,7 +216,7 @@ private void InitializeComponent()
// labelPulseWidthCathodic
//
this.labelPulseWidthCathodic.AutoSize = true;
- this.labelPulseWidthCathodic.Location = new System.Drawing.Point(11, 44);
+ this.labelPulseWidthCathodic.Location = new System.Drawing.Point(11, 73);
this.labelPulseWidthCathodic.Name = "labelPulseWidthCathodic";
this.labelPulseWidthCathodic.Size = new System.Drawing.Size(107, 16);
this.labelPulseWidthCathodic.TabIndex = 24;
@@ -221,7 +224,7 @@ private void InitializeComponent()
//
// textboxPulseWidthCathodic
//
- this.textboxPulseWidthCathodic.Location = new System.Drawing.Point(132, 39);
+ this.textboxPulseWidthCathodic.Location = new System.Drawing.Point(132, 68);
this.textboxPulseWidthCathodic.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.textboxPulseWidthCathodic.Name = "textboxPulseWidthCathodic";
this.textboxPulseWidthCathodic.Size = new System.Drawing.Size(55, 22);
@@ -229,26 +232,27 @@ private void InitializeComponent()
this.textboxPulseWidthCathodic.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.ParameterKeyPress_Time);
this.textboxPulseWidthCathodic.Leave += new System.EventHandler(this.Samples_TextChanged);
//
- // textboxAmplitudeCathodic
+ // textboxAmplitudeCathodicRequested
//
- this.textboxAmplitudeCathodic.Location = new System.Drawing.Point(132, 14);
- this.textboxAmplitudeCathodic.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
- this.textboxAmplitudeCathodic.Name = "textboxAmplitudeCathodic";
- this.textboxAmplitudeCathodic.Size = new System.Drawing.Size(55, 22);
- this.textboxAmplitudeCathodic.TabIndex = 5;
- this.textboxAmplitudeCathodic.Leave += new System.EventHandler(this.Amplitude_TextChanged);
+ this.textboxAmplitudeCathodicRequested.Location = new System.Drawing.Point(132, 14);
+ this.textboxAmplitudeCathodicRequested.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
+ this.textboxAmplitudeCathodicRequested.Name = "textboxAmplitudeCathodicRequested";
+ this.textboxAmplitudeCathodicRequested.Size = new System.Drawing.Size(55, 22);
+ this.textboxAmplitudeCathodicRequested.TabIndex = 5;
+ this.textboxAmplitudeCathodicRequested.Leave += new System.EventHandler(this.Amplitude_TextChanged);
//
// groupBoxAnode
//
+ this.groupBoxAnode.Controls.Add(this.textboxAmplitudeAnodic);
this.groupBoxAnode.Controls.Add(this.labelAmplitudeAnodic);
this.groupBoxAnode.Controls.Add(this.labelPulseWidthAnodic);
this.groupBoxAnode.Controls.Add(this.textboxPulseWidthAnodic);
- this.groupBoxAnode.Controls.Add(this.textboxAmplitudeAnodic);
+ this.groupBoxAnode.Controls.Add(this.textboxAmplitudeAnodicRequested);
this.groupBoxAnode.Location = new System.Drawing.Point(13, 94);
this.groupBoxAnode.Margin = new System.Windows.Forms.Padding(4);
this.groupBoxAnode.Name = "groupBoxAnode";
this.groupBoxAnode.Padding = new System.Windows.Forms.Padding(4);
- this.groupBoxAnode.Size = new System.Drawing.Size(195, 69);
+ this.groupBoxAnode.Size = new System.Drawing.Size(195, 101);
this.groupBoxAnode.TabIndex = 2;
this.groupBoxAnode.TabStop = false;
this.groupBoxAnode.Text = "Anode";
@@ -265,7 +269,7 @@ private void InitializeComponent()
// labelPulseWidthAnodic
//
this.labelPulseWidthAnodic.AutoSize = true;
- this.labelPulseWidthAnodic.Location = new System.Drawing.Point(8, 44);
+ this.labelPulseWidthAnodic.Location = new System.Drawing.Point(8, 73);
this.labelPulseWidthAnodic.Name = "labelPulseWidthAnodic";
this.labelPulseWidthAnodic.Size = new System.Drawing.Size(107, 16);
this.labelPulseWidthAnodic.TabIndex = 7;
@@ -273,7 +277,7 @@ private void InitializeComponent()
//
// textboxPulseWidthAnodic
//
- this.textboxPulseWidthAnodic.Location = new System.Drawing.Point(129, 39);
+ this.textboxPulseWidthAnodic.Location = new System.Drawing.Point(129, 68);
this.textboxPulseWidthAnodic.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.textboxPulseWidthAnodic.Name = "textboxPulseWidthAnodic";
this.textboxPulseWidthAnodic.Size = new System.Drawing.Size(55, 22);
@@ -281,19 +285,19 @@ private void InitializeComponent()
this.textboxPulseWidthAnodic.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.ParameterKeyPress_Time);
this.textboxPulseWidthAnodic.Leave += new System.EventHandler(this.Samples_TextChanged);
//
- // textboxAmplitudeAnodic
+ // textboxAmplitudeAnodicRequested
//
- this.textboxAmplitudeAnodic.Location = new System.Drawing.Point(129, 14);
- this.textboxAmplitudeAnodic.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
- this.textboxAmplitudeAnodic.Name = "textboxAmplitudeAnodic";
- this.textboxAmplitudeAnodic.Size = new System.Drawing.Size(55, 22);
- this.textboxAmplitudeAnodic.TabIndex = 3;
- this.textboxAmplitudeAnodic.Leave += new System.EventHandler(this.Amplitude_TextChanged);
+ this.textboxAmplitudeAnodicRequested.Location = new System.Drawing.Point(129, 14);
+ this.textboxAmplitudeAnodicRequested.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
+ this.textboxAmplitudeAnodicRequested.Name = "textboxAmplitudeAnodicRequested";
+ this.textboxAmplitudeAnodicRequested.Size = new System.Drawing.Size(55, 22);
+ this.textboxAmplitudeAnodicRequested.TabIndex = 3;
+ this.textboxAmplitudeAnodicRequested.Leave += new System.EventHandler(this.Amplitude_TextChanged);
//
// buttonClearPulses
//
this.buttonClearPulses.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F);
- this.buttonClearPulses.Location = new System.Drawing.Point(19, 206);
+ this.buttonClearPulses.Location = new System.Drawing.Point(19, 238);
this.buttonClearPulses.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.buttonClearPulses.Name = "buttonClearPulses";
this.buttonClearPulses.Size = new System.Drawing.Size(99, 34);
@@ -308,7 +312,7 @@ private void InitializeComponent()
// buttonReadPulses
//
this.buttonReadPulses.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F);
- this.buttonReadPulses.Location = new System.Drawing.Point(123, 206);
+ this.buttonReadPulses.Location = new System.Drawing.Point(123, 238);
this.buttonReadPulses.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.buttonReadPulses.Name = "buttonReadPulses";
this.buttonReadPulses.Size = new System.Drawing.Size(100, 34);
@@ -368,7 +372,7 @@ private void InitializeComponent()
// buttonAddPulses
//
this.buttonAddPulses.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F);
- this.buttonAddPulses.Location = new System.Drawing.Point(318, 206);
+ this.buttonAddPulses.Location = new System.Drawing.Point(318, 238);
this.buttonAddPulses.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.buttonAddPulses.Name = "buttonAddPulses";
this.buttonAddPulses.Size = new System.Drawing.Size(100, 34);
@@ -392,7 +396,7 @@ private void InitializeComponent()
// labelNumberOfPulses
//
this.labelNumberOfPulses.AutoSize = true;
- this.labelNumberOfPulses.Location = new System.Drawing.Point(237, 174);
+ this.labelNumberOfPulses.Location = new System.Drawing.Point(237, 206);
this.labelNumberOfPulses.Name = "labelNumberOfPulses";
this.labelNumberOfPulses.Size = new System.Drawing.Size(113, 16);
this.labelNumberOfPulses.TabIndex = 13;
@@ -409,7 +413,7 @@ private void InitializeComponent()
//
// textboxNumberOfStimuli
//
- this.textboxNumberOfStimuli.Location = new System.Drawing.Point(363, 170);
+ this.textboxNumberOfStimuli.Location = new System.Drawing.Point(363, 202);
this.textboxNumberOfStimuli.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.textboxNumberOfStimuli.Name = "textboxNumberOfStimuli";
this.textboxNumberOfStimuli.Size = new System.Drawing.Size(55, 22);
@@ -433,7 +437,7 @@ private void InitializeComponent()
//
// textboxInterStimulusInterval
//
- this.textboxInterStimulusInterval.Location = new System.Drawing.Point(143, 169);
+ this.textboxInterStimulusInterval.Location = new System.Drawing.Point(143, 201);
this.textboxInterStimulusInterval.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.textboxInterStimulusInterval.Name = "textboxInterStimulusInterval";
this.textboxInterStimulusInterval.Size = new System.Drawing.Size(55, 22);
@@ -444,7 +448,7 @@ private void InitializeComponent()
// labelInterStimulusInterval
//
this.labelInterStimulusInterval.AutoSize = true;
- this.labelInterStimulusInterval.Location = new System.Drawing.Point(15, 172);
+ this.labelInterStimulusInterval.Location = new System.Drawing.Point(15, 204);
this.labelInterStimulusInterval.Name = "labelInterStimulusInterval";
this.labelInterStimulusInterval.Size = new System.Drawing.Size(115, 16);
this.labelInterStimulusInterval.TabIndex = 9;
@@ -499,7 +503,7 @@ private void InitializeComponent()
this.tabPageTable.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.tabPageTable.Name = "tabPageTable";
this.tabPageTable.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2);
- this.tabPageTable.Size = new System.Drawing.Size(1082, 646);
+ this.tabPageTable.Size = new System.Drawing.Size(1082, 644);
this.tabPageTable.TabIndex = 1;
this.tabPageTable.Text = "Table";
this.tabPageTable.UseVisualStyleBackColor = true;
@@ -517,7 +521,7 @@ private void InitializeComponent()
this.dataGridViewStimulusTable.Name = "dataGridViewStimulusTable";
this.dataGridViewStimulusTable.RowHeadersWidth = 62;
this.dataGridViewStimulusTable.RowTemplate.Height = 28;
- this.dataGridViewStimulusTable.Size = new System.Drawing.Size(1076, 642);
+ this.dataGridViewStimulusTable.Size = new System.Drawing.Size(1076, 640);
this.dataGridViewStimulusTable.TabIndex = 0;
this.dataGridViewStimulusTable.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridViewStimulusTable_CellEndEdit);
this.dataGridViewStimulusTable.DataBindingComplete += new System.Windows.Forms.DataGridViewBindingCompleteEventHandler(this.DataGridViewStimulusTable_DataBindingComplete);
@@ -529,7 +533,7 @@ private void InitializeComponent()
this.panelProbe.Location = new System.Drawing.Point(1099, 2);
this.panelProbe.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.panelProbe.Name = "panelProbe";
- this.panelProbe.Size = new System.Drawing.Size(445, 401);
+ this.panelProbe.Size = new System.Drawing.Size(445, 367);
this.panelProbe.TabIndex = 0;
//
// menuStrip
@@ -590,7 +594,7 @@ private void InitializeComponent()
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
- this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 274F));
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 308F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 42F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(1547, 721);
this.tableLayoutPanel1.TabIndex = 8;
@@ -599,11 +603,11 @@ private void InitializeComponent()
//
this.groupBox1.Controls.Add(this.panelParameters);
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
- this.groupBox1.Location = new System.Drawing.Point(1099, 407);
+ this.groupBox1.Location = new System.Drawing.Point(1099, 373);
this.groupBox1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2);
- this.groupBox1.Size = new System.Drawing.Size(445, 270);
+ this.groupBox1.Size = new System.Drawing.Size(445, 304);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Define Stimuli";
@@ -621,6 +625,24 @@ private void InitializeComponent()
this.flowLayoutPanel1.Size = new System.Drawing.Size(1541, 38);
this.flowLayoutPanel1.TabIndex = 7;
//
+ // textboxAmplitudeAnodic
+ //
+ this.textboxAmplitudeAnodic.Location = new System.Drawing.Point(129, 39);
+ this.textboxAmplitudeAnodic.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
+ this.textboxAmplitudeAnodic.Name = "textboxAmplitudeAnodic";
+ this.textboxAmplitudeAnodic.ReadOnly = true;
+ this.textboxAmplitudeAnodic.Size = new System.Drawing.Size(55, 22);
+ this.textboxAmplitudeAnodic.TabIndex = 8;
+ //
+ // textboxAmplitudeCathodic
+ //
+ this.textboxAmplitudeCathodic.Location = new System.Drawing.Point(132, 39);
+ this.textboxAmplitudeCathodic.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2);
+ this.textboxAmplitudeCathodic.Name = "textboxAmplitudeCathodic";
+ this.textboxAmplitudeCathodic.ReadOnly = true;
+ this.textboxAmplitudeCathodic.Size = new System.Drawing.Size(55, 22);
+ this.textboxAmplitudeCathodic.TabIndex = 9;
+ //
// Rhs2116StimulusSequenceDialog
//
this.AccessibleDescription = "";
@@ -668,7 +690,7 @@ private void InitializeComponent()
private System.Windows.Forms.Button buttonOk;
private System.Windows.Forms.Label labelAmplitudeAnodic;
private System.Windows.Forms.Label labelDelay;
- private System.Windows.Forms.TextBox textboxAmplitudeAnodic;
+ private System.Windows.Forms.TextBox textboxAmplitudeAnodicRequested;
private System.Windows.Forms.TextBox textboxDelay;
private System.Windows.Forms.CheckBox checkboxBiphasicSymmetrical;
private System.Windows.Forms.Button buttonAddPulses;
@@ -688,7 +710,7 @@ private void InitializeComponent()
private System.Windows.Forms.Label labelAmplitudeCathodic;
private System.Windows.Forms.Label labelPulseWidthCathodic;
private System.Windows.Forms.TextBox textboxPulseWidthCathodic;
- private System.Windows.Forms.TextBox textboxAmplitudeCathodic;
+ private System.Windows.Forms.TextBox textboxAmplitudeCathodicRequested;
private System.Windows.Forms.TextBox textboxInterPulseInterval;
private System.Windows.Forms.Label labelInterPulseInterval;
private System.Windows.Forms.Button buttonClearPulses;
@@ -707,5 +729,7 @@ private void InitializeComponent()
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.TextBox textBoxStepSize;
private System.Windows.Forms.GroupBox groupBox1;
+ private System.Windows.Forms.TextBox textboxAmplitudeCathodic;
+ private System.Windows.Forms.TextBox textboxAmplitudeAnodic;
}
}
diff --git a/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs b/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs
index 178a5fd..9872758 100644
--- a/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs
+++ b/OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs
@@ -12,8 +12,15 @@ namespace OpenEphys.Onix1.Design
///
public partial class Rhs2116StimulusSequenceDialog : Form
{
+ const double SamplePeriodMilliSeconds = 1e3 / Rhs2116.SampleFrequencyHz;
+
internal Rhs2116StimulusSequencePair Sequence { get; set; }
+ private readonly Rhs2116StimulusSequencePair SequenceCopy = new();
+
+ private readonly double[] RequestedAnodicAmplitudeuA;
+ private readonly double[] RequestedCathodicAmplitudeuA;
+
///
/// 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.
///
@@ -21,11 +28,9 @@ public partial class Rhs2116StimulusSequenceDialog : Form
internal readonly Rhs2116ChannelConfigurationDialog ChannelDialog;
- private const double SamplePeriodMilliSeconds = 1e3 / 30.1932367151e3;
const double MinAmplitudeuA = 0.01; // NB: Minimum possible amplitude is 10 nA (0.01 µA)
const double MaxAmplitudeuA = 2550; // NB: Maximum possible amplitude is 2550000 nA (2550 µA)
-
///
/// Opens a dialog allowing for easy changing of stimulus sequence parameters, with visual feedback on what the resulting stimulus sequence looks like.
///
@@ -37,6 +42,15 @@ public Rhs2116StimulusSequenceDialog(Rhs2116StimulusSequencePair sequence, Rhs21
Shown += FormShown;
Sequence = new Rhs2116StimulusSequencePair(sequence);
+ RequestedAnodicAmplitudeuA = new double[Sequence.Stimuli.Length];
+ RequestedCathodicAmplitudeuA = new double[Sequence.Stimuli.Length];
+
+ for (int i = 0; i < Sequence.Stimuli.Length; i++)
+ {
+ RequestedAnodicAmplitudeuA[i] = Sequence.Stimuli[i].AnodicAmplitudeSteps * Sequence.CurrentStepSizeuA;
+ RequestedCathodicAmplitudeuA[i] = Sequence.Stimuli[i].CathodicAmplitudeSteps * Sequence.CurrentStepSizeuA;
+ }
+
StepSize = Sequence.CurrentStepSize;
ChannelDialog = new(probeGroup)
@@ -229,11 +243,11 @@ private void HighlightInvalidContacts()
ChannelDialog.RefreshZedGraph();
}
- private static double GetPeakToPeakAmplitudeInMicroAmps(Rhs2116StimulusSequencePair stimulusSequence)
+ private double GetPeakToPeakAmplitudeInMicroAmps()
{
- return stimulusSequence.MaximumPeakToPeakAmplitudeSteps > 0
- ? stimulusSequence.CurrentStepSizeuA * stimulusSequence.MaximumPeakToPeakAmplitudeSteps
- : stimulusSequence.CurrentStepSizeuA * 1;
+ return Sequence.MaximumPeakToPeakAmplitudeSteps > 0
+ ? Sequence.GetMaxPeakToPeakAmplitudeuA()
+ : Sequence.CurrentStepSizeuA * 1; // NB: Used to give a buffer when plotting the stimulus waveform
}
private void DrawStimulusWaveform()
@@ -244,24 +258,22 @@ private void DrawStimulusWaveform()
zedGraphWaveform.GraphPane.GraphObjList.Clear();
zedGraphWaveform.ZoomOutAll(zedGraphWaveform.GraphPane);
- double peakToPeak = GetPeakToPeakAmplitudeInMicroAmps(Sequence) * 1.1;
+ double peakToPeak = GetPeakToPeakAmplitudeInMicroAmps() * 1.1;
ZoomInBoundaryY = 3;
- var stimuli = Sequence.Stimuli;
-
double maxLength = 0;
- for (int i = 0; i < stimuli.Length; i++)
+ for (int i = 0; i < Sequence.Stimuli.Length; i++)
{
var channelOffset = peakToPeak * i;
if (ChannelDialog.SelectedContacts[i] || plotAllContacts)
{
- PointPairList pointPairs = CreateStimulusWaveform(stimuli[i], channelOffset, peakToPeak);
+ PointPairList pointPairs = CreateStimulusWaveform(Sequence.Stimuli[i], channelOffset, peakToPeak);
Color color;
- if (stimuli[i].IsValid())
+ if (Sequence.Stimuli[i].IsValid())
{
color = Color.CornflowerBlue;
}
@@ -290,7 +302,7 @@ private void DrawStimulusWaveform()
zedGraphWaveform.GraphPane.XAxis.Scale.Max = maxLength;
zedGraphWaveform.GraphPane.XAxis.Scale.Min = -(maxLength * 0.02);
zedGraphWaveform.GraphPane.YAxis.Scale.Min = -2;
- zedGraphWaveform.GraphPane.YAxis.Scale.Max = stimuli.Length - 0.2;
+ zedGraphWaveform.GraphPane.YAxis.Scale.Max = Sequence.Stimuli.Length - 0.2;
DrawScale();
@@ -340,7 +352,7 @@ private void DrawScale()
timeScale.ZOrder = ZOrder.A_InFront;
zedGraphWaveform.GraphPane.GraphObjList.Add(timeScale);
- TextObj amplitudeScale = new((GetPeakToPeakAmplitudeInMicroAmps(Sequence) / 2).ToString() + " µA", zeroOffsetX, zeroOffsetY + y * 1.02, CoordType.AxisXYScale, AlignH.Center, AlignV.Bottom);
+ TextObj amplitudeScale = new((GetPeakToPeakAmplitudeInMicroAmps() / 2).ToString() + " µA", zeroOffsetX, zeroOffsetY + y * 1.02, CoordType.AxisXYScale, AlignH.Center, AlignV.Bottom);
amplitudeScale.FontSpec.Border.IsVisible = false;
amplitudeScale.FontSpec.Fill.IsVisible = false;
amplitudeScale.ZOrder = ZOrder.A_InFront;
@@ -604,7 +616,7 @@ private void SetStatusValidity()
return (reason, ind);
})
.Where(reason => reason.reason != "")
- .First();
+ .FirstOrDefault();
toolStripStatusIsValid.Image = Properties.Resources.StatusCriticalImage;
toolStripStatusIsValid.Text = string.Format("Invalid sequence - Contact {0}, Reason: {1}", reason.ind, reason.reason);
@@ -619,68 +631,96 @@ private void SetPercentOfSlotsUsed()
private void ButtonAddPulses_Click(object sender, EventArgs e)
{
- if (ChannelDialog.SelectedContacts.All(x => x))
- {
- DialogResult result = MessageBox.Show("Caution: All channels are currently selected, and all " +
- "settings will be applied to all channels if you continue. Press Okay to add pulse settings to all channels, or Cancel to keep them as is",
- "Set all channel settings?", MessageBoxButtons.OKCancel);
-
- if (result == DialogResult.Cancel)
- {
- return;
- }
- }
-
if (ChannelDialog.SelectedContacts.All(x => x == false))
{
MessageBox.Show("No contacts selected. Please select contact(s) before trying to add pulses.");
return;
}
- if (StepSize != Sequence.CurrentStepSize)
+ var stimuli = Sequence.Stimuli
+ .Select((s, ind) => { return (Index: ind, Stimulus: s); })
+ .Where(s => s.Stimulus.Valid
+ && (s.Stimulus.AnodicAmplitudeSteps != 0
+ || s.Stimulus.CathodicAmplitudeSteps != 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(RequestedAnodicAmplitudeuA[s.Index], out var requestedAnodicSteps);
+ var requestedAnodicError = s.Stimulus.AnodicAmplitudeSteps == 0
+ ? GetAmplitudeFromSample(requestedAnodicSteps, StepSize)
+ : CalculateAmplitudePercentError(RequestedAnodicAmplitudeuA[s.Index], StepSize);
+
+ GetSampleFromAmplitude(RequestedCathodicAmplitudeuA[s.Index], out var requestedCathodicSteps);
+ var requestedCathodicError = s.Stimulus.CathodicAmplitudeSteps == 0
+ ? GetAmplitudeFromSample(requestedCathodicSteps, StepSize)
+ : CalculateAmplitudePercentError(RequestedCathodicAmplitudeuA[s.Index], StepSize);
+
+ return (s.Index,
+ ErrorAnodic: requestedAnodicError,
+ ErrorCathodic: requestedCathodicError,
+ StepsAnodic: requestedAnodicSteps,
+ StepsCathodic: requestedCathodicSteps);
+ });
+
+ if (Sequence.CurrentStepSize != StepSize && stimuli.Any(e => e.ErrorCathodic != 0 || e.ErrorAnodic != 0 &&
+ ((Sequence.Stimuli[e.Index].AnodicAmplitudeSteps == 0 && e.StepsAnodic != 0) ||
+ (Sequence.Stimuli[e.Index].CathodicAmplitudeSteps == 0 && e.StepsCathodic != 0))))
{
- var stimuli = Sequence.Stimuli
- .Select((s, ind) => { return (Index: ind, Stimulus: s); })
- .Where(s => s.Stimulus.IsValid() && (s.Stimulus.AnodicAmplitudeSteps != 0 || s.Stimulus.CathodicAmplitudeSteps != 0) && !ChannelDialog.SelectedContacts[s.Index])
- .Select(s =>
- {
- var currentAnodicAmplitude = GetAmplitudeFromSample(s.Stimulus.AnodicAmplitudeSteps, Sequence.CurrentStepSize);
- var currentCathodicAmplitude = GetAmplitudeFromSample(s.Stimulus.CathodicAmplitudeSteps, Sequence.CurrentStepSize);
-
- var validAnodicAmplitude = GetSampleFromAmplitude(currentAnodicAmplitude, out var newAnodicSteps);
- var validCathodicAmplitude = GetSampleFromAmplitude(currentAnodicAmplitude, out var newCathodicSteps);
-
- return (ValidAmplitudes: validAnodicAmplitude && newAnodicSteps != 0 && validCathodicAmplitude && newCathodicSteps != 0,
- s.Index,
- s.Stimulus,
- NewAnodicSteps: newAnodicSteps,
- NewCathodicSteps: newCathodicSteps);
- });
-
- foreach (var (ValidAmplitudes, Index, Stimulus, NewAnodicSteps, NewCathodicSteps) in stimuli)
+ var message = $"The step size is changing from {GetStepSizeStringuA(Sequence.CurrentStepSize)} to {GetStepSizeStringuA(StepSize)}, " +
+ $"which will adjust some amplitudes. If applied, the following values will be modified:\n";
+
+ foreach (var (Index, ErrorAnodic, ErrorCathodic, StepsAnodic, StepsCathodic) in stimuli)
{
- if (ValidAmplitudes)
+ if (ErrorAnodic != 0 || ErrorCathodic != 0 && ((Sequence.Stimuli[Index].AnodicAmplitudeSteps == 0 && StepsAnodic != 0) || (Sequence.Stimuli[Index].CathodicAmplitudeSteps == 0 && StepsCathodic != 0)))
{
- Sequence.Stimuli[Index].AnodicAmplitudeSteps = NewAnodicSteps;
- Sequence.Stimuli[Index].CathodicAmplitudeSteps = NewCathodicSteps;
+ var oldAnodicAmplitude = GetAmplitudeFromSample(Sequence.Stimuli[Index].AnodicAmplitudeSteps, Sequence.CurrentStepSize);
+ var newAnodicAmplitude = GetAmplitudeFromSample(StepsAnodic, StepSize);
+
+ var oldCathodicAmplitude = GetAmplitudeFromSample(Sequence.Stimuli[Index].CathodicAmplitudeSteps, Sequence.CurrentStepSize);
+ var newCathodicAmplitude = GetAmplitudeFromSample(StepsCathodic, StepSize);
+
+ if (oldAnodicAmplitude == newAnodicAmplitude && oldCathodicAmplitude == newCathodicAmplitude) continue;
+
+ message += $"\nChannel {Index}: Anode = {oldAnodicAmplitude} µA → {newAnodicAmplitude} µA," +
+ $" Cathode = {oldCathodicAmplitude} µA → {newCathodicAmplitude} µA";
}
- else
- {
- var result = MessageBox.Show($"The new amplitude ({GetAmplitudeString((byte)textboxAmplitudeAnodic.Tag) + " µA"}) is using a step size of {GetStepSizeStringuA(StepSize)}," +
- $" but channel {Index} ({GetAmplitudeString(Stimulus.AnodicAmplitudeSteps, Sequence.CurrentStepSize) + " µA"}) cannot be defined with this step size. " +
- $"Press Ok to clear channel {Index}, or Cancel to stop adding this sequence.",
- "Amplitude Out of Range", MessageBoxButtons.OKCancel);
+ }
- if (result == DialogResult.Cancel)
- {
- return;
- }
+ message += "\n\nClick Update to update these channels, or Cancel to stop.";
+ CustomMessageBox messageBox = new(message, "New Amplitude Values", "Update", "Cancel");
+ var result = messageBox.ShowDialog();
+
+ if (result == DialogResult.Cancel) return;
+ }
+
+ foreach (var (Index, ErrorAnodic, ErrorCathodic, StepsAnodic, StepsCathodic) in stimuli)
+ {
+ if (StepsAnodic == 0 && StepsCathodic == 0)
+ {
+ if (Sequence.Stimuli[Index].AnodicAmplitudeSteps != 0 && Sequence.Stimuli[Index].CathodicAmplitudeSteps != 0)
+ {
+ 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.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;
+
+ Sequence.Stimuli[Index].AnodicAmplitudeSteps = StepsAnodic;
+ Sequence.Stimuli[Index].CathodicAmplitudeSteps = StepsCathodic;
+ }
}
+ 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])
@@ -690,6 +730,11 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)
Sequence.Stimuli[i].DelaySamples = (uint)textboxDelay.Tag;
}
+ if (textboxAmplitudeAnodicRequested.Tag != null)
+ {
+ RequestedAnodicAmplitudeuA[i] = (double)textboxAmplitudeAnodicRequested.Tag;
+ }
+
if (textboxAmplitudeAnodic.Tag != null)
{
Sequence.Stimuli[i].AnodicAmplitudeSteps = (byte)textboxAmplitudeAnodic.Tag;
@@ -705,6 +750,11 @@ private void ButtonAddPulses_Click(object sender, EventArgs e)
Sequence.Stimuli[i].DwellSamples = (uint)textboxInterPulseInterval.Tag;
}
+ if (textboxAmplitudeCathodicRequested.Tag != null)
+ {
+ RequestedCathodicAmplitudeuA[i] = (double)textboxAmplitudeCathodicRequested.Tag;
+ }
+
if (textboxAmplitudeCathodic.Tag != null)
{
Sequence.Stimuli[i].CathodicAmplitudeSteps = (byte)textboxAmplitudeCathodic.Tag;
@@ -882,16 +932,31 @@ private bool GetSampleFromTime(double value, out uint samples)
/// Get the number of samples needed at the current step size to represent a given amplitude.
///
/// Double value defining the amplitude in microamps.
+ ///
/// Output returning the number of samples as a byte.
/// Returns true if the number of samples is a valid byte value (between 0 and 255). Returns false if the number of samples cannot be represented in byte format.
- private bool GetSampleFromAmplitude(double value, out byte samples)
+ private bool GetSampleFromAmplitude(double value, Rhs2116StepSize stepSize, out byte samples)
{
- var ratio = value / Rhs2116StimulusSequence.GetStepSizeuA(StepSize);
- samples = (byte)Math.Round(ratio);
+ var ratio = GetRatio(value, Rhs2116StimulusSequence.GetStepSizeuA(stepSize));
+
+ if (ratio >= 255) samples = 255;
+ else if (ratio <= 0) samples = 0;
+ else samples = (byte)Math.Round(ratio);
return !(ratio > byte.MaxValue || ratio < 0);
}
+ private double GetRatio(double value1, double value2)
+ {
+ return value1 / value2;
+ }
+
+ ///
+ private bool GetSampleFromAmplitude(double value, out byte samples)
+ {
+ return GetSampleFromAmplitude(value, StepSize, out samples);
+ }
+
private double GetTimeFromSample(uint value)
{
return value * SamplePeriodMilliSeconds;
@@ -902,28 +967,52 @@ private double GetAmplitudeFromSample(byte value, Rhs2116StepSize stepSize)
return value * Rhs2116StimulusSequence.GetStepSizeuA(stepSize);
}
+ private void UpdateAmplitudeTextBoxes(TextBox textBox, string text = "", byte? tag = null)
+ {
+ if (checkboxBiphasicSymmetrical.Checked)
+ {
+ textboxAmplitudeCathodic.Text = text;
+ textboxAmplitudeCathodic.Tag = tag.HasValue ? tag.Value : null;
+
+ textboxAmplitudeAnodic.Text = text;
+ textboxAmplitudeAnodic.Tag = tag.HasValue ? tag.Value : null;
+
+ if (textBox.Name == nameof(textboxAmplitudeAnodicRequested))
+ {
+ textboxAmplitudeCathodicRequested.Text = textboxAmplitudeAnodicRequested.Text;
+ textboxAmplitudeCathodicRequested.Tag = textboxAmplitudeAnodicRequested.Tag;
+ }
+ else if (textBox.Name == nameof(textboxAmplitudeCathodicRequested))
+ {
+ textboxAmplitudeAnodicRequested.Text = textboxAmplitudeCathodicRequested.Text;
+ textboxAmplitudeAnodicRequested.Tag = textboxAmplitudeCathodicRequested.Tag;
+ }
+ }
+ else
+ {
+ if (textBox.Name == nameof(textboxAmplitudeAnodicRequested))
+ {
+ textboxAmplitudeAnodic.Text = text;
+ textboxAmplitudeAnodic.Tag = tag.HasValue ? tag.Value : null;
+ }
+ else if (textBox.Name == nameof(textboxAmplitudeCathodicRequested))
+ {
+ textboxAmplitudeCathodic.Text = text;
+ textboxAmplitudeCathodic.Tag = tag.HasValue ? tag.Value : null;
+ }
+ }
+
+ }
+
private void Amplitude_TextChanged(object sender, EventArgs e)
{
TextBox textBox = (TextBox)sender;
if (textBox.Text == "")
{
+ UpdateAmplitudeTextBoxes(textBox);
textBox.Tag = null;
- if (checkboxBiphasicSymmetrical.Checked)
- {
- if (textBox.Name == nameof(textboxAmplitudeAnodic))
- {
- textboxAmplitudeCathodic.Text = "";
- textboxAmplitudeCathodic.Tag = null;
- }
- else if (textBox.Name == nameof(textboxAmplitudeCathodic))
- {
- textboxAmplitudeAnodic.Text = "";
- textboxAmplitudeAnodic.Tag = null;
- }
- }
-
return;
}
@@ -931,36 +1020,26 @@ private void Amplitude_TextChanged(object sender, EventArgs e)
{
if (!UpdateStepSizeFromAmplitude(result))
{
- textBox.Text = result > MaxAmplitudeuA ? MaxAmplitudeuA.ToString() : "0";
- textBox.Tag = result > MaxAmplitudeuA ? 255 : 0;
+ string text = result > MaxAmplitudeuA ? MaxAmplitudeuA.ToString() : "0";
+ byte tag = result > MaxAmplitudeuA ? (byte)255 : (byte)0;
+
+ UpdateAmplitudeTextBoxes(textBox, text, tag);
+
return;
}
+ textBox.Tag = result;
+
GetSampleFromAmplitude(result, out byte sampleAmplitude);
- textBox.Text = GetAmplitudeString(sampleAmplitude);
- textBox.Tag = sampleAmplitude;
+ UpdateAmplitudeTextBoxes(textBox, GetAmplitudeString(sampleAmplitude), sampleAmplitude);
}
else
{
- MessageBox.Show("Unable to parse text. Please enter a valid value in milliamps");
+ MessageBox.Show("Unable to parse text. Please enter a valid value in milliamps.", "Invalid Requested Amplitude");
textBox.Text = "";
textBox.Tag = null;
}
-
- if (checkboxBiphasicSymmetrical.Checked)
- {
- if (textBox.Name == nameof(textboxAmplitudeAnodic))
- {
- textboxAmplitudeCathodic.Text = textBox.Text;
- textboxAmplitudeCathodic.Tag = textBox.Tag;
- }
- else if (textBox.Name == nameof(textboxAmplitudeCathodic))
- {
- textboxAmplitudeAnodic.Text = textBox.Text;
- textboxAmplitudeAnodic.Tag = textBox.Tag;
- }
- }
}
///
@@ -988,56 +1067,18 @@ private bool UpdateStepSizeFromAmplitude(double amplitude)
return false;
}
- // NB: Update step size to a value that supports the requested amplitude.
- var possibleStepSizes = Enum.GetValues(typeof(Rhs2116StepSize))
- .Cast()
- .Where(s =>
- {
- return IsValidNumberOfSteps(GetNumberOfSteps(amplitude, s));
- });
+ var stepSizes = Enum.GetValues(typeof(Rhs2116StepSize)).Cast();
+ var validStepSizes = stepSizes.Where(stepSize => IsValidNumberOfSteps(GetNumberOfSteps(amplitude, stepSize)));
- if (possibleStepSizes.Count() == 1)
+ if (validStepSizes.Count() == 1)
{
- StepSize = possibleStepSizes.First();
- }
- else
- {
- if (possibleStepSizes.Contains(Sequence.CurrentStepSize))
- {
- StepSize = Sequence.CurrentStepSize;
- }
- else
- {
- // NB: Search through the possible step sizes and try to find one that matches all current amplitudes
- var validStepSizes = possibleStepSizes.Where(s =>
- {
- var numberOfStimuli = Sequence.Stimuli.Length;
-
- bool[] isValid = new bool[numberOfStimuli];
-
- for (int i = 0; i < numberOfStimuli; i++)
- {
- isValid[i] = IsValidNumberOfSteps(GetNumberOfSteps(GetAmplitudeFromSample(Sequence.Stimuli[i].AnodicAmplitudeSteps, Sequence.CurrentStepSize), s));
- }
-
- return isValid.All(i => i);
- });
-
- if (!validStepSizes.Any())
- {
- MessageBox.Show("No step size found that fits all existing and new amplitudes. " +
- "Either clear existing stimuli that fall outside the range of the new step size, or modify " +
- "the new amplitude.", "Invalid Amplitude");
-
- StepSize = possibleStepSizes.First();
- }
- else
- {
- StepSize = validStepSizes.First();
- }
- }
+ StepSize = validStepSizes.First();
+ textBoxStepSize.Text = GetStepSizeStringuA(StepSize);
+
+ return true;
}
+ StepSize = Rhs2116StimulusSequence.GetStepSizeWithMinError(validStepSizes, Sequence.Stimuli, Sequence.CurrentStepSize);
textBoxStepSize.Text = GetStepSizeStringuA(StepSize);
return true;
@@ -1053,6 +1094,17 @@ private int GetNumberOfSteps(double amplitude, Rhs2116StepSize stepSize)
return (int)(amplitude / Rhs2116StimulusSequence.GetStepSizeuA(stepSize));
}
+ private double CalculateAmplitudePercentError(double amplitude, Rhs2116StepSize stepSize)
+ {
+ if (amplitude == 0) return 0;
+
+ var stepSizeuA = Rhs2116StimulusSequence.GetStepSizeuA(stepSize);
+
+ GetSampleFromAmplitude(amplitude, stepSize, out var steps);
+
+ return 100 * ((amplitude - steps * stepSizeuA) / amplitude);
+ }
+
private void Checkbox_CheckedChanged(object sender, EventArgs e)
{
if (checkboxBiphasicSymmetrical.Checked)
@@ -1067,6 +1119,9 @@ private void Checkbox_CheckedChanged(object sender, EventArgs e)
textboxAmplitudeCathodic.Text = textboxAmplitudeAnodic.Text;
textboxAmplitudeCathodic.Tag = textboxAmplitudeAnodic.Tag;
+
+ textboxAmplitudeCathodicRequested.Text = textboxAmplitudeAnodicRequested.Text;
+ textboxAmplitudeCathodicRequested.Tag = textboxAmplitudeAnodicRequested.Tag;
}
else
{
@@ -1078,6 +1133,9 @@ private void Checkbox_CheckedChanged(object sender, EventArgs e)
textboxAmplitudeAnodic.Text = textboxAmplitudeCathodic.Text;
textboxAmplitudeAnodic.Tag = textboxAmplitudeCathodic.Tag;
+
+ textboxAmplitudeAnodicRequested.Text = textboxAmplitudeCathodicRequested.Text;
+ textboxAmplitudeAnodicRequested.Tag = textboxAmplitudeCathodicRequested.Tag;
}
}
else
@@ -1089,25 +1147,13 @@ private void Checkbox_CheckedChanged(object sender, EventArgs e)
private void ButtonClearPulses_Click(object sender, EventArgs e)
{
- if (ChannelDialog.SelectedContacts.All(x => x == false) || ChannelDialog.SelectedContacts.All(x => x == true))
- {
- DialogResult result = MessageBox.Show("Caution: All channels are currently selected, and all " +
- "settings will be cleared if you continue. Press Okay to clear all pulse settings, or Cancel to keep them",
- "Remove all channel settings?", MessageBoxButtons.OKCancel);
-
- if (result == DialogResult.Cancel)
- {
- return;
- }
- }
-
- var clearAllContacts = ChannelDialog.SelectedContacts.All(x => x == false);
-
for (int i = 0; i < ChannelDialog.SelectedContacts.Length; i++)
{
- if (ChannelDialog.SelectedContacts[i] || clearAllContacts)
+ if (ChannelDialog.SelectedContacts[i])
{
Sequence.Stimuli[i].Clear();
+ RequestedAnodicAmplitudeuA[i] = 0.0;
+ RequestedCathodicAmplitudeuA[i] = 0.0;
}
}
@@ -1153,12 +1199,34 @@ private void ButtonReadPulses_Click(object sender, EventArgs e)
textboxAmplitudeAnodic.Text = GetAmplitudeString(Sequence.Stimuli[index].AnodicAmplitudeSteps);
textboxAmplitudeAnodic.Tag = Sequence.Stimuli[index].AnodicAmplitudeSteps;
+ if (RequestedAnodicAmplitudeuA[index] != 0.0)
+ {
+ textboxAmplitudeAnodicRequested.Text = RequestedAnodicAmplitudeuA[index].ToString();
+ textboxAmplitudeAnodicRequested.Tag = RequestedAnodicAmplitudeuA[index];
+ }
+ else
+ {
+ textboxAmplitudeAnodicRequested.Text = "";
+ textboxAmplitudeAnodicRequested.Tag = null;
+ }
+
textboxPulseWidthAnodic.Text = GetTimeString(Sequence.Stimuli[index].AnodicWidthSamples);
textboxPulseWidthAnodic.Tag = Sequence.Stimuli[index].AnodicWidthSamples;
textboxAmplitudeCathodic.Text = GetAmplitudeString(Sequence.Stimuli[index].CathodicAmplitudeSteps);
textboxAmplitudeCathodic.Tag = Sequence.Stimuli[index].CathodicAmplitudeSteps;
+ if (RequestedCathodicAmplitudeuA[index] != 0.0)
+ {
+ textboxAmplitudeCathodicRequested.Text = RequestedCathodicAmplitudeuA[index].ToString();
+ textboxAmplitudeCathodicRequested.Tag = RequestedCathodicAmplitudeuA[index];
+ }
+ else
+ {
+ textboxAmplitudeCathodicRequested.Text = "";
+ textboxAmplitudeCathodicRequested.Tag = null;
+ }
+
textboxPulseWidthCathodic.Text = GetTimeString(Sequence.Stimuli[index].CathodicWidthSamples);
textboxPulseWidthCathodic.Tag = Sequence.Stimuli[index].CathodicWidthSamples;
@@ -1175,7 +1243,7 @@ private void MenuItemSaveFile_Click(object sender, EventArgs e)
{
if (!Sequence.Valid)
{
- var result = MessageBox.Show("Warning: Not all stimuli are valid; are you sure you want to save this file?",
+ var result = MessageBox.Show("Warning: Not all stimuli are valid; are you sure you want to save this file?",
"Invalid Stimuli", MessageBoxButtons.YesNo, MessageBoxIcon.Error);
if (result == DialogResult.No) return;
diff --git a/OpenEphys.Onix1/Rhs2116Stimulus.cs b/OpenEphys.Onix1/Rhs2116Stimulus.cs
index d57522f..b5cbcda 100644
--- a/OpenEphys.Onix1/Rhs2116Stimulus.cs
+++ b/OpenEphys.Onix1/Rhs2116Stimulus.cs
@@ -1,5 +1,6 @@
using System.ComponentModel;
using System.Xml.Serialization;
+using Bonsai;
namespace OpenEphys.Onix1
{
@@ -8,6 +9,28 @@ namespace OpenEphys.Onix1
///
public class Rhs2116Stimulus
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Rhs2116Stimulus() { }
+
+ ///
+ /// Construct a new instance with the same parameters as the given object.
+ ///
+ ///
+ public Rhs2116Stimulus(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;
+ }
+
///
/// Number of stimuli delivered for each trigger.
///
diff --git a/OpenEphys.Onix1/Rhs2116StimulusSequence.cs b/OpenEphys.Onix1/Rhs2116StimulusSequence.cs
index 6771905..1258dc0 100644
--- a/OpenEphys.Onix1/Rhs2116StimulusSequence.cs
+++ b/OpenEphys.Onix1/Rhs2116StimulusSequence.cs
@@ -3,6 +3,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("OpenEphys.Onix1.Design")]
namespace OpenEphys.Onix1
{
@@ -11,7 +14,7 @@ namespace OpenEphys.Onix1
///
public class Rhs2116StimulusSequence
{
- const int NumberOfChannelsPerDevice = 16;
+ internal const int NumberOfChannels = 16;
///
/// Initializes a new instance of the class with 16 default
@@ -19,7 +22,7 @@ public class Rhs2116StimulusSequence
///
public Rhs2116StimulusSequence()
{
- Stimuli = new Rhs2116Stimulus[NumberOfChannelsPerDevice];
+ Stimuli = new Rhs2116Stimulus[NumberOfChannels];
for (var i = 0; i < Stimuli.Length; i++)
{
@@ -147,6 +150,15 @@ public static double GetStepSizeuA(Rhs2116StepSize stepSize)
};
}
+ ///
+ /// Gets the maximum peak-to-peak amplitude across all stimuli.
+ ///
+ /// Double containing the maximum peak-to-peak amplitude in µA.
+ public double GetMaxPeakToPeakAmplitudeuA()
+ {
+ return CurrentStepSizeuA * MaximumPeakToPeakAmplitudeSteps;
+ }
+
///
/// Gets the maximum possible amplitude for a single pulse, in µA.
///
@@ -172,7 +184,7 @@ private Dictionary GetDeltaTable()
{
var table = new Dictionary();
- for (int i = 0; i < NumberOfChannelsPerDevice; i++)
+ for (int i = 0; i < NumberOfChannels; i++)
{
var s = Stimuli[i];
@@ -217,5 +229,51 @@ private static void AddOrInsert(ref Dictionary table, int channe
table[key][channel + 16] = polarity;
}
}
+
+ internal static Rhs2116StepSize GetStepSizeWithMinError(IEnumerable stepSizes, Rhs2116Stimulus[] stimuli, Rhs2116StepSize currentStepSize)
+ {
+ var numberOfStepSizes = stepSizes.Count();
+ var maxError = new List(numberOfStepSizes);
+ var stepSizesuA = stepSizes.Select(s => GetStepSizeuA(s)).ToArray();
+ var currentStepSizeuA = GetStepSizeuA(currentStepSize);
+
+ static double CalculateError(double amplitude, double stepSizeuA)
+ {
+ return Math.Abs((amplitude - (stepSizeuA * Math.Round(amplitude / stepSizeuA))) / amplitude);
+ }
+
+ for (int s = 0; s < numberOfStepSizes; s++)
+ {
+ maxError.Add(0);
+
+ for (int c = 0; c < stimuli.Length; c += 1)
+ {
+ if (stimuli[c].AnodicAmplitudeSteps == 0 && stimuli[c].CathodicAmplitudeSteps == 0) continue;
+
+ var anodicAmp = stimuli[c].AnodicAmplitudeSteps * currentStepSizeuA;
+ var cathodicAmp = stimuli[c].CathodicAmplitudeSteps * currentStepSizeuA;
+
+ var anodicError = anodicAmp < stepSizesuA[s] || anodicAmp > stepSizesuA[s] * 255 ?
+ double.PositiveInfinity :
+ CalculateError(anodicAmp, stepSizesuA[s]);
+
+ var cathodicError = cathodicAmp < stepSizesuA[s] || cathodicAmp > stepSizesuA[s] * 255 ?
+ double.PositiveInfinity :
+ CalculateError(cathodicAmp, stepSizesuA[s]);
+
+ maxError[s] = Math.Max(maxError[s], Math.Max(anodicError, cathodicError));
+ }
+ }
+
+ if (maxError.Distinct().Count() == 1)
+ {
+ // NB: All step sizes have the same error; compare to current step size and choose the closest step size
+ return stepSizes.OrderBy(s => Math.Abs(GetStepSizeuA(s) - currentStepSizeuA)).First();
+ }
+
+ var optimalStepIndex = maxError.IndexOf(maxError.Min());
+
+ return stepSizes.ElementAt(optimalStepIndex);
+ }
}
}
diff --git a/OpenEphys.Onix1/Rhs2116StimulusSequencePair.cs b/OpenEphys.Onix1/Rhs2116StimulusSequencePair.cs
index 20f3a68..05bbb0f 100644
--- a/OpenEphys.Onix1/Rhs2116StimulusSequencePair.cs
+++ b/OpenEphys.Onix1/Rhs2116StimulusSequencePair.cs
@@ -1,6 +1,9 @@
using System;
using System.Linq;
using System.Xml.Serialization;
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("OpenEphys.Onix1.Design")]
namespace OpenEphys.Onix1
{
@@ -9,8 +12,8 @@ namespace OpenEphys.Onix1
///
public class Rhs2116StimulusSequencePair
{
- internal readonly Rhs2116StimulusSequence StimulusSequenceA;
- internal readonly Rhs2116StimulusSequence StimulusSequenceB;
+ internal Rhs2116StimulusSequence StimulusSequenceA { get; }
+ internal Rhs2116StimulusSequence StimulusSequenceB { get; }
///
/// Initializes a new instance of the class with 16 default
@@ -33,6 +36,18 @@ public Rhs2116StimulusSequencePair(Rhs2116StimulusSequencePair stimulusSequenceD
StimulusSequenceB = new Rhs2116StimulusSequence(stimulusSequenceDual.StimulusSequenceB);
}
+ ///
+ /// Initializes a new instance of the by performing a
+ /// shallow copy of the reference sequences.
+ ///
+ /// Existing for sequence A.
+ /// Existing for sequence B.
+ public Rhs2116StimulusSequencePair(Rhs2116StimulusSequence stimulusSequenceA, Rhs2116StimulusSequence stimulusSequenceB)
+ {
+ StimulusSequenceA = new Rhs2116StimulusSequence(stimulusSequenceA);
+ StimulusSequenceB = new Rhs2116StimulusSequence(stimulusSequenceB);
+ }
+
///
/// Gets or sets the array of stimuli.
///
@@ -46,6 +61,34 @@ public Rhs2116Stimulus[] Stimuli
}
}
+ ///
+ /// Updates the stimulus at the given index.
+ ///
+ ///
+ /// This is necessary to change the values of individual stimuli, since the implementation for getting does not
+ /// allow for the underlying to be updated.
+ ///
+ /// Current to copy.
+ /// Zero-indexed value of the channel to update.
+ /// Index must be between 0 and the sum of the number of elements in
+ /// and .
+ internal void UpdateStimulus(Rhs2116Stimulus stimulus, int index)
+ {
+ if (index >= Stimuli.Length || index < 0)
+ {
+ throw new IndexOutOfRangeException("Index is outside of the range of stimuli. Must be less than " + Stimuli.Length.ToString() + ", and greater than zero.");
+ }
+
+ if (index < StimulusSequenceA.Stimuli.Length)
+ {
+ StimulusSequenceA.Stimuli[index] = stimulus.Clone();
+ }
+ else
+ {
+ StimulusSequenceB.Stimuli[index - StimulusSequenceA.Stimuli.Length] = stimulus.Clone();
+ }
+ }
+
///
/// Gets or sets the .
///
@@ -99,5 +142,14 @@ public Rhs2116StepSize CurrentStepSize
///
[XmlIgnore]
public double CurrentStepSizeuA => StimulusSequenceA.CurrentStepSizeuA;
+
+ ///
+ /// Gets the maximum peak-to-peak amplitude across all stimuli.
+ ///
+ /// Double containing the maximum peak-to-peak amplitude in µA.
+ public double GetMaxPeakToPeakAmplitudeuA()
+ {
+ return Math.Max(StimulusSequenceA.GetMaxPeakToPeakAmplitudeuA(), StimulusSequenceB.GetMaxPeakToPeakAmplitudeuA());
+ }
}
}