Skip to content

Commit 7d217c9

Browse files
committed
SF: operation avg add mode to average over groups of data
- a new mode was added "group" - the user has to give an array of datasets with at least 2 elements as first argument - the averaging is done over the first entries of the datasets, then over the second and so on ds0 = dataset(1, 2, 3) ds1 = dataset(4, 5, 6) avg([$ds1, $ds2], group) Then 1 is averaged with 4 2 is averaged with 5 3 is averaged with 6 and the resulting dataset contains three elements with single point waves equal to dsResult = dataset(2.5, 3.5, 4.5)
1 parent d9bed87 commit 7d217c9

File tree

3 files changed

+206
-39
lines changed

3 files changed

+206
-39
lines changed

Packages/MIES/MIES_SweepFormula_Helpers.ipf

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ End
248248
/// @param copy [optional, defaults to 0] If the returned data should be safe for modification (true) or is only read (false)
249249
/// @param[out] wvNote [optional, defaults to None] Wave note of the dataset, useful for single result cases where you still need
250250
/// to query JSON wave note entries
251-
Function/WAVE SFH_GetArgumentAsWave(STRUCT SF_ExecutionData &exd, string opShort, variable argNum, [string defOp, WAVE/Z defWave, variable singleResult, variable expectedMinorType, variable expectedMajorType, variable copy, string &wvNote])
251+
/// @param resolveSelect [optional, defaults to 0] If set then argument of the select type are automatically converted to sweep data, effectively the data() operation is applied
252+
/// As with data, if the argument is an array of selects, each sweep result gets concatenated to a wref wave
253+
Function/WAVE SFH_GetArgumentAsWave(STRUCT SF_ExecutionData &exd, string opShort, variable argNum, [string defOp, WAVE/Z defWave, variable singleResult, variable expectedMinorType, variable expectedMajorType, variable copy, string &wvNote, variable resolveSelect])
252254

253255
variable checkExist, numArgs, checkMinorType, checkMajorType, result
254256
string msg
@@ -273,12 +275,23 @@ Function/WAVE SFH_GetArgumentAsWave(STRUCT SF_ExecutionData &exd, string opShort
273275
else
274276
singleResult = !!singleResult
275277
endif
276-
copy = ParamIsDefault(copy) ? 0 : !!copy
278+
copy = ParamIsDefault(copy) ? 0 : !!copy
279+
resolveSelect = ParamIsDefault(resolveSelect) ? 0 : !!resolveSelect
277280

278281
numArgs = SFH_GetNumberOfArguments(exd)
279282

280283
if(argNum < numArgs)
281-
WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum)
284+
if(resolveSelect)
285+
WAVE/Z/WAVE input = SFH_GetArgumentSelect(exd, argNum, doNotEnforce = 1)
286+
if(WaveExists(input))
287+
WAVE/WAVE data = SFH_GetDataFromSelect(exd.graph, input)
288+
WAVE input = data
289+
else
290+
WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum)
291+
endif
292+
else
293+
WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum)
294+
endif
282295

