Skip to content

Commit

Permalink
TP: Added two functions that allow to retrieve info about TPs
Browse files Browse the repository at this point in the history
Added TP_GetStoredTP and TP_GetStoredTPsFromCycle that allow to get
information about a TP by tpMarker or TPs by cycle id and headstage.

- both functions allow to recreate the DA wave for the TPs with the flag includeDAC
- the returned data includes the AD, DA data as well as metadata for
  each returned TP (from TPStorage).

- These TP functions use the same TP utility function.
  • Loading branch information
MichaelHuth committed Sep 3, 2024
1 parent 99f5eb7 commit 82d748d
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 17 deletions.
173 changes: 156 additions & 17 deletions Packages/MIES/MIES_TestPulse.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -106,45 +106,184 @@ Function TP_StoreTP(device, TPWave, tpMarker, hsList)
SetNumberInWaveNote(storedTP, NOTE_INDEX, index)
End

/// @brief Return a number of consecutive test pulses ending with the TP
/// identified by tpMarker.
///
/// The wave reference wave will have as many columns as active headstages were used.
Function/WAVE TP_GetConsecutiveTPsUptoMarker(string device, variable tpMarker, variable number)
static Function TP_GetStoredTPIndex(string device, variable tpMarker)

variable numEntries

WAVE/WAVE storedTP = GetStoredTestPulseWave(device)
numEntries = GetNumberFromWaveNote(storedTP, NOTE_INDEX)

if(numEntries == 0)
return $""
return NaN
endif

Make/FREE/N=(numEntries) matches

Multithread matches[0, numEntries - 1] = GetNumberFromWaveNote(storedTP[p], "TPMarker") == tpMarker

FindValue/V=1 matches

if(V_row == -1)
return NaN
endif

return V_row
End

static Function/WAVE TP_RecreateDACWave(variable tpLengthPointsDAC, variable pulseStartPointsDAC, variable pulseLengthPointsDAC, variable clampMode, variable clampAmp, variable samplingInterval)

Make/FREE/D/N=0 tpDAC
TP_CreateTestPulseWaveImpl(tpDAC, tpLengthPointsDAC, pulseStartPointsDAC, pulseLengthPointsDAC)
tpDAC *= clampAmp
SetScale/P x, 0, samplingInterval, "ms", tpDAC
SetScale d, 0, 0, GetADChannelUnit(clampMode), tpDAC

return tpDAC
End

static Function/WAVE TP_GetTPMetaData(WAVE tpStorage, variable tpMarker, variable headstage)

variable i
variable numEntries = GetNumberFromWaveNote(tpStorage, NOTE_INDEX)
variable numlayers = DimSize(tpStorage, LAYERS)
variable dimMarker = FindDimLabel(tpStorage, LAYERS, "TPMarker")

FindValue/RMD=[][headstage][dimMarker]/V=(tpMarker) tpStorage
ASSERT(V_row >= 0, "Inconsistent TP data")
Duplicate/FREE/RMD=[V_row][headstage][] tpStorage, tpResult
Redimension/E=1/N=(numLayers) tpResult
for(i = 0; i < numLayers; i += 1)
SetDimLabel ROWS, i, $GetDimLabel(tpStorage, LAYERS, i), tpResult
endfor

return tpResult
End

/// @brief Returns data about a stored TestPulse from a given tpMarker
///
/// Returns a wave reference wave with 3 entries:
/// 0 : numeric wave with the acquired AD data of the test pulse (signal) in the format as created by @ref TP_StoreTP
/// 1 : numeric wave with the recreated DA data of the test pulse (command)
/// 2 : Additional information for the test pulse from creation and analysis in the format described for @ref GetTPStorage
/// As the information is for a single TP only, the wave contains a single slice (1 row)
///
/// @param device device name
/// @param tpMarker testpulse marker
/// @param headstage headstage number
/// @param includeDAC flag, when set the DAC wave of the testpulse is recreated
Function/WAVE TP_GetStoredTP(string device, variable tpMarker, variable headstage, variable includeDAC)

variable tpIndex
variable i, numlayers

ASSERT(headstage >= 0 && headstage < NUM_HEADSTAGES && IsInteger(headstage), "Invalid headstage number")
includeDAC = !!includeDAC

tpIndex = TP_GetStoredTPIndex(device, tpMarker)
if(IsNaN(tpIndex))
return $""
endif

Make/FREE/N=(number)/WAVE result
WAVE/WAVE tpStored = GetStoredTestPulseWave(device)
WAVE tpADC = tpStored[tpIndex]

WAVE tpStorage = GetTPStorage(device)
WAVE tpResult = TP_GetTPMetaData(tpStorage, tpMarker, headstage)

if(number > V_row + 1)
if(includeDAC)
WAVE tpDAC = TP_RecreateDACWave(tpResult[%TPLENGTHPOINTSDAC], tpResult[%PULSESTARTPOINTSDAC], tpResult[%PULSELENGTHPOINTSDAC], tpResult[%ClampMode], tpResult[%CLAMPAMP], tpResult[%SAMPLINGINTERVALADC])
else
WAVE/Z tpDAC = $""
endif

