Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance adaptive suprathreshold #2302

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 105 additions & 39 deletions Packages/MIES/MIES_AnalysisFunctions_PatchSeq.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ End
/// - "PassingSupraSweep": Sweep with passing supra set QC
/// - "PassingRheobaseSweep": Sweep with passing rheobase set QC
/// - "PassingRhSuAdSweeps": List of passing rheobase/supra/adaptive SCI sweeps
/// - "FailingAdaptiveSweep": Failing adaptive sweep, the very last one, of the previous SCI (*written* by PSQ_DaScale)
/// - "PassingAdaptiveSweepFromFailingSet": Passing adaptive sweeps from failing sets from previous SCIs (*written* by PSQ_DaScale)
///
/// #PSQ_CHIRP:
///
Expand Down Expand Up @@ -1601,56 +1601,106 @@ static Function PSQ_GetLastPassingLongRHSweep(string device, variable headstage,
return INVALID_SWEEP_NUMBER
End

/// @brief Return the previously acquired sweep number
/// @brief Return the truth that sweepNo/headstage is from an adaptive SCI with special properties
///
/// But only when it fullfills all of the following conditions:
/// Special properties:
/// - DAScale supra adaptive analysis function was run
/// - failing set QC
/// - all analysis parameters are the same
/// - used same targetV autobias value
static Function PSQ_GetPreviousSetQCFailingAdaptive(string device, variable headstage, string params)
static Function PSQ_IsSuitableFailingAdaptiveSweep(string device, variable sweepNo, variable headstage, string params)

variable sweepNo, setQC, currentAutoBiasV
variable setQC, currentAutoBiasV
string key, opMode

sweepNo = AFH_GetLastSweepAcquired(device)

if(!IsValidSweepNumber(sweepNo))
return INVALID_SWEEP_NUMBER
endif

WAVE numericalValues = GetLBNumericalValues(device)
WAVE textualValues = GetLBTextualValues(device)

key = CreateAnaFuncLBNKey(PSQ_DA_SCALE, PSQ_FMT_LBN_DA_OPMODE, query = 1)
opMode = GetLastSettingTextIndep(textualValues, sweepNo, key, UNKNOWN_MODE)
opMode = GetLastSettingTextIndepSCI(numericalValues, textualValues, sweepNo, key, headstage, UNKNOWN_MODE)

if(cmpstr(opMode, PSQ_DS_ADAPT))
return INVALID_SWEEP_NUMBER
return 0
endif

key = CreateAnaFuncLBNKey(PSQ_DA_SCALE, PSQ_FMT_LBN_SET_PASS, query = 1)
setQC = GetLastSettingIndep(numericalValues, sweepNo, key, UNKNOWN_MODE, defValue = 0)
setQC = GetLastSettingIndepSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE, defValue = 0)

if(setQC)
return INVALID_SWEEP_NUMBER
return 0
endif

WAVE/T previousAnalysisParams = GetLastSetting(textualValues, sweepNo, ANALYSIS_FUNCTION_PARAMS_LBN, DATA_ACQUISITION_MODE)
WAVE/T previousAnalysisParams = GetLastSettingTextSCI(numericalValues, textualValues, sweepNo, ANALYSIS_FUNCTION_PARAMS_LBN, headstage, DATA_ACQUISITION_MODE)

if(cmpstr(previousAnalysisParams[headstage], params))
return INVALID_SWEEP_NUMBER
return 0
endif

currentAutoBiasV = DAG_GetNumericalValue(device, "setvar_DataAcq_AutoBiasV")

WAVE autoBiasV = GetLastSetting(numericalValues, sweepNo, "Autobias Vcom", DATA_ACQUISITION_MODE)

if(!CheckIfClose(autoBiasV[headstage], currentAutoBiasV, tol = 1e-2))
return INVALID_SWEEP_NUMBER
return 0
endif

return sweepNo
return 1
End

/// @brief Return passing sweeps from failing adaptive sets
///
/// Look into as many previous SCIs as given in the FailingAdaptiveSCIRange analysis parameter to return the
/// passing sweeps where the SCI fullfills the properties listed at @ref PSQ_IsSuitableFailingAdaptiveSweep()
static Function/WAVE PSQ_GetPreviousSetQCFailingAdaptive(string device, variable headstage, string params)

variable sweepNo, failingAdaptiveSCIRange, i, sciSweepNo

sweepNo = AFH_GetLastSweepAcquired(device)

if(!IsValidSweepNumber(sweepNo))
return $""
endif

