Merge 2 waves

Hi,

I want to merge multiple 3D waves in a way, that the layers from the different waves are alternating. Thus giving MergeWave[][][0] = a[][][0], MergeWave[][]1] = b[][][0], MergeWave[][][2] = a[][][1], MergeWave[][]3] = b[][][1] and so on...
Currently I'm looping over all layers of MergeWave, but this scales rather badly with the size of the input waves. Is there a better way?


Function merge()
	Make /O /N=(500,500, 100) a = 0
	Make /O /N=(500, 500, 100) b = 1
	
	Make /O /N=(500, 500, 200) MergeWave
	
	Variable i, timerRefNum, microSeconds
	
	timerRefNum = startMSTimer
	for (i=0; i<50; i+=1)
		MergeWave[][][i*2] = a[x][y][i*2]
		MergeWave[][][i*2+1] = b[x][y][i*2+1]
	endfor
	microSeconds = stopMSTimer(timerRefNum)
	Print microSeconds/1000, "ms passed."
End
The key here is to use ImageTransform to set the planes. But while I was writing it up I figured I might multithread it as well. I merged my code with yours for easy comparison.


Function merge()
	Make /O /N=(500,500, 100) a = 0
	Make /O /N=(500, 500, 100) b = 1
	
	Make /O /N=(500, 500, 200) MergeWave, MergeWave_New
	
	Variable i, timerRefNum, microSeconds
	
	timerRefNum = startMSTimer
	for (i=0; i<50; i+=1)
		MergeWave[][][i*2] = a[x][y][i*2]
		MergeWave[][][i*2+1] = b[x][y][i*2+1]
	endfor
	microSeconds = stopMSTimer(timerRefNum) / 1e6
	
	variable myTime
	
	timerRefNum = startMSTimer
	Make /N=(DimSize(a, 2)) /FREE W_Dummy	// this is just a trick to use the MultiThread keyword
	MultiThread W_Dummy = MergePlane(a, b, MergeWave_New, p)
	myTime = StopMSTimer(timerRefNum) / 1e6
	
	Printf "Original: %g. Now: %g\r", microSeconds, myTime
End

ThreadSafe Function MergePlane(M_PlaneFromThisWave1, M_PlaneFromThisWave2, M_PlaneToThisWave, fromIndex)
    wave M_PlaneFromThisWave1, M_PlaneFromThisWave2, M_PlaneToThisWave
    variable fromIndex
    
    ImageTransform /P=(fromIndex) getPlane, M_PlaneFromThisWave1
    wave M_ImagePlane
    ImageTransform /D=M_ImagePlane /P=(2 * fromIndex) setPlane, M_PlaneToThisWave
    
    ImageTransform /P=(fromIndex) getPlane, M_PlaneFromThisWave2
    wave M_ImagePlane
    ImageTransform /D=M_ImagePlane /P=(2 * fromIndex + 1) setPlane, M_PlaneToThisWave
End


Result on my laptop:
Original: 2.5658. Now: 0.0528195


About 50 times faster.
I decided to see how wave assignments compared:

Function test()

	Make /O /N=(500,500, 100) a = 0
	Make /O /N=(500, 500, 100) b = 1
 
	Make /O /N=(500, 500, 200) MergeWave

	Variable timerref
	timerref = StartMSTimer
	Multithread MergeWave[][][0,;2] = a[p][q][r/2]
	Multithread MergeWave[][][1,;2] = b[p][q][floor(r/2)]
	Variable microSeconds = stopMSTimer(timerref)
	Print microSeconds/1000, "ms passed."
end

On my 8-core Mac Pro:
959.949 ms passed.
Running 741's version:
Original: 3.95354. Now: 0.0563738

So ImageTransform wins, hands down.

Some comments on your code...
a[x][y][i*2]

On the right side of a wave assignment, square brackets refer to point numbers (rows, columns, etc.) but x and y refer to the *scaled* values from the left side. Your code works because you didn't set wave scaling on your waves, so the scaled and unscaled values are the same. The code will fail if you ever feed it a wave with scaling.

a[x][y][i*2]

b[x][y][i*2+1]


I think you want just [i] in both cases, and run the loop for 100 iterations:
	for (i=0; i<100; i+=1)


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com