How to split one wave into multiple waves

Hi,

I would like to split one wave into equally sized waves. I am new to coding and I was hoping to get some help. 

Thanks a lot in advance.

Salome

function split(waveID)
    wave waveID
    variable nPoints = DimSize (waveID,0)
    Variable i, x
    for (i = 0; i < nPoints; i+=81)
        for (x = 2; x < 14; x+=1)
            duplicate/R=[i] waveID, wavex
        endfor
    endfor
end

 

Hi Salome,

You are very close.  Here is how I would approach it and make it a bit more general.  The first thing that caught my eye was the interval of 81 which is not a common number and I was wondering if it was accurate. Since Igor Pro starts at 0, going from 0 up to but not including 81 actually gives you 81 points and not 80 as is sometimes the real goal. To that end I have also brought the sample size into the parameters which makes the overall function a bit more reusable.  From there I determine the number of possible subsets and do not assume that there is an event multiple which cause an error if it is applied to a wave with a non-even number of subsets.

The duplicate function now goes through each chuck of the input wave and creates a subset. For the output wave name, notice I create a base name as a string and then convert the index value to a string to concatenate onto the base name and use the $ operation to have Igor use the value of the string. You could further extend the function to take a base name as an input parameter.  In your code the use of "wavex" does not change as you increment x. Wavex is just reused and actually will case an error the second time the duplicate function is called because it was created the first pass and will be used again the next time.  This is one reason I have also included the /O overwrite flag.  Usually when writing code you need to test it a couple of times and if you don't use the overwrite you need to remember to delete the created waves before each run.

I hope this helps and if I was bit too basic please forgive me, better too basic than too obscure. 

Andy

Function Split(WaveID,samplesize)
    wave waveID
    variable samplesize
   
    Variable HowMany
    HowMany = floor(Numpnts(WaveID)/samplesize)
    String NewBaseName ="NewName_"
    Variable index

    For(index=0;index<Howmany;index+=1)
        Duplicate/O/R=[index*samplesize,(index+1)*samplesize-1] waveID, $(NewBaseName+num2str(index))
    endfor
End

 

Another approach would be to first redimension the 1D wave into a 2D wave where each column of the 2D wave represents what you want to become 1 wave in the output. Then use the SplitWaves operation to split that 2D wave into multiple 1D waves.

Hi,

Thank you for helping me out last time.

I am trying to modify the code to normalize the data. If e.g I have a long wave that I split into 12 waves, for the first 6 waves I need to subtract the first points ( wave0-=wave[0], wave1-=wave1[0],… etc). However, for the last 6 waves (wave6-wave11) I need to subtract first values from the first 6 waves respectively (wave6-=wave[0], wave7-=wave[1], etc). The code does the normalization of the first 6 waves right but gives me wrong values for the other half.

I would appreciate a lot if somebody can help me to find the mistake.

Thanks in advance for your help!

Function Split(WaveID,samplesize,timeint)
    wave waveID
    variable samplesize
    variable timeint
   
    make/O /N=(samplesize) timewave=timeint*p
   
    Variable HowMany
    HowMany = floor(Numpnts(WaveID)/samplesize)
    String Phase1 ="Phase1_"
    String Phase2 ="Phase2_"
    String Phase1Norm ="P1Norm_"
    String Phase2Norm ="P2Norm_"
    Variable index
 
    For (index=0;index<=Howmany/2;index+=1)
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPphase1" //  $(Phase1+num2str(index))
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPp1norm" //$(Phase1Norm+num2str(index))
        wave Tempphase1, TempP1norm
        Tempp1norm-=tempphase1[0]
        DUplicate /O/D TEMPP1norm,$(Phase1Norm+num2str(index))
        DUplicate /O/D TEMPPhase1,$(Phase1+num2str(index))
        endfor
       
    For (index=howmany/2+1;index<=Howmany;index+=1)    
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPphase2" //  $(Phase2+num2str(index))
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPp2norm" //$(Phase2Norm+num2str(index))
        wave TEMPphase2,TEMPp2norm
        Tempp2norm=tempphase1[0]
        DUplicate /O/D TEMPP2norm,$(Phase2Norm+num2str(index))
        endfor
 End
       
       

Salome

Your first loop has finished, so when you do this (I guess you forgot a minus sign):

Tempp2norm-=tempphase1[0]

then tempphase1 is stuck in your last part extracted from waveID in loop one. A solution would be to access the right point for normalization from waveID directly or just have one loop, where you decide with an if branch what to use for normalization. E.g., if your index is above howmany/2 then switch to the Phase2 naming scheme, but use the Phase1 waves for normalization. By the way, if you are creating throwaway waves like tempphase, you can also use the /Free flag instead of /O, which makes these waves disappear at the end of execution.

In reply to by chozo

Hi and Thank you for the answer, 

The truth is I tried to use if loops/branch but it gives me the same wrong values for the second set of the normalized waves. I am very new to coding  so probably I don't know how to use the tempwaves right. 

Thanks again for your help, 

Salome 

