SpHr_ActivityOverTime [ flags ] [ keywords ] CFs=CFs, XsNs = { Xs,  Ns }, IPD = { IPDs, IPDneurons, IPDneuronLabels }, ILD = {  ILDs, ILDneurons, ILDneuronLabels} 


Generates neural activities patterns representive of auditory space over time within individual frequency bands (i.e., over frequency-specific IPD and/or ILD value(s) passed to the operation).


Required Keyword Parameters

CFs = CFs      CFs is the reference to a wave of filterbank center frequencies. The CFs wave is typically generated using the SpHr_FilterCenterFreqs operation.


XsNs = { Xs,  Ns }

    Xs is the reference to a wave of frequency-specific time (X-axis) values.

    Ns is the reference to a wave indicating the number of frequency-specific Xs and other values obtained.

    Waves Xs and Ns are typically generated using the SpHr_CrossingCarrierCues and/or SpHr_CrossingEnvelopeCues operations.


IPD = { IPDs, IPDneurons, IPDneuronLabels }

    IPDs is the reference to a wave of frequency-specific interaural phase differences (IPD) values.

    The IPDs wave is typically generated using the SpHr_CrossingCarrierCues and/or SpHr_CrossingEnvelopeCues operations.

    IPDneurons is the reference to a 'look-up' wave (table) of modeled neurons and activities evoked by interaural phase differences (IPD).

    IPDneuronLabels is the reference to a 'look-up' wave (table) of half-maximal neuron 'labels' (column 0) and maximal neuron 'labels' (column 1).

    Waves IPDneurons and IPDneuronLabels are typically generated using the SpHr_NeuronsIPD operation.


and/or


ILD = {  ILDs, ILDneurons, ILDneuronLabels [, ScaleILDtoITD] } 

    ILDs is the reference to a wave of frequency-specific interaural level differences (ILD) values.

    The ILDs wave is typically generated using the SpHr_CrossingCarrierCues and/or SpHr_CrossingEnvelopeCues operations.

    ILDneurons is the reference to a 'look-up' wave (table) of modeled neurons and activities evoked by interaural level differences (ILD).

    ILDneuronLabels is the reference to a 'look-up' wave (table) of neuron 'labels'.

    Waves ILDneurons and ILDneuronLabels are typically generated using the SpHr_NeuronsILD operation.

    ScaleILDtoITD is an optional variable to determine if ILD labels scale with ITD (ScaleILDtoITD = 1, Default) or scale directly with IPD labels (ScaleILDtoITD = 0). When labels scale with ITD, values in the wave ILDs are multiplied with a scaling value calculated as: frequency/((ILDlabelSpread/IPDlabelSpread); where frequency is center frequency, ILDlabelSpread is the average spread of ILD labels away from 0 dB and IPDlabelSpread is the average spread of IPD labels away from 0 seconds (average spread = (maximum label - minimum label) / 2)).


Note: If keywords IPD and ILD are both used, activity outputs are unit-less, reflecting a combination of IPD (cycles) or ITD (seconds, with /ITD flag) and ILD (dB).


Optional Keyword Parameters

Env = { FilterImpulseEnvelopeWidths [, NeuronWidth ] }

    The ‘Env=‘ keyword should be used when envelope IPDs passed using the IPDs keyword were obtained using the SpHr_CrossingEnvelopeCues operation. The SpHr_CrossingCarrierCues operation should not be used with the Env keyword.

    FilterImpulseEnvelopeWidths is a wave of filterbank impulse envelope widths. See the /W flag of SpHr_FilterBankBiquadCoefs operation.

    NeuronWidth is the width of IPD neurons at the half-maximal activity level. See the variable V_NeuronWidth set by the SpHr_NeuronsIPD operation. If neuronWidth is omitted, a default value of 0.4284 is used (log-normal 2 width parameters).

 

Wts = {  Wts [, LastWeightsDest ] }

    Wts is the reference to a wave of weights corresponding to IPDs and/or ILDs that have been pre-averaged across the left and right channels. The weights are typically obtained using the /AWts flag of the SpHr_CrossingCarrierCues operation.

    LastWeightsDest is an optional specification for a wave of frequency-specific weights obtained at the time of the last IPD and/or ILD value(s) passed to the operation. Values are meaningless if activities are averaged over time (/Avg = 1 or /Stats = 1).


Flags