Make/FREE/WAVE tpAll = {tpADC, tpDAC, tpResult}

return tpAll
End

/// @brief Returns data about stored TestPulses from a given cycle id
///
/// Returns a wave reference wave with 3 entries:
/// 0 : wave ref wave that stores numeric waves with the acquired AD data of the test pulse (signal) in the format as created by @ref TP_StoreTP
/// The number of elements in the wave ref wave equals the number of test pulses in the cycle.
/// 1 : numeric wave with the recreated DA data of the test pulse (command)
/// Note: here only a single wave is recreated because the DA data for all test pulses of that cycle is identical
/// 2 : wave ref wave that stores additional information for the test pulses from creation and analysis in the format described for @ref GetTPStorage
/// The number of elements in the wave ref wave equals the number of test pulses in the cycle and has the same order as the signal waves from index 0.
/// Each element is a single slice (1 row) of tpStorage.
///
/// If no test pulses exist for the given cycle id a null wave is returned.
///
/// @param device device name
/// @param cycleId test pulse cycle id
/// @param headstage headstage number
/// @param includeDAC flag, when set the DAC wave of the testpulse is recreated
Function/WAVE TP_GetStoredTPsFromCycle(string device, variable cycleId, variable headstage, variable includeDAC)

variable i, numStored, numIndices

ASSERT(headstage >= 0 && headstage < NUM_HEADSTAGES && IsInteger(headstage), "Invalid headstage number")
includeDAC = !!includeDAC

WAVE/WAVE tpStored = GetStoredTestPulseWave(device)
numStored = GetNumberFromWaveNote(tpStored, NOTE_INDEX)
Make/FREE/D/N=(numStored) matchCycleId
matchCycleId[] = cycleId == GetNumberFromWaveNote(tpStored[p], "TPCycleID") ? p : NaN
WAVE/Z tpIndices = ZapNaNs(matchCycleId)
if(!WaveExists(tpIndices))
return $""
endif

numIndices = DimSize(tpIndices, ROWS)
Make/FREE/WAVE/N=(numIndices) tpsADC, tpsresult
for(i = 0; i < numIndices; i += 1)
Duplicate/FREE/RMD=[][headstage] tpStored[tpIndices[i]], tpADCSliced
Redimension/N=(-1) tpADCSliced
tpsADC[i] = tpADCSliced
endfor

Make/FREE/D/N=(numIndices) tpMarkers
tpMarkers[] = GetNumberFromWaveNote(tpsADC[p], "TPMarker")

WAVE tpStorage = GetTPStorage(device)
tpsResult[] = TP_GetTPMetaData(tpStorage, tpMarkers[p], headstage)

if(includeDAC)
Make/FREE/WAVE/N=(numIndices) tpsDAC
tpsDAC[] = TP_RecreateDACWave(WaveRef(tpsResult[p])[%TPLENGTHPOINTSDAC], WaveRef(tpsResult[p])[%PULSESTARTPOINTSDAC], WaveRef(tpsResult[p])[%PULSELENGTHPOINTSDAC], WaveRef(tpsResult[p])[%ClampMode], WaveRef(tpsResult[p])[%CLAMPAMP], WaveRef(tpsResult[p])[%SAMPLINGINTERVALADC])
else
WAVE/Z tpsDAC = $""
endif

Make/FREE/WAVE tpAll = {tpsADC, tpsDAC, tpsResult}

return tpAll
End

/// @brief Return a number of consecutive test pulses ending with the TP
/// identified by tpMarker.
///
/// The wave reference wave will have as many columns as active headstages were used.
Function/WAVE TP_GetConsecutiveTPsUptoMarker(string device, variable tpMarker, variable number)

variable tpIndex, tpCycleId

tpIndex = TP_GetStoredTPIndex(device, tpMarker)
if(IsNaN(tpIndex))
return $""
endif

if(number > tpIndex + 1)
// too few TPs available
return $""
endif

result[] = storedTP[V_row - number + 1 + p]
Make/FREE/N=(number)/WAVE result

// check that they all belong to the same TP cycle
Redimension/N=(number) matches
matches[] = GetNumberFromWaveNote(result[0], "TPCycleID") == GetNumberFromWaveNote(result[p], "TPCycleID")
WAVE/WAVE storedTP = GetStoredTestPulseWave(device)
result[] = storedTP[tpIndex - number + 1 + p]

if(Sum(matches) < number)
// check that they all belong to the same TP cycle
Make/FREE/N=(number) matches
tpCycleId = GetNumberFromWaveNote(result[0], "TPCycleID")
matches[] = tpCycleId == GetNumberFromWaveNote(result[p], "TPCycleID")
if(sum(matches) < number)
return $""
endif

Expand Down
109 changes: 109 additions & 0 deletions Packages/tests/HardwareBasic/UTF_TestPulseAndTPDuringDAQ.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,115 @@ static Function TPDuringDAQwithPS_PreAcq(device)
PGC_SetAndActivateControl(device, "check_settings_show_power", val = 1)
End

