!******************************************************************************!
! This tests the functionality of fastcorrelate.
!
! @author  Scott Fernandez / Neon Ngo
! @version $Id: test_fastcorrelate.mm,v 1.5 2011/12/20 16:35:26 ntn Exp $
! @since   NeXtMidas 3.1.0
!******************************************************************************!
startmacro s:func[""]
  switch KEEP      keep      GET DEF=FALSE SDEF=TRUE  ! to keep generated / output files
  switch TOLERANCE tol       GET DEF=1e-6
  switch SHORTFILE shortfile GET DEF="ram:const_filter"

  ! create small constant short file (FIR / filter impulse response input file)
  WAVEFORM shortfile FORM=SF ELEM=1 SHAPE=CONSTANT AMP=1

  if func NEQS "" and func NEQS "ALL" then
    call test_^{func}
    stop
  endif

  call test_basic temp_fastcorrelate_sinsf SF temp_fastcorrelate_out1
  call test_basic temp_fastcorrelate_sincf CF temp_fastcorrelate_out2
  ! NTN: FASTCORRELATE currently DOES NOT allow SD and CD inputs (matches X-Midas FASTCORL)
  ! call test_basic temp_fastcorrelate_sinsd SD temp_fastcorrelate_out3
  ! call test_basic temp_fastcorrelate_sincd CD temp_fastcorrelate_out4

  call test_advanced
  call test_fastcorl

  ! placeholder--transfer length not yet implemented
  !call test_xferLength

  ! cleanup
  if keep isFalse then
    erase shortfile
  endif
endmacro

!******************************************************************************!
! Process unhandled exceptions
procedure processException m:emsg
  assert/text="^reg.main.name: Unexpected exception: ^{emsg} data=^{emsg.data}" false
  invoke ,, emsg.data.printStacktrace()
return

!******************************************************************************!
! Basic test
procedure test_basic S:INFILE["ram:temp_sin1"] S:FORMAT["SD"] S:OUTFILE["ram:temp_out1"]
  CALCULATOR/QUIET inFileLen RANDOM 50k * FLOOR 4k +
  WAVEFORM INFILE FORMAT ELEM=inFileLen SHAPE=SIN AMP=1 FREQ=.01

  fastcorrelate INFILE shortfile OUTFILE
  COMPARE INFILE OUTFILE MAX_OUT=temp_max MIN_OUT=temp_min

  assert/text="^reg.main.name: ^format - Compare output to known values" temp_max < tol and temp_min < tol

  ! cleanup
  remove temp_max temp_min inpLength
  if keep isFalse then
    erase INFILE OUTFILE
  endif
return

!******************************************************************************!
! Advanced tests
procedure test_advanced
  set expected1 "nxm.dsp.test.test_correlate_expected1.prm"
  set expected2 "nxm.dsp.test.test_correlate_expected2.prm"
  WAVEFORM OUT="ram:temp_in"    FORM=SF ELEM=25 SHAPE=CONSTANT AMP=0
  WAVEFORM OUT="ram:temp_merge" FORM=SF ELEM=15 SHAPE=CONSTANT AMP=10
  MERGEFILE IN="ram:temp_in" OUT="ram:temp_merge"

  fastcorrelate/pad ram:temp_merge ram:temp_merge temp_fastcor_aout1
  COMPARE IN1=expected1 IN2=temp_fastcor_aout1 MAX_OUT=temp_max MIN_OUT=temp_min  RESULT=same
  assert/text="^reg.main.name: Advanced comparing output to known values" temp_max <= 1E-3 and temp_min >= -1E-3

  fastcorrelate/pad temp_fastcor_aout1 temp_fastcor_aout1 temp_fastcor_aout2
  COMPARE IN1=expected2 IN2=temp_fastcor_aout2 MAX_OUT=temp_max MIN_OUT=temp_min RESULT=same
  assert/text="^reg.main.name: Advanced comparing output to known values" temp_max <= 10 and temp_min >= -10

  ! cleanup
  remove temp_max temp_min
  if keep isFalse then
    erase temp_fastcor_aout1 temp_fastcor_aout2
  endif
return