283296
if(singleResult)
284297
sprintf msg, "Argument #%d of operation %s: Too many input values", argNum, opShort
@@ -2094,3 +2107,53 @@ Function SFH_StoreAssertInfoExecutor(variable jsonId, variable srcLocId, string
20942107
info[%JSONPATH] = jsonPath
20952108
info[%STEP] = num2istr(SF_STEP_EXECUTOR)
20962109
End
2110+
2111+
Function/WAVE SFH_GetDataFromSelect(string graph, WAVE/WAVE selectData)
2112+
2113+
WAVE/WAVE output = SFH_GetSweepsForFormula(graph, selectData, SF_OP_DATA)
2114+
if(!DimSize(output, ROWS))
2115+
DebugPrint("Call to SFH_GetSweepsForFormula returned no results")
2116+
endif
2117+
2118+
SFH_AddOpToOpStack(output, "", SF_OP_DATA)
2119+
SFH_ResetArgSetupStack(output, SF_OP_DATA)
2120+
2121+
return output
2122+
End
2123+
2124+
/// @brief Function returns a wave reference wave with one wave for each element of the dataset array
2125+
/// Each wave contains the resolved dataset (as wave references)
2126+
///
2127+
/// @param exd Execution data structure
2128+
/// @param argNum Argument index
2129+
/// @param resolveSelect [optional, defaults to 0] If set then argument of the select type are automatically converted to sweep data, effectively the data() operation is applied
2130+
/// As with data, if the argument is an array of selects, each sweep result gets concatenated to a wref wave
2131+
/// @returns wref wave with one wave for each dataset array element. Each wave contains the resolved dataset as waveref wave.
2132+
Function/WAVE SFH_GetDatasetArrayAsResolvedWaverefs(STRUCT SF_ExecutionData &exd, variable argNum, [variable resolveSelect])
2133+
2134+
variable numGroups
2135+
2136+
resolveSelect = ParamIsDefault(resolveSelect) ? 0 : !!resolveSelect
2137+
2138+
SFH_ASSERT(argNum < SFH_GetNumberOfArguments(exd), "operation has no argument number " + num2istr(argNum))
2139+
if(resolveSelect)
2140+
WAVE/Z/WAVE input = SFH_GetArgumentSelect(exd, argNum, doNotEnforce = 1)
2141+
if(WaveExists(input))
2142+
// In contrast to SFH_GetArgumentAsWave, resolve all selects from the array separately
2143+
numGroups = DimSize(input, ROWS)
2144+
SFH_ASSERT(numGroups >= 2, "First argument must be an array with at least two elements")
2145+
Make/FREE/WAVE/N=(numGroups) dataFromEachGroup = SFH_GetDataFromSelect(exd.graph, {input[p]})
2146+
endif
2147+
endif
2148+
2149+
if(!WaveExists(dataFromEachGroup))
2150+
WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, argNum)
2151+
SFH_ASSERT(IsTextWave(input[0]), "Expected a dataset")
2152+
WAVE/T elemRefs = input[0]
2153+
numGroups = DimSize(elemRefs, ROWS)
2154+
SFH_ASSERT(numGroups > 1, "First argument must be an array with at least two elements")
2155+
Make/FREE/WAVE/N=(numGroups) dataFromEachGroup = SFH_AttemptDatasetResolve(elemRefs[p], checkWithSFHAssert = 1)
2156+
endif
2157+
2158+
return dataFromEachGroup
2159+
End

Packages/MIES/MIES_SweepFormula_Operations.ipf

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ static StrConstant SF_OP_APFREQUENCY_X_TIME = "time"
3232

3333
static StrConstant SF_OP_AVG_INSWEEPS = "in"
3434
static StrConstant SF_OP_AVG_OVERSWEEPS = "over"
35+
static StrConstant SF_OP_AVG_GROUPS = "group"
3536

3637
static StrConstant SF_OP_EPOCHS_TYPE_RANGE = "range"
3738
static StrConstant SF_OP_EPOCHS_TYPE_NAME = "name"
@@ -487,40 +488,72 @@ End
487488

488489
Function/WAVE SFO_OperationAvg(STRUCT SF_ExecutionData &exd)
489490

490-
variable numArgs
491-
string mode
491+
variable numArgs, numGroups
492+
string mode
492493
string opShort = SF_OP_AVG
493494

494495
numArgs = SFH_CheckArgumentCount(exd, opShort, 1, maxArgs = 2)
495496

496-
mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS})
497+
mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS, SF_OP_AVG_GROUPS})
497498
// attempt to resolve as select type argument or array of it
498499
WAVE/Z/WAVE input = SFH_GetArgumentSelect(exd, 0, doNotEnforce = 1)
499-
if(WaveExists(input))
500-
// successful resolved as selection
501-
if(!CmpStr(mode, SF_OP_AVG_INSWEEPS) || !CmPStr(mode, SF_OP_AVG_OVERSWEEPS))
502-
WAVE/WAVE data = SFO_GetDataFromSelect(exd.graph, input)
503-
WAVE input = data
504-
endif
500+
501+
if(!CmpStr(mode, SF_OP_AVG_INSWEEPS) || !CmpStr(mode, SF_OP_AVG_OVERSWEEPS))
502+
WAVE/WAVE input = SFH_GetArgumentAsWave(exd, opShort, 0, resolveSelect = 1)
503+
strswitch(mode)
504+
case SF_OP_AVG_INSWEEPS:
505+
WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, DimSize(input, ROWS))
506+
output[] = SFO_OperationAvgImplIn(input[p])
507+
SFH_TransferFormulaDataWaveNoteAndMeta(input, output, opShort, SF_DATATYPE_AVG)
508+
return SFH_GetOutputForExecutor(output, exd.graph, opShort, clear = input)
509+
510+
case SF_OP_AVG_OVERSWEEPS:
511+
return SFO_OperationAvgImplOver(input, exd.graph, opShort)
512+
513+
default:
514+
FATAL_ERROR("Unhandled avg operation mode")
515+
endswitch
516+
elseif(!CmpStr(mode, SF_OP_AVG_GROUPS))
517+
WAVE/WAVE dataFromEachGroup = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 0, resolveSelect = 1)
518+
WAVE/WAVE averagedGroup = SFO_OperationAvgImplSweepGroups(dataFromEachGroup, exd.graph, opShort)
519+
SFH_TransferFormulaDataWaveNoteAndMeta(dataFromEachGroup[0], averagedGroup, opShort, opShort)
520+
521+
return SFH_GetOutputForExecutor(averagedGroup, exd.graph, opShort)
505522
else
506-
// any other type
507-
WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, 0)
523+
FATAL_ERROR("Unhandled avg operation mode")
508524
endif
525+
End
509526