failingAdaptiveSCIRange = AFH_GetAnalysisParamNumerical("FailingAdaptiveSCIRange", params, defValue = FAILING_ADAPTIVE_SCI_RANGE_DEFAULT)

if(failingAdaptiveSCIRange == 0)
// turned off
return $""
endif

WAVE numericalValues = GetLBNumericalValues(device)

// i == x: x SCIs earlier
sciSweepNo = sweepNo
for(i = 0; i < failingAdaptiveSCIRange; i++)
WAVE/Z sweepsSCI = AFH_GetSweepsFromSameSCI(numericalValues, sciSweepNo, headstage)

if(!WaveExists(sweepsSCI))
break
endif

sciSweepNo = WaveMin(sweepsSCI)
if(!PSQ_IsSuitableFailingAdaptiveSweep(device, sciSweepNo, headstage, params))
continue
endif

WAVE/ZZ passingAdaptiveSweeps = PSQ_DS_GetPassingDAScaleSweeps(numericalValues, sciSweepNo, headstage)

if(WaveExists(passingAdaptiveSweeps))
Concatenate/FREE/NP=(ROWS) {passingAdaptiveSweeps}, sweeps
endif

sciSweepNo -= 1
endfor

if(!WaveExists(sweeps))
return $""
endif

// ensure that the sweeps are ordered ascending
Sort sweeps, sweeps

return sweeps
End