/Lim = limit [ , limitTimes ]

    When modeled activities exceed the value set by limit, prior activities are diminished by the excess difference. If the /Lim flag is omitted, a default value of 20 is used. Prior activities diminish faster as the value of limit is reduced (i.e., activities accrue faster). Conversely, prior activities diminish more slowly as the value of limit is increased. Smaller limit values thus result in faster apparent 'adaptation' over time whereas larger values result in slower apparent 'adaptation' over time. Because IPDs and/or ILDs coincide with carrier or envelope cycles, prior activities diminish faster as center frequency increases. Two IPD and/or ILD values are assumed per  cycle and the actual limit used internally therefore equals limit * 2. Upon completion, the internal limit used is set to the variable V_FreqAvgLimit.

    limitTimes is an optional specification for a wave of times (s) when the specified limit is first reached for each center frequency. Modeled activities obtained before the specified limit is reached should be ignored. Upon completion, the time at which limit is first reached is set to the variable V_FreqMaxLimitTime.


/ITD [ = itd ]    itd = 1 is the same as /ITD flag alone. Data units indicate interaural time difference (ITD).

    itd = 0 is the same no flag. Data units indicate interaural phase difference (IPD).

    Output is unit-less when the 'ILD=" keyword is used with the 'IPD=' keyword.