510-
strswitch(mode)
511-
case SF_OP_AVG_INSWEEPS:
512-
WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, DimSize(input, ROWS))
513-
output[] = SFO_OperationAvgImplIn(input[p])
514-
SFH_TransferFormulaDataWaveNoteAndMeta(input, output, opShort, SF_DATATYPE_AVG)
515-
return SFH_GetOutputForExecutor(output, exd.graph, opShort, clear = input)
527+
static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSelection, string graph, string opShort)
516528

517-
case SF_OP_AVG_OVERSWEEPS:
518-
return SFO_OperationAvgImplOver(input, exd.graph, opShort)
529+
variable numData, numMaxSweeps, numGroups, i, j
530+
STRUCT RGBColor s
519531

520-
default:
521-
FATAL_ERROR("Unknown avg operation mode")
522-
endswitch
532+
[s] = GetTraceColorForAverage()
533+
Make/FREE/W/U traceColor = {s.red, s.green, s.blue}
523534

535+
numGroups = DimSize(sweepsFromEachSelection, ROWS)
536+
Make/FREE/D/N=(numGroups) sweepCnts = DimSize(sweepsFromEachSelection[p], ROWS)
537+
numMaxSweeps = WaveMax(sweepCnts)
538+
WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numMaxSweeps)
539+
for(i = 0; i < numMaxSweeps; i += 1)
540+
Make/FREE/WAVE/N=(numGroups) avgSet
541+
numData = 0
542+
for(j = 0; j < numGroups; j += 1)
543+
if(DimSize(sweepsFromEachSelection[j], ROWS) > i)
544+
avgSet[numData] = WaveRef(sweepsFromEachSelection[j], row = i)
545+
numData += 1
546+
endif
547+
endfor
548+
Redimension/N=(numData) avgSet
549+
WAVE/WAVE avg = MIES_fWaveAverage(avgSet, 1, IGOR_TYPE_64BIT_FLOAT)
550+
output[i] = avg[0]
551+
JWN_SetWaveInWaveNote(output[i], SF_META_TRACECOLOR, traceColor)
552+
JWN_SetNumberInWaveNote(output[i], SF_META_TRACETOFRONT, 1)
553+
JWN_SetNumberInWaveNote(output[i], SF_META_LINESTYLE, 0)
554+
endfor
555+
556+
return output
524557
End
525558

526559
static Function/WAVE SFO_OperationAvgImplOver(WAVE/WAVE input, string graph, string opShort)
@@ -690,24 +723,11 @@ Function/WAVE SFO_OperationData(STRUCT SF_ExecutionData &exd)
690723
SFH_CheckArgumentCount(exd, SF_OP_DATA, 0, maxArgs = 1)
691724
WAVE/WAVE selectData = SFH_GetArgumentSelect(exd, 0)
692725

693-
WAVE output = SFO_GetDataFromSelect(exd.graph, selectData)
726+
WAVE output = SFH_GetDataFromSelect(exd.graph, selectData)
694727

695728
return SFH_GetOutputForExecutor(output, exd.graph, SF_OP_DATA)
696729
End
697730

698-
static Function/WAVE SFO_GetDataFromSelect(string graph, WAVE/WAVE selectData)
699-
700-
WAVE/WAVE output = SFH_GetSweepsForFormula(graph, selectData, SF_OP_DATA)
701-
if(!DimSize(output, ROWS))
702-
DebugPrint("Call to SFH_GetSweepsForFormula returned no results")
703-
endif
704-
705-
SFH_AddOpToOpStack(output, "", SF_OP_DATA)
706-
SFH_ResetArgSetupStack(output, SF_OP_DATA)
707-
708-
return output
709-
End
710-
711731
// dataset(array data1, array data2, ...)
712732
Function/WAVE SFO_OperationDataset(STRUCT SF_ExecutionData &exd)
713733