/// @brief Return the truth that str is a valid PSQ_DAScale operation mode
Expand Down Expand Up @@ -2393,15 +2443,17 @@ static Function/WAVE PSQ_DS_GatherOvershootCorrection(STRUCT PSQ_DS_DAScaleParam
x = DAScales[i]
xp = DAScales[i + 1]
xs = (xp - x) / 2
xm = x + xs
xm = round(x + xs)

frac = yp / y - 1
DAScaleStepMin = cdp.daScaleStepMinNorm * y

maxFreqRelCond = frac > (cdp.maxFrequencyChangePercent * PERCENT_TO_ONE)
minFreqDistCond = abs(yp - y) > cdp.absFrequencyMinDistance
minDaScaleCond = xs > DAScaleStepMin
alreadyMeasured = WaveExists(futureDAScalesHistoric) && !IsNaN(GetRowIndex(futureDAScalesHistoric, val = xm))
alreadyMeasured = WaveExists(futureDAScalesHistoric) && !IsNaN(GetRowIndex(futureDAScalesHistoric, val = xm)) \
&& xm != x \
&& xm != xp

newDAScaleValue = maxFreqRelCond && minFreqDistCond && minDaScaleCond && !alreadyMeasured

Expand Down Expand Up @@ -2450,20 +2502,20 @@ static Function PSQ_DS_CalculateDAScale(STRUCT PSQ_DS_DAScaleParams &cdp, variab

ASSERT(cdp.maxFrequencyChangePercent > PSQ_DS_MAX_FREQ_OFFSET, "Invalid PSQ_DS_MAX_FREQ_OFFSET")
yp = y * (1 + (cdp.maxFrequencyChangePercent - PSQ_DS_MAX_FREQ_OFFSET) * PERCENT_TO_ONE)
xp = (yp - a) / (m)
xp = round((yp - a) / (m))

sprintf msg, "result %g with a=%g, m=%g, [x, xp]=[%g, %g], [y, yp]=[%g, %g], maxFrequencyChangePercent=%g, absDAScaleStepMin=%g, absDAScaleStepMax=%g\r", xp, a, m, x, xp, y, yp, cdp.maxFrequencyChangePercent, absDAScaleStepMin, absDAScaleStepMax
DEBUGPRINT(msg)

if(CheckIfSmall(m) || abs(x - xp) > absDAScaleStepMax)
// avoid excessive too large values
xp = x + absDAScaleStepMax
xp = ceil(x + absDAScaleStepMax)

sprintf msg, "corrected result: %g\r", xp
DEBUGPRINT(msg)
elseif(abs(y - yp) < cdp.absFrequencyMinDistance)
// or too small values
xp = x + absDAScaleStepMin
xp = ceil(x + absDAScaleStepMin)

sprintf msg, "corrected result: %g\r", xp
DEBUGPRINT(msg)
Expand Down Expand Up @@ -3014,19 +3066,20 @@ static Function/WAVE PSQ_DS_FilterPassingData(WAVE/Z data, WAVE/Z booleanQC, [va
return passingData
End

static Function/WAVE PSQ_DS_GetPassingDAScaleSweeps(WAVE numericalValues, variable passingSweep, variable headstage)
/// @brief Return a wave with all passing sweeps from the SCI containing sweepNo/headstage
static Function/WAVE PSQ_DS_GetPassingDAScaleSweeps(WAVE numericalValues, variable sweepNo, variable headstage)

string key

if(!IsValidSweepNumber(passingSweep))
if(!IsValidSweepNumber(sweepNo))
return $""
endif

WAVE/Z sweeps = AFH_GetSweepsFromSameSCI(numericalValues, passingSweep, headstage)
WAVE/Z sweeps = AFH_GetSweepsFromSameSCI(numericalValues, sweepNo, headstage)
ASSERT(WaveExists(sweeps), "Missing sweeps from passing DAScale SCI")

key = CreateAnaFuncLBNKey(PSQ_DA_SCALE, PSQ_FMT_LBN_SWEEP_PASS, query = 1)
WAVE sweepsQC = GetLastSettingIndepEachSCI(numericalValues, passingSweep, key, headstage, UNKNOWN_MODE)
WAVE sweepsQC = GetLastSettingIndepEachSCI(numericalValues, sweepNo, key, headstage, UNKNOWN_MODE)

WAVE/Z passingSweeps = PSQ_DS_FilterPassingData(sweeps, sweepsQC)

Expand Down Expand Up @@ -3059,7 +3112,7 @@ End

static Function/WAVE PSQ_DS_GetPassingRhSuAdSweepsAndStoreInLBN(string device, variable sweepNo, variable headstage, string params)

variable passingSupraSweep, passingRheobaseSweep, failingAdaptiveSweep
variable passingSupraSweep, passingRheobaseSweep
string key

passingSupraSweep = PSQ_GetLastPassingDAScale(device, headstage, PSQ_DS_SUPRA)
Expand All @@ -3078,12 +3131,16 @@ static Function/WAVE PSQ_DS_GetPassingRhSuAdSweepsAndStoreInLBN(string device, v
return $""
endif

failingAdaptiveSweep = PSQ_GetPreviousSetQCFailingAdaptive(device, headstage, params)
WAVE/ZZ passingAdSweepsFailSet = PSQ_GetPreviousSetQCFailingAdaptive(device, headstage, params)

if(!WaveExists(passingAdSweepsFailSet))
Make/FREE/N=0 passingAdSweepsFailSet
endif

if(TestOverrideActive())
WAVE overrideResults = GetOverrideResults()
WAVE sweeps = JWN_GetNumericWaveFromWaveNote(overrideResults, "/PassingRhSuAdSweeps")
JWN_SetNumberInWaveNote(overrideResults, "/FailingAdaptiveSweep", failingAdaptiveSweep)
JWN_SetWaveInWaveNote(overrideResults, "/PassingAdaptiveSweepFromFailingSet", passingAdSweepsFailSet)

// consistency checks
WAVE DAScalesRhSuAd = JWN_GetNumericWaveFromWaveNote(overrideResults, "/DAScalesRhSuAd")
Expand All @@ -3093,15 +3150,10 @@ static Function/WAVE PSQ_DS_GetPassingRhSuAdSweepsAndStoreInLBN(string device, v
else
WAVE numericalValues = GetLBNumericalValues(device)

WAVE passingRheobaseSweeps = PSQ_DS_GetPassingRheobaseSweeps(numericalValues, passingRheobaseSweep, headstage)
WAVE passingSupraSweeps = PSQ_DS_GetPassingDAScaleSweeps(numericalValues, passingSupraSweep, headstage)
WAVE/Z passingAdaptiveSweeps = PSQ_DS_GetPassingDAScaleSweeps(numericalValues, failingAdaptiveSweep, headstage)
WAVE passingRheobaseSweeps = PSQ_DS_GetPassingRheobaseSweeps(numericalValues, passingRheobaseSweep, headstage)
WAVE passingSupraSweeps = PSQ_DS_GetPassingDAScaleSweeps(numericalValues, passingSupraSweep, headstage)

if(!WaveExists(passingAdaptiveSweeps))
Make/N=0/FREE passingAdaptiveSweeps
endif

Concatenate/NP=(ROWS)/FREE {passingRheobaseSweeps, passingSupraSweeps, passingAdaptiveSweeps}, sweeps
Concatenate/NP=(ROWS)/FREE {passingRheobaseSweeps, passingSupraSweeps, passingAdSweepsFailSet}, sweeps
endif

WAVE/T RhSuAdSweepsLBN = LBN_GetTextWave()
Expand Down Expand Up @@ -3401,6 +3453,7 @@ Function/S PSQ_DAScale_GetParams()
"[DAScaleModifier:variable]," + \
"[DaScaleStepWidthMinMaxRatio:variable]," + \
"DAScales:wave," + \
"[FailingAdaptiveSCIRange]," + \
"[FinalSlopePercent:variable]," + \
"[MaximumSpikeCount:variable]," + \
"[MinimumSpikeCount:variable]," + \
Expand Down Expand Up @@ -3439,6 +3492,9 @@ Function/S PSQ_DAScale_GetHelp(string name)
return "DA Scale Factors in pA"
case "AbsFrequencyMinDistance":
return "Minimum absolute frequency distance for DAScale estimation. Only for \"AdaptiveSupra\"."
case "FailingAdaptiveSCIRange":
return "Number of stimset cycles (SCIs) we search backwards in time for failing Adaptive sets, defaults to 1. " \
+ "Set to 0 to turn it off and inf to look into all available SCIs. Only for \"AdaptiveSupra\"."
case "MaxFrequencyChangePercent":
return "The maximum allowed difference for the frequency for two consecutive measurements. " \
+ "In case this value is overshot, we redo the measurement with a fitting DAScale in-between. " \
Expand Down Expand Up @@ -3513,6 +3569,12 @@ Function/S PSQ_DAScale_CheckParam(string name, STRUCT CheckParametersStruct &s)
return "Invalid value"
endif
break
case "FailingAdaptiveSCIRange":
val = AFH_GetAnalysisParamNumerical(name, s.params)
if(!(IsNullOrPositiveAndFinite(val) || val == Inf))
return "Invalid value"
endif
break
case "NumInvalidSlopeSweepsAllowed":
val = AFH_GetAnalysisParamNumerical(name, s.params)
if(!(val >= 0 && val <= IDX_NumberOfSweepsInSet(s.setName)))
Expand Down Expand Up @@ -3907,6 +3969,10 @@ Function PSQ_DAScale(string device, STRUCT AnalysisFunction_V3 &s)
// when the fits from RhSuAd are not valid we are already done
endif

// F: fillin
// R: regular
// X: ???

if(WaveExists(futureDAScales))
PSQ_DS_CalcFutureDAScalesAndStoreInLBN(device, s.sweepNo, s.headstage, futureDAScales)
endif
Expand Down
2 changes: 1 addition & 1 deletion Packages/MIES/MIES_Constants.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,7 @@ Constant PSQ_DA_NUM_SWEEPS_SATURATION = 2
Constant PSQ_DA_NUM_INVALID_SLOPE_SWEEPS_ALLOWED = 3
Constant PSQ_DA_MAX_FREQUENCY_CHANGE_PERCENT = 20
Constant PSQ_DA_DASCALE_STEP_WITH_MIN_MAX_FACTOR = 3

Constant FAILING_ADAPTIVE_SCI_RANGE_DEFAULT = 1
///@}

/// @name PatchSeq Ramp
Expand Down
2 changes: 0 additions & 2 deletions Packages/MIES/MIES_GuiUtilities.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -2140,12 +2140,10 @@ Function ShowTraceInfoTags()
// Returns in S_value the state before toggling
DoIgorMenu/OVRD "Graph", "Show Trace Info Tags"
if(IsNull(S_value))
BUG("DoIgorMenu returned S_value as null string for \"Show Trace Info Tags\"")
KillWindow/Z $S_name
return NaN
endif
if(IsEmpty(S_value))
BUG("DoIgorMenu returned S_value as empty string for \"Show Trace Info Tags\"")
KillWindow/Z $S_name
return NaN
endif
Expand Down
4 changes: 2 additions & 2 deletions Packages/MIES/MIES_JSONWaveNotes.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ threadsafe Function JWN_SetWaveInWaveNote(WAVE wv, string jsonPath, WAVE noteWav
variable jsonID, idx
string jsonPathArray

ASSERT_TS(WaveExists(wv), "Missing wave")
ASSERT_TS(WaveExists(noteWave), "Missing noteWave")
ASSERT_TS(WaveExists(wv), "Missing wave to attach JSON wave note")
ASSERT_TS(WaveExists(noteWave), "Missing wave to add into the JSON wave note")

ASSERT_TS(!IsEmpty(jsonPath), "Empty jsonPath")

Expand Down
Loading
Loading