!******************************************************************************!
! Test transfer length (NOTE: /TL NOT IMPLEMENTED YET for FASTCOR)
procedure test_xferLength
  ! Randomize impulse and input sizes, make sure at least 1
  CALCULATOR/QUIET impulseLen RANDOM 401 * FLOOR 1 +
  CALCULATOR/QUIET inFileLen  RANDOM 2k * FLOOR 1 +
  WAVEFORM OUT=imp FORM=SF ELEM=impulseLen SHAPE=CONSTANT AMP=10
  WAVEFORM OUT=in  FORM=SF ELEM=inFileLen  SHAPE=SIN AMP=5

  ! Compare tl=inpLength and tl=impLength
  fastcorrelate in imp out1 /tl=impulseLen
  fastcorrelate in imp out2 /tl=inFileLen
  COMPARE IN1=out1 IN2=out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: xfer len - Comparing output with tl at input sizes" same eq 1

  ! Compare probably tl < impulseLen

  ! 1 + floor( (impulseLen-1)*random ), less than or equal to impLength
  CALCULATOR/QUIET rand 1 impulseLen 1 - RANDOM * FLOOR +
  fastcorrelate in imp out2 /tl=rand
  COMPARE IN1=out1 IN2=out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: xfer len - Comparing to output with small transfer length" same eq 1

  ! Compare probably impulseLen < tl < inFileLen

  ! floor( |inFileLen-impulseLen|*random) ) + impulseLen, greater than or
  ! equal to impulseLen, probably less than inFileLen, probably in between
  CALCULATOR/QUIET rand impulseLen inFileLen impulseLen - ABS RANDOM * FLOOR +
  fastcorrelate in imp out2 /tl=rand
  COMPARE IN1=out1 IN2=out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: xfer len - Comparing to output with transfer length in between" same eq 1

  ! Compare tl = inpLength + ceil(1M*random) > inpLength
  CALCULATOR/QUIET rand inpLength 1M RANDOM * CEIL +
  fastcorrelate in imp out2 /tl=rand
  COMPARE IN1=out1 IN2=out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: xfer len - Comparing to output with very large transfer length" same eq 1

  if keep isFalse then
    erase in imp out1 out2
  endif
return


!******************************************************************************!
! test case similar to X-Midas's test_fastcorl.txt
procedure test_fastcorl S:format["SF"]
  set delta 160E-9
  set start 2.007

  ! create test (long) input file
  waveform temp_fastcor_cos.tmp format ELEM=131072 SHAPE=COS FREQ=1.5E6 START=start DELTA=delta

  ! create an (short) impulse input file with 1 at t=0, followed by (16k - 1) zeros
  waveform temp_fastcor_impulse.tmp "SF" ELEM=16384 SHAPE=CONSTANT AMP=0 DELTA=delta
  set FILE(temp_fastcor_impulse.tmp).data(0) 1.0

  ! correlate the impulse with the input file.
  fastcor temp_fastcor_cos.tmp temp_fastcor_impulse.tmp temp_fastcor_out.tmp /verbose

  ! verify output file's headers
  status temp_fastcor_out.tmp xs=xstart xd=xdelta size=size form=form
  assert/text="^reg.main.name: xstart (^xstart) of fastcor output" xstart eq start
  assert/text="^reg.main.name: xdelta (^xdelta) of fastcor output" xdelta eq delta
  assert/text="^reg.main.name: size (^size) of fastcor output"     size   eq 114689
  assert/text="^reg.main.name: format (^form)  of fastcor output"  form   eqs format

  ! subtract the input file from the output and run statistics on the difference
  fcalc temp_fastcor_diff.tmp temp_fastcor_cos.tmp temp_fastcor_out.tmp -
  statistics temp_fastcor_diff.tmp table=stats

  ! make sure max/min of difference are within tolerance
  assert/text="^reg.main.name: compare diff between IN and fastcor OUT - min (^stats.min)" stats.min le/m tol
  assert/text="^reg.main.name: compare diff between IN and fastcor OUT - max (^stats.max)" stats.max le/m tol

  ! cleanup
  if keep isFalse then
    erase temp_fastcor_cos.tmp temp_fastcor_impulse.tmp temp_fastcor_out.tmp temp_fastcor_diff.tmp
  endif
return