/// UTF_TD_GENERATOR DeviceNameGeneratorMD1
static Function GetStoredTPTest([str])
string str

STRUCT DAQSettings s
InitDAQSettingsFromString(s, "MD1_RA0_I0_L0_BKG1_STP1_TP1" + \
"__HS0_DA0_AD0_CM:IC:_ST:TestPulse:" + \
"__HS1_DA1_AD1_CM:VC:_ST:TestPulse:")

AcquireData_NG(s, str)

CtrlNamedBackGround StopTPAfterFiveSeconds, start=(ticks + TP_DURATION_S * 60), period=1, proc=StopTPAfterFiveSeconds_IGNORE
End

static Function GetStoredTPTest_REENTRY([str])
string str
variable i, sweepNo, marker, cycleId, headstage, numHS

Make/FREE/D headstages = {0, 1}
numHS = DimSize(headstages, ROWS)

CHECK_EQUAL_VAR(GetSetVariable(str, "SetVar_Sweep"), 0)

sweepNo = AFH_GetLastSweepAcquired(str)
CHECK_EQUAL_VAR(sweepNo, NaN)

WaitAndCheckStoredTPs_IGNORE(str, numHS)

WAVE/Z TPStorage = GetTPStorage(str)
CHECK_WAVE(TPStorage, NUMERIC_WAVE)
marker = TPStorage[0][0][%TPMarker]
CHECK_NEQ_VAR(marker, NaN)

// Check GetStoredTP
WAVE/Z storedTPData = TP_GetStoredTP(str, NaN, 0, 1)
CHECK_WAVE(storedTPData, NULL_WAVE)

try
WAVE/Z storedTPData = TP_GetStoredTP(str, marker, NaN, 1)
FAIL()
catch
PASS()
endtry

Make/FREE/WAVE/N=(numHS) tpDACsRef, tpResultsRef
for(headstage : headstages)
WAVE/Z storedTPData = TP_GetStoredTP(str, marker, headstage, 1)
CHECK_WAVE(storedTPData, WAVE_WAVE)
CHECK_EQUAL_VAR(DimSize(storedTPData, ROWS), 3)

WAVE/WAVE tpData = storedTPData
WAVE/Z tpADC = tpData[0]
WAVE/Z tpDAC = tpData[1]
WAVE/Z tpInfo = tpData[2]

CHECK_WAVE(tpADC, NUMERIC_WAVE)
CHECK_GE_VAR(DimSize(tpADC, ROWS), 1)
CHECK_WAVE(tpDAC, NUMERIC_WAVE)
CHECK_GE_VAR(DimSize(tpDAC, ROWS), 1)

WAVE tpResult = MIES_TP#TP_GetTPMetaData(tpStorage, marker, headstage)
CHECK_EQUAL_WAVES(tpInfo, tpResult)

tpDACsRef[i] = tpDAC
tpResultsRef[i] = tpInfo
i += 1
endfor

// Check TP_GetStoredTPsFromCycle
cycleId = TPStorage[0][0][%TPCycleID]
CHECK_NEQ_VAR(cycleId, NaN)

WAVE/Z storedTPData = TP_GetStoredTPsFromCycle(str, NaN, 0, 1)
CHECK_WAVE(storedTPData, NULL_WAVE)

try
WAVE/Z storedTPData = TP_GetStoredTPsFromCycle(str, cycleId, NaN, 1)
FAIL()
catch
PASS()
endtry

i = 0
for(headstage : headstages)
WAVE/Z storedTPData = TP_GetStoredTPsFromCycle(str, cycleId, headstage, 1)
CHECK_WAVE(storedTPData, WAVE_WAVE)
CHECK_EQUAL_VAR(DimSize(storedTPData, ROWS), 3)

WAVE/WAVE tpData = storedTPData
WAVE/WAVE/Z tpADCs = tpData[0]
WAVE/WAVE/Z tpDACs = tpData[1]
WAVE/WAVE/Z tpInfoWref = tpData[2]

CHECK_WAVE(tpADCs, WAVE_WAVE)
CHECK_GE_VAR(DimSize(tpADCs, ROWS), 1)
CHECK_WAVE(tpDACs, WAVE_WAVE)
CHECK_GE_VAR(DimSize(tpDACs, ROWS), 1)
CHECK_WAVE(tpInfoWref, WAVE_WAVE)
CHECK_EQUAL_VAR(DimSize(tpADCs, ROWS), DimSize(tpInfoWref, ROWS))
CHECK_EQUAL_VAR(DimSize(tpADCs, ROWS), DimSize(tpDACs, ROWS))

WAVE tpInfo0 = tpInfoWref[0]
CHECK_EQUAL_WAVES(tpInfo0, tpResultsRef[i])
WAVE tpDAC0 = tpDACs[0]
CHECK_EQUAL_WAVES(tpDAC0, tpDACsRef[i])
i += 1
endfor
End

// UTF_TD_GENERATOR DeviceNameGeneratorMD1
static Function TPDuringDAQwithPS([str])
string str
Expand Down

0 comments on commit 82d748d

Please sign in to comment.