Packages/tests/Basic/UTF_SweepFormula_Operations.ipf

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,90 @@ static Function TestOperationAverage()
12181218
CHECK_EQUAL_VAR(JWN_GetNumberFromWaveNote(data, SF_META_LINESTYLE), 0)
12191219
WAVE/Z tColor = JWN_GetNumericWaveFromWaveNote(data, SF_META_TRACECOLOR)
12201220
CHECK_EQUAL_WAVES(tColor, {s.red, s.green, s.blue}, mode = WAVE_DATA)
1221+
1222+
str = "ds0 = dataset(1, 2, 3)\rds1 = dataset(2, 3, 4)\r\ravg([$ds0, $ds1], group)"
1223+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1224+
CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 3)
1225+
WAVE wv0 = dataRef[0]
1226+
CHECK_EQUAL_WAVES(wv0, {1.5}, mode = WAVE_DATA)
1227+
WAVE wv1 = dataRef[1]
1228+
CHECK_EQUAL_WAVES(wv1, {2.5}, mode = WAVE_DATA)
1229+
WAVE wv2 = dataRef[2]
1230+
CHECK_EQUAL_WAVES(wv2, {3.5}, mode = WAVE_DATA)
1231+
1232+
str = "ds0 = dataset(1, 2, 3)\rds1 = dataset(2, 3, 4)\rds2 = dataset(6, 10, 14)\r\ravg([$ds0, $ds1, $ds2], group)"
1233+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1234+
CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 3)
1235+
WAVE wv0 = dataRef[0]
1236+
CHECK_EQUAL_WAVES(wv0, {3}, mode = WAVE_DATA)
1237+
WAVE wv1 = dataRef[1]
1238+
CHECK_EQUAL_WAVES(wv1, {5}, mode = WAVE_DATA)
1239+
WAVE wv2 = dataRef[2]
1240+
CHECK_EQUAL_WAVES(wv2, {7}, mode = WAVE_DATA)
1241+
1242+
try
1243+
str = "ds0 = dataset(1, 2, 3)\r\ravg([$ds0], group)"
1244+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1245+
FAIL()
1246+
catch
1247+
PASS()
1248+
endtry
1249+
1250+
try
1251+
str = "avg(1, group)"
1252+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1253+
FAIL()
1254+
catch
1255+
PASS()
1256+
endtry
1257+
End
1258+
1259+
static Function TestOperationAverage2()
1260+
1261+
string win, device
1262+
string str
1263+
variable sweepNo, numResults, i
1264+
1265+
[win, device] = CreateEmptyUnlockedDataBrowserWindow()
1266+
1267+
sweepNo = 0
1268+
1269+
win = CreateFakeSweepData(win, device, sweepNo = sweepNo)
1270+
win = CreateFakeSweepData(win, device, sweepNo = sweepNo + 1)
1271+
1272+
// Meta Data Transfer from first group
1273+
str = "ds0 = data(select(selsweeps(0), selvis(all)))\rds1 = data(select(selsweeps(1), selvis(all)))\r\ravg([$ds0, $ds1], group)"
1274+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1275+
CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 4)
1276+
WAVE wv0 = dataRef[0]
1277+
sweepNo = JWN_GetNumberFromWaveNote(wv0, SF_META_SWEEPNO)
1278+
CHECK_EQUAL_VAR(sweepNo, 0)
1279+
1280+
// Use implicit select resolve instead
1281+
str = "avg([select(selsweeps(0), selvis(all)), select(selsweeps(1), selvis(all))], group)"
1282+
WAVE/WAVE dataRef2 = SFE_ExecuteFormula(str, win)
1283+
CHECK_EQUAL_VAR(DimSize(dataRef2, ROWS), 4)
1284+
1285+
numResults = DimSize(dataRef2, ROWS)
1286+
for(i = 0; i < numResults; i += 1)
1287+
WAVE wv0 = dataRef[i]
1288+
WAVE wv1 = dataRef2[i]
1289+
JWN_SetNumberInWaveNote(wv0, SF_META_COLOR_GROUP, 0)
1290+
JWN_SetNumberInWaveNote(wv1, SF_META_COLOR_GROUP, 0)
1291+
CHECK_EQUAL_WAVES(wv0, wv1)
1292+
endfor
1293+
1294+
str = "avg(select(selsweeps(0, 1), selvis(all)))"
1295+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1296+
CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 8)
1297+
WAVE wv0 = dataref[0]
1298+
CHECK_EQUAL_WAVES(wv0, {4.5}, mode = WAVE_DATA)
1299+
1300+
str = "avg(select(selsweeps(0, 1), selvis(all)), over)"
1301+
WAVE/WAVE dataRef = SFE_ExecuteFormula(str, win)
1302+
CHECK_EQUAL_VAR(DimSize(dataRef, ROWS), 1)
1303+
WAVE wv0 = dataref[0]
1304+
CHECK_EQUAL_WAVES(wv0, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, mode = WAVE_DATA)
12211305
End
12221306

12231307
static Function CheckSweepsFromData(WAVE/WAVE dataWref, WAVE sweepRef, variable numResults, WAVE chanIndex, [WAVE ranges])

0 commit comments

Comments
 (0)