Function Split(WaveID,samplesize,timeint)
    wave waveID
    variable samplesize
    variable timeint
   
    make/O /N=(samplesize) timewave=timeint*p
   
    Variable HowMany
    HowMany = floor(Numpnts(WaveID)/samplesize)
    String Phase1 ="Phase1_"
    String Phase2 ="Phase2_"
    String Phase1Norm ="P1Norm_"
    String Phase2Norm ="P2Norm_"
    Variable index
 
    For (index=0;index<=Howmany;index+=1)
        if (index<=Howmany/2)
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPphase1" //  $(Phase1+num2str(index))
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPp1norm" //$(Phase1Norm+num2str(index))
        wave Tempphase1, TempP1norm
        Tempp1norm-=tempphase1[0]
        DUplicate /O/D TEMPP1norm,$(Phase1Norm+num2str(index))
        DUplicate /O/D TEMPPhase1,$(Phase1+num2str(index))
        else  
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPphase2" //  $(Phase2+num2str(index))
        Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $"TEMPp2norm" //$(Phase2Norm+num2str(index))
        wave TEMPphase2,TEMPp2norm
        Tempp2norm-=tempphase1[0]
        DUplicate /O/D TEMPP2norm,$(Phase2Norm+num2str(index))
        endif
        endfor
 End

r the second set of the normilized way. 

Here is an alternative approach that is based on aclight suggestion:

Function splitEf(WaveID,samplesize)
    wave waveID
    variable samplesize
   
    Variable nCols=floor(Numpnts(WaveID)/samplesize)
    Duplicate/Free WaveID,dummyWave
    Redimension/N=(sampleSize,nCols) dummyWave
    // create a matrix wave from the original but subtract the first column
    MatrixOP/O/free normMatrix=dummyWave-rowRepeat(row(dummyWave,0),sampleSize)    
 
    if(dataFolderExists("clutter"))
        doAlert 1,"Clutter datafolder exists.  OK to erase?"
        if(V_flag==1)
            KillDataFolder/z Clutter
        else
            return 0
        endif
    endif
    ///SplitWave/DDF=clutter/N=ww dummyWave
    SplitWave/DDF=clutter/N=normw normMatrix
    // At this point you have all the waves that you want.
 End

 

Here, this may work (couldn't test it though):

Function Split(WaveID,samplesize,timeint)
    wave waveID
    variable samplesize
    variable timeint
   
    Make/O/N=(samplesize) timewave=timeint*p
   
    Variable HowMany = floor(Numpnts(WaveID)/samplesize)
    String Phase1 ="Phase1_"
    String Phase2 ="Phase2_"
    String Phase1Norm ="P1Norm_"
    String Phase2Norm ="P2Norm_"
   
    Variable index
    for (index=0; index <= HowMany; index+=1)
        if (index <= HowMany/2)
            Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $(Phase1+num2str(index))
            Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $(Phase1Norm+num2str(index))
            Wave Tempphase1 = $(Phase1+num2str(index))
            Wave TempP1norm = $(Phase1Norm+num2str(index))
            TempP1norm -= Tempphase1[0]
        else  
            Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $(Phase2+num2str(index))
            Duplicate/O/D/R=[index*samplesize,(index+1)*samplesize-1] waveID, $(Phase2Norm+num2str(index))
            Wave Tempphase1 = $(Phase1+num2str(index-HowMany/2))
            Wave TempP2norm = $(Phase2Norm+num2str(index))
            TempP2norm -= Tempphase1[0]
        endif
    endfor
    return 0
End

Note how I refer to the waves from the first branch in the second branch by using index-HowMany/2. This may need debugging depending on whether HowMany is even or odd.

I think this might do the job as well.

StrConstant splitPrefix = "split"

Function split_wave(wave iwave, variable nsplit)

    variable npts, ic, nSize, ni, nf
    string dName
   
    npts = numpnts(iwave)
    nSize = floor(npts/nsplit)

    // the first one
    sprintf dName "%s%d", splitPrefix, 0
    duplicate/O iwave $dName
    wave theSplit = $dName
    theSplit[nSize,npts-1] = NaN
    // the middle ones
    for (ic=1;ic<nsplit-1;ic+=1)
        sprintf dName "%s%d", splitPrefix, ic
        duplicate/O iwave $dName
        wave theSplit = $dName
        ni = ic*nSize - 1
        nf = ni + nSize + 1
        theSplit[0,ni] = NaN
        theSplit[nf,npts-1] = NaN
    endfor
    // the last one
    sprintf dName "%s%d", splitPrefix, nsplit-1
    duplicate/O iwave $dName
    wave theSplit = $dName
    theSplit[0,nf-1] = NaN
   
    for (ic=0;ic<nsplit;ic+=1)
        sprintf dName "%s%d", splitPrefix, ic
        wave theSplit = $dName
        WaveTransform zapNaNs theSplit
    endfor
   
    return 0

end

To test this, try on the command line input:

make/N=1002 testwave = p
split_wave(testwave,6)

This will give you six waves. The first five are 167 points. The last wave contains the overflow points.

In reply to by chozo

Hi again and thanks a lot! 

I tested the code and I only needed to change <= into < in the following lines 

for (index=0; index < HowMany; index+=1)
        if (index < HowMany/2)

and it worked :-)

Thanks again for your help!

Best regards, 

Salome 

 

In reply to by Igor

Thanks a lot for the code! 

I tested it and it does not normilize second set of waves right. But one of the codes suggested here works so I will go with it :-) 

 

Thanks a lot again, 

Best regards,

Salome