/IHC = { limitIndex [,  halvingIndex ] }

    Inter-hemispheric coordination. When limitIndex = 1 (Default), prior activities are diminished in both hemispheres whenever activities in either hemisphere exceed limit ((See /Lim flag). When limitIndex = 0, prior activities are diminished independently in each hemisphere.

    When HalvingIndex = 1 (Default), maximal activities in both hemispheres are used to determine the level at which activities are reflected downward so that half-maximal activities may be viewed as 'peaks' (see /HMOP flag). When halvingIndex = 0, activities are reflected independently in each hemisphere. If halvingIndex is omitted, it is set to the same value as limitIndex.


/T = { startTime, endTime }

    Activities are obtained only when times passed by the Xs wave via the 'XsNs=' keyword are greater than startTime and less than endTime.

    Abbreviated form:

    /T =  endTime 


/F = { lowFreq , highFreq  }

    Activities are obtained only when center frequencies passed by the CFs wave via the 'CFs=' keyword are greater than lowFreq and less than highFreq.

    Abbreviated forms:

    /F = highFreq    If the 'Env=' keyword is omitted.

    /F = lowFreq    If the 'Env=' keyword is used.


/Q [ = quiet ]    Silences uncritical warnings. quiet = 1 is the same as the /Q flag alone.


/DF = dfRef    dfRef is an optional datafolder reference. Destination waves are written to this existing datafolder, overriding individual wave specifications. Waves are written to the current datafolder if dfRef is omitted and no other datafolder is specified.


Activity output flags

/HM [ = HalfmaxDatafolderString ]

    Activity patterns where half-maximal or 'edge' activities indicate the greatest contributions to auditory spatial perception.

    Activities for each center frequency (see /CFs or /CF flags) are written as individual waves to the datafolder specified by HalfmaxDatafolderString. If the datafolder specified by HalfmaxDatafolderString does not already exist in the current datafolder or in the datafolder specified by the /DF flag, a new datafolder named HalfmaxDatafolderString is created.

    To avoid generating excess waves, it is recommended that the datafolders created by this operation are killed between calls, after closing all windows using included waves.

    If the string HalfmaxDatafolderString is omitted, the default string "ActivityHalfMaxima" is used, or the string "EnvelopeActivityHalfMaxima" if the 'Env=' keyword was also used. In all cases, the string used is written to the string variable S_HMflag.

    Individual wave names are prefixed with HalfmaxDatafolderString followed by an underscore '_', an integer for center frequency, '_Hz_', and then either the 'Left' or 'Right'. 

    For example, if the flags /CF=100 and /HM="HM" were used, waves named HM_100_Hz_Left and HM_100_Hz_Right would be created in a new or already existing datafolder named HM.

    Similarly, if the flags /CF=100 and /HM with no string parameter were used, waves named ActivityHalfMaxima_100_Hz_Left and ActivityHalfMaxima_100_Hz_Right would be created in a new or already existing datafolder named ActivityHalfMaxima.


/HMOP = { useMaximalLabels [, reflectAtHalfmaximum] } 

    Output options for the /HM flag.

    If useMaximalLabels is set to 1, maximal labels are used instead of half-maximal labels. Half-maximal labels are used if useMaximalLabels is set to 0 (Default).

    If reflectAtHalfmaximum is omitted or set to 1(Default), activities above limit/2 (see /L=Limit flag) are reflected downward so that half-maximal activities may be viewed as 'peaks'.


/M [ = MaximalDatafolderString ]

    Activity patterns where maximal activities indicate the greatest contributions to auditory spatial perception.

    Activities for each center frequency (see /CFs or /CF flags) are written as individual waves to the datafolder specified by MaximalDatafolderString. If the datafolder specified by MaximalDatafolderString does not already exist in the current datafolder or in the datafolder specified by the /DF flag, a new datafolder named MaximalDatafolderString is created.

    To avoid generating excess waves, it is recommended that the datafolders created by this operation are killed between calls, after closing all windows using included waves.

    If the string MaximalDatafolderString is omitted, the default string "ActivityMaxima" is used, or the string "EnvelopeActivityMaxima" if the 'Env=' keyword was also used. In all cases, the string used is written to the string variable S_Mflag.

    Individual wave names are prefixed with MaximalDatafolderString followed by an underscore '_', an integer for center frequency, '_Hz_', and then either the 'Left' or 'Right'. 

    For example, if the flags /CF=100 and /M="M" were used, waves named M_100_Hz_Left and M_100_Hz_Right would be created in a new or already existing datafolder named M.

    Similarly, if the flags /CF=100 and /M with no string parameter were used, waves named ActivityMaxima_100_Hz_Left and ActivityMaxima_100_Hz_Right would be created in a new or already existing datafolder named ActivityMaxima.


/MOP = { useHalfmaximalLabels

    Output options for the /M flag.

    If useHalfmaximalLabels is set to 1, half-maximal labels are used instead of maximal labels. Maximal labels are used if useHalfmaximalLabels is set to 0 (Default).


/P [ = { HalfmaximalActivityPoints, MaximalActivityPoints } ] 

    HalfmaximalActivityPoints is the specification for a wave to which frequency-specific half-maximal activity levels and corresponding 'labels' are written.

    Frequency-specific values obtained over time are written across rows (time) and columns (frequency).

    'Labels' for the left and right hemispheres are written to layers 0 and 1, respectively, of the first chunk (chunk 0). 

    Activity levels for the left and right hemispheres are written to layers 0 and 1, respectively, of the second chunk (chunk 1). Note that activity levels should remain close to V_FreqAvgLimit (see /L=Limit flag) once this value is reached and that all outputs should be ignored if this level has not yet been reached.

    If the keywords IPD and ILD are both used, 'lables' are unit-less, reflecting IPD (cycles) or ITD (seconds, with /ITD flag) and ILD (dB). If the wave specification HalfmaximalActivityPoints is omitted, a wave named HalfmaximalActivityPoints is created. The name used is always written to the string variable S_PflagHM.

    MaximalActivityPoints is the specification for a wave to which frequency-specific maximal activity levels and corresponding 'labels' are written. If the wave specification MaximalActivityPoints is omitted, a wave named MaximalActivityPoints is created. The name used is always written to the string variable S_PflagM.

    The formatting of MaximalActivityPoints is otherwise similar to that of HalfmaximalActivityPoints.


/POP = { setPointsAtLimitsToNaN

    Output options for the /P flag.

    If setPointsAtLimitsToNaN is set to 1 (Default), then values in waves HalfmaximalActivityPoints and MaximalActivityPoints (see /P flag) are set to NaN if points are found to correspond to the first or last 'labels' passed using the 'IPD=' and/or 'ILD=' keywords. As an example, values are set to NaN if half-maximal 'labels' in IPDneuronLabels range from -0.2 to 0.2 (cycles) and a half-maximal 'peak' was found corresponding to 0.2 cycles.


/ACC [ = activityAccrual ]

    activityAccrual is the specification for a wave indicating how prior activities were diminished prior to the time of the last IPD and/or ILD value. If the activityAccrual specification is omitted, a wave named Accruals is created or a wave named EnvelopeAccruals if the 'Env=' keyword was also used. The name used is written to the string variable S_ACCflagRight.


Recommended Image Display flags

/X = xWaveNameString

    Matrices generated using the /HM, /M, /P, and /ACC flags are linearly scaled across rows from the time of the first passed IPD and/or ILD to the time of the last passed IPD and/or ILD (see 'IPD=' and 'ILD=' keywords). To use proper times corresponding to each individual IPD and/or ILD value, matrices generated using the /P and /ACC flags may be displayed as traces versus the Xs wave that was passed using the '/XsNs=' keyword.

    The /X flag creates 'image edge' values so that matrices generated using the /HM and /M flags may be properly displayed as images (see AppendImage and 'Image X and Y Coordinates - Unevenly Spaced' help topics). 

    'Image edge' values for each center frequency (see /CFs or /CF flags) are written as individual waves to the datafolder specified by xWaveNameString. If the datafolder specified by xWaveNameString does not already exist in the current datafolder or in the datafolder specified by the /DF flag, a new datafolder named xWaveNameString is created.

    To avoid generating excess waves, it is recommended that the datafolders created by this operation are killed between calls, after closing all windows using included waves.

    If the string xWaveNameString is omitted, the default string "XEdges" is used, or the string "EnvelopeXEdges" if the 'Env=' keyword was also used. In all cases, the string used is written to the string variable S_Xflag.

    Individual wave names are prefixed with xWaveNameString followed by an underscore '_', an integer for center frequency, and then '_Hz'.

    For example, if the flags /CF=100 and /X="MX" were used, a wave named MX_100_Hz would be created in a new or already existing datafolder named MX.

    Similarly, if the flags /CF=100 and /X with no string parameter were used, waves named XEdges_100_Hz would be created in a new or already existing datafolder named XEdges.


/Y = yWaveNameString

    Matrices generated using the /HM, /M, /P, and /ACC flags are linearly scaled across columns as determined by waves IPDneuronLabels (see 'IPD=' keyword) and/or ILDneuronLabels (see 'ILD=' keyword).

    Currently, neuron 'labels' are linearly spaced and thus the /Y flag need not be used.

    This may change if nonlinear, psychoacoustic, relationships between coordinates of azimuth and/or elevation and IPDs/ITDs and/or ILDs are devised. Not my job nor my immediate concern, since HRTF-based relationships seem inadequate and I was long ago excluded from academic resources...


Example

Function SpHr_ActivityOverTime_Example()

    variable useEnvelopeCues = 0 // carrier=0, envelope=1

    DFREF saveDFR = GetDataFolderDFR()

    NewDataFolder/O/S ActivityOverTime

    // Test Signal, ITD= 0.1 (ms), ILD= 3 (dB), Independence  0.1 (Index)

    SpHr_SignalBinaural/sec=1/Ramp=1/dB=70/HP=50/Sp=1/Ind=0.1/ITD={0.1}/ILD={3} 48000, NoiseBurst

    // Filter bank

    variable lowHz = 100, highHz = 8000, carrierHighHz = 2000

    SpHr_FilterCenterFreqs/R/Type=(2) lowHz, highHz, 32, CFs

    SpHr_FilterBankBiquadCoefs/W=FilterWidths 48000, CFs, coefBank

    SpHr_FilterBankBiquad /RMS/Dest=FilterBanks CFs, coefBank, NoiseBurst

    KillWaves/Z coefBank, NoiseBurst

    variable Frequency

    // Cues: IPD, ILDs, Xs, and XNs

    if(useEnvelopeCues)

        Frequency = 2500

        SpHr_CrossingEnvelopeCues/IPD=IPDs/ILD=ILDs/X=Xs/XN=Ns CFs, FilterBanks

    else

        Frequency = 300

        SpHr_CrossingCarrierCues/F={carrierHighHz}/IPD=IPDs/ILD=ILDs/X=Xs/XN=Ns/AWts={20,20,EnvWts} CFs, FilterBanks

    endif

    KillWaves/Z FilterBanks

    // Model left hemisphere IPD and ILD Neurons

    variable numNeurons = 501, numNeuronBins = 501

    SpHr_NeuronsIPD/R=1.2/L=0.2/N={numNeurons,numNeuronBins} IPDLabels, MaxLabels, IPDNeurons; killwaves/Z MaxLabels

    SpHr_NeuronsILD/R=(50)/W=6/S/L=24/N={numNeurons,numNeuronBins}/SL=(V_IPDLabelShift) ILDLabels, ILDNeurons

    // SpHr_ActivityOverTime - default output wave names

    variable LimitSet = 20 // Activity limit

    String HM_Str="", HM_DFStr=""

    if(useEnvelopeCues) // include Env={FilterWidths,V_NeuronWidth}

        SpHr_ActivityOverTime/Lim=(LimitSet)/ITD/HM/P/X CFs=CFs,XsNs={Xs,Ns},ILD={ILDs,ILDNeurons,ILDLabels,1},IPD={IPDs,IPDNeurons,IPDLabels},Env={FilterWidths,V_NeuronWidth}

    else

        SpHr_ActivityOverTime/Lim=(LimitSet)/F=(carrierHighHz)/ITD/HM/P/X CFs=CFs,XsNs={Xs,Ns},ILD={ILDs,ILDNeurons,ILDLabels,1},IPD={IPDs,IPDNeurons,IPDLabels}

    endif

    Wave HM_Points = $S_PflagHM

    Wave M_Points = $S_PflagM; KillWaves/Z M_Points

    // Display Activities re: Half-maximum

    Variable LimitUsed = V_FreqAvgLimit

    // custom ColorTable, /P=(0.5) so half-maximum is hot

    SpHr_ColorTable/P=(0.5)/Dest=ColorTable "Turbo"

    // Find index in CFs closest to Frequency

    Frequency = limit(Frequency,CFs[0],CFs[numpnts(CFs)-1])

    variable FreqIndex = round(BinarySearchInterp(CFs,Frequency))

    Frequency = CFs[FreqIndex] // CFs frequency

    KillWindow/Z LeftHemisphereOT; KillWindow/Z RightHemisphereOT

    // Left Hemisphere

    Display /W=(12,55,450,290)/N=LeftHemisphereOT/K=1 HM_Points[*][FreqIndex][0][0] vs Xs[][FreqIndex] as "Left Hemisphere "+num2str(Frequency)+" Hz"

    wave HM_L = $":"+S_HMflag+":"+S_HMflag+"_"+num2str(Frequency)+"_Hz_Left"

    wave XEdges = $":"+S_Xflag+":"+S_Xflag+"_"+num2str(Frequency)+"_Hz"

    AppendImage HM_L vs {XEdges,*}

    ModifyImage $NameOfWave(HM_L) ctab={0,LimitUsed,ColorTable,0}

    ModifyGraph mode=3,marker=19,rgb=(0,0,0),msize=1

    ModifyGraph zero(left)=1,mirror=0,zeroThick(left)=0.5

    SetAxis/A/E=2 left

    Label bottom "time (\\U)"

    Label left "Combination of ILD and ITD\\u#2"

    ModifyGraph margin(right)=54

    ColorScale/C/N=text0/F=0/B=1/A=RC/X=-15.00/Y=0.00

    ColorScale/C/N=text0 image=$NameOfWave(HM_L),side=1,frame=0

    ColorScale/C/N=text0 height=120, width=6,tickThick=0.5,tickLen=2,nticks=3,lblMargin=-4

    // Right Hemisphere

    KillWindow/Z RightHemisphereOT; KillWindow/Z RightHemisphereOT

    Display /W=(12,316,450,551)/N=RightHemisphereOT/K=1 HM_Points[*][FreqIndex][1][0] vs Xs[][FreqIndex] as "Right Hemisphere "+num2str(Frequency)+" Hz"

    wave HM_R = $":"+S_HMflag+":"+S_HMflag+"_"+num2str(Frequency)+"_Hz_Right"

    wave XEdges = $":"+S_Xflag+":"+S_Xflag+"_"+num2str(Frequency)+"_Hz"

    AppendImage HM_R vs {XEdges,*}

    ModifyImage $NameOfWave(HM_R) ctab={0,LimitUsed,ColorTable,0}

    ModifyGraph mode=3,marker=19,rgb=(0,0,0),msize=1

    ModifyGraph zero(left)=1,mirror=0,zeroThick(left)=0.5

    SetAxis/A/E=2 left

    Label bottom "time (\\U)"

    Label left "Combination of ILD and ITD\\u#2"

    ModifyGraph margin(right)=54

    ColorScale/C/N=text0/F=0/B=1/A=RC/X=-15.00/Y=0.00

    ColorScale/C/N=text0 image=$NameOfWave(HM_R),side=1,frame=0

    ColorScale/C/N=text0 height=120, width=6,tickThick=0.5,tickLen=2,nticks=3,lblMargin=-4

    SetDataFolder saveDFR

End

Contact: Brian