Skip to content

Commit

Permalink
Merge pull request #393 from open-ephys/issue-392
Browse files Browse the repository at this point in the history
Rhs2116 step size algorithm now accounts for requested amplitude
  • Loading branch information
bparks13 authored Jan 17, 2025
2 parents 8d8ba02 + acb084b commit 067989b
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 27 deletions.
22 changes: 5 additions & 17 deletions OpenEphys.Onix1.Design/Rhs2116StimulusSequenceDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ public partial class Rhs2116StimulusSequenceDialog : Form

internal readonly Rhs2116ChannelConfigurationDialog ChannelDialog;

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)

/// <summary>
/// Opens a dialog allowing for easy changing of stimulus sequence parameters, with visual feedback on what the resulting stimulus sequence looks like.
/// </summary>
Expand Down Expand Up @@ -1020,8 +1017,9 @@ private void Amplitude_TextChanged(object sender, EventArgs e)
{
if (!UpdateStepSizeFromAmplitude(result))
{
string text = result > MaxAmplitudeuA ? MaxAmplitudeuA.ToString() : "0";
byte tag = result > MaxAmplitudeuA ? (byte)255 : (byte)0;
string text = "0";
byte tag = 0;
textBox.Text = "";

UpdateAmplitudeTextBoxes(textBox, text, tag);

Expand Down Expand Up @@ -1051,21 +1049,11 @@ private bool UpdateStepSizeFromAmplitude(double amplitude)
{
const string InvalidAmplitudeString = "Invalid Amplitude";

if (amplitude > MaxAmplitudeuA)
{
MessageBox.Show($"Warning: Amplitude is too high. Amplitude must be less than or equal to {MaxAmplitudeuA} µA.", InvalidAmplitudeString);
return false;
}
else if (amplitude < 0)
if (amplitude < 0)
{
MessageBox.Show("Warning: Amplitude cannot be a negative value.", InvalidAmplitudeString);
return false;
}
else if (amplitude < MinAmplitudeuA && amplitude >= 0)
{
MessageBox.Show($"Amplitude is too small to be resolved. Amplitude must be greater than or equal to {MinAmplitudeuA} µA.", InvalidAmplitudeString);
return false;
}

var stepSizes = Enum.GetValues(typeof(Rhs2116StepSize)).Cast<Rhs2116StepSize>();
var validStepSizes = stepSizes.Where(stepSize => IsValidNumberOfSteps(GetNumberOfSteps(amplitude, stepSize)));
Expand All @@ -1078,7 +1066,7 @@ private bool UpdateStepSizeFromAmplitude(double amplitude)
return true;
}

StepSize = Rhs2116StimulusSequence.GetStepSizeWithMinError(validStepSizes, Sequence.Stimuli, Sequence.CurrentStepSize);
StepSize = Rhs2116StimulusSequence.GetStepSizeWithMinError(validStepSizes, Sequence.Stimuli, amplitude, Sequence.CurrentStepSize);
textBoxStepSize.Text = GetStepSizeStringuA(StepSize);

return true;
Expand Down
34 changes: 24 additions & 10 deletions OpenEphys.Onix1/Rhs2116StimulusSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ private static void AddOrInsert(ref Dictionary<uint, BitArray> table, int channe
}
}

internal static Rhs2116StepSize GetStepSizeWithMinError(IEnumerable<Rhs2116StepSize> stepSizes, Rhs2116Stimulus[] stimuli, Rhs2116StepSize currentStepSize)
internal static Rhs2116StepSize GetStepSizeWithMinError(IEnumerable<Rhs2116StepSize> stepSizes, Rhs2116Stimulus[] stimuli, double requestedAmplitude, Rhs2116StepSize currentStepSize)
{
var numberOfStepSizes = stepSizes.Count();
var maxError = new List<double>(numberOfStepSizes);
Expand All @@ -239,7 +239,9 @@ internal static Rhs2116StepSize GetStepSizeWithMinError(IEnumerable<Rhs2116StepS

static double CalculateError(double amplitude, double stepSizeuA)
{
return Math.Abs((amplitude - (stepSizeuA * Math.Round(amplitude / stepSizeuA))) / amplitude);
return Math.Round(amplitude / stepSizeuA) > 0 && Math.Round(amplitude / stepSizeuA) <= 255
? Math.Abs((amplitude - (stepSizeuA * Math.Round(amplitude / stepSizeuA))) / amplitude)
: double.PositiveInfinity;
}

for (int s = 0; s < numberOfStepSizes; s++)
Expand All @@ -253,16 +255,15 @@ static double CalculateError(double amplitude, double stepSizeuA)
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]);
var anodicError = CalculateError(anodicAmp, stepSizesuA[s]);
var cathodicError = CalculateError(cathodicAmp, stepSizesuA[s]);

maxError[s] = Math.Max(maxError[s], Math.Max(anodicError, cathodicError));
}

var requestedError = CalculateError(requestedAmplitude, stepSizesuA[s]);

maxError[s] = Math.Max(maxError[s], requestedError);
}

if (maxError.Distinct().Count() == 1)
Expand All @@ -271,7 +272,20 @@ static double CalculateError(double amplitude, double stepSizeuA)
return stepSizes.OrderBy(s => Math.Abs(GetStepSizeuA(s) - currentStepSizeuA)).First();
}

var optimalStepIndex = maxError.IndexOf(maxError.Min());
var minimumError = maxError.Min();
var optimalStepIndex = maxError
.Select((e, ind) =>
{
if (e == minimumError)
{
return (Min: true, Ind: ind);
}
return (Min: false, Ind: -1);
})
.Where(e => e.Min)
.OrderBy(e => Math.Abs(GetStepSizeuA(stepSizes.ElementAt(e.Ind)) - currentStepSizeuA))
.Select(e => e.Ind)
.First();

return stepSizes.ElementAt(optimalStepIndex);
}
Expand Down

0 comments on commit 067989b

Please sign in to comment.