!******************************************************************************!
! Illustrates the nyquist theorem using both an adequately and undersampled waveform
!
! @author:  Jeanette McCall
!******************************************************************************!
startmacro
  switch CLEAN  clean  GET DEF=FALSE SDEF=TRUE

  if CLEAN then
    res quals "{AUX=RAM}"
  else
    res quals ""
  endif

  call adjustColors

  res initTime "2018:01:02::08:00:00"
  new nxm.sys.lib.Time(^initTime) starttime

  res sig_1 "cos2hz.tmp^quals"
  res sig_2 "cos2p5hz.tmp^quals"
  res sig_3 "cos3hz.tmp^quals"
  res signal "signal_nyquist.tmp^quals"
  res fft_signal "fft_signal_nyquist.tmp^quals"
  res aliased_sig "aliased_signal.tmp^quals"
  res fft_aliased_sig "fft_aliased_signal.tmp^quals"
  res ok_signal "newrate_demo_ok_sig.tmp"
  res fft_ok_signal "newrate_demo_fft_ok_sig.tmp"
  res freq_1 4
  res freq_2 2.5
  res freq_3 2
  res elem 400
  res delta_orig 0.01
  !(elem*delta) = time_elapsed, time_elapsed * freq = num_cycles

  call setLayerInfo

  call formSignal
  call setSamplingFreqs
  call sigNEWRATE
  call setInstructions

  pipe on

    panel/msgid=MAIN/setup/controls=gc/THEME={^slide}
    gcontrol label macro "DSP Demo NEWRATE and Nyquist"
    gcontrol menu  main "Click EXIT to close =" "EXIT" TABLE={ItemColors={EXIT="YELLOW"}} /tleft
    gcontrol text  instrText "NEWRATE: arbitrary resampling of a signal" instructions 24 20 /title  
    GCONTROL dval  freq1  "Main Frequency"      P1=freq_1 P2=0.5 P3=10 P4=0.5
    GCONTROL dval  freq2  "Secondary Frequency" P1=freq_2 P2=0.5 P3=10 P4=0.5
    GCONTROL dval  freq3  "Tertiary Frequency"  P1=freq_3 P2=0.5 P3=10 P4=0.5
    plot/id=sigparts sig_1^{sig_1_layer}|sig_2^{sig_2_layer}|sig_3^{sig_3_layer}
    plot/id=fullsignal signal^{signal_layer}
    plot/id=sigasig signal^{signal_layer}|aliased_sig^{aliased_sig_layer}
    plot/id=sig_ok_sig signal^{signal_layer}|ok_signal^{ok_sig_layer}
    plot/id=fftsig fft_signal^{fft_signal_layer} x1=0 x2=5
    plot/id=fftasig fft_aliased_sig^{fft_aliased_sig_layer} x1=0 x2=5
    plot/id=fft_ok_sig fft_ok_signal^{fft_ok_sig_layer} x1=0 x2=5

  pipe off

  call eraseFiles

endmacro

!******************************************************************************!
! Main process message for this macro. Should be right after the ENDMACRO.
procedure processMessage m:msg
  if msg.name eqs "MAIN" then
    pipe stop
  elseif msg.name eqss "FREQ" then
    if msg.name eqs "FREQ1" then
      res freq_1 msg.data
    elseif msg.name eqs "FREQ2" then
      res freq_2 msg.data
    elseif msg.name eqs "FREQ3" then
      res freq_3 msg.data
    endif
    call formSignal
    call setSamplingFreqs
    call sigNEWRATE
    call updatePlots
    call setInstructions
    res gc.instrText.value instructions
  endif

!******************************************************************************!
! sets up color scheme based on current theme
procedure adjustColors

  if env.theme EQSS GEAR THEN
    res slide "CBG=midnightblue,CGF=GREEN,CWTS=midnightblue,CWFH=GREEN,CWFH=YELLOW,CWFG=white,CWTITLE=RED,CWBS=midnightblue,CBGX=green,CWMS=midnightblue,CWBG=BLUE}"
    res thick 4
    res c_green green
    res c_blue  blue
    res c_yel_or yellow
    res c_pnk_mar pink
  else
    res slide "CBG=midnightblue,CGF=GREEN,CWTS=midnightblue,CWFH=GREEN,CWFH=YELLOW,CWFG=white,CWTITLE=RED,CWBS=midnightblue,CBGX=green,CWMS=midnightblue,CWBG=BLUE}"
    res thick 4
    res c_green olive
    res c_blue  navy
    res c_yel_or darkorange
    res c_pnk_mar maroon
  endif

return
!********************************************
procedure formSignal
  waveform sig_1 FORM=SF ELEM=^elem SHAPE=cos AMP=1 FREQ=freq_1 delta=delta_orig
  waveform sig_2 FORM=SF ELEM=^elem SHAPE=cos AMP=0.5 PHASE=0.125 FREQ=freq_2 delta=delta_orig
  waveform sig_3 FORM=SF ELEM=^elem SHAPE=cos AMP=0.3 PHASE=0.25 FREQ=freq_3 delta=delta_orig
  fcalc signal sig_1 sig_2 +
  fcalc signal signal sig_3 +
return
!***********************************************
procedure setLayerInfo
    res sig_1_layer           {LAYER={COLOR=^c_green,LINE={THICKNESS=^thick}}}
    res sig_2_layer           {LAYER={COLOR=^c_pnk_mar,LINE={THICKNESS=^thick}}}
    res sig_3_layer           {LAYER={COLOR=^c_yel_or,LINE={THICKNESS=^thick}}}
    res signal_layer          {LAYER={COLOR=^c_blue,LINE={THICKNESS=^thick}}}
    res aliased_sig_layer     {LAYER={TYPE="SYMBOL",SYMBOL="DIAMOND",SYMBOLFILL="YES",SYMBOLSIZE=9,COLOR=lightgreen}}
    res ok_sig_layer          {LAYER={TYPE="SYMBOL",SYMBOL="DIAMOND",SYMBOLFILL="YES",SYMBOLSIZE=9,COLOR=aqua}}
    res fft_signal_layer      {LAYER={COLOR=RED,LINE={THICKNESS=^thick}}}
    res fft_aliased_sig_layer {LAYER={COLOR=RED,LINE={THICKNESS=^thick}}}
    res fft_ok_sig_layer      {LAYER={COLOR=RED,LINE={THICKNESS=^thick}}}
return
!**********************************************
procedure setSamplingFreqs
  res maxFreq freq_1
  if freq_2 GT maxFreq then
    res maxFreq freq_2
  endif
  if freq_3 GT maxFreq then
    res maxFreq freq_3
  endif
  calc underSampleFreq maxFreq 1 +
  calc goodSampleFreq maxFreq 3 *
return
!***************************************
procedure sigNEWRATE
  ! sampling at 5 hz
  calc delta_ratio delta_orig 0.2 /
  calc elema elem delta_ratio *
  newrate in=signal out=aliased_sig underSampleFreq

  ! sampling at 10 hz
  calc delta_ratio delta_orig 0.1 /
  calc elemok elem delta_ratio *
  newrate in=signal out=ok_signal goodSampleFreq

  fft IN1=signal out1=fft_signal
  fft IN1=aliased_sig out1=fft_aliased_sig
  fft IN1=ok_signal out1=fft_ok_signal
return
!*******************************************
procedure updatePlots
  message send sigparts name=openfile info=-1 data="sig_1^{sig_1_layer}|sig_2^{sig_2_layer}|sig_3^{sig_3_layer}"
  message send fullsignal name=openfile info=-1 data="signal^{signal_layer}"
  message send sigasig name=openfile info=-1 data="signal^{signal_layer}|aliased_sig^{aliased_sig_layer}"
  message send sig_ok_sig name=openfile info=-1 data="signal^{signal_layer}|ok_signal^{ok_sig_layer}"
  message send fftsig name=openfile info=-1 data="fft_signal^{fft_signal_layer}" quals={X1=0,X2=^maxFreq}
  message send fftasig name=openfile info=-1 data="fft_aliased_sig^{fft_aliased_sig_layer}" quals={X1=0,X2=^maxFreq}
  message send fft_ok_sig name=openfile info=-1 data="fft_ok_signal^{fft_ok_sig_layer}" quals={X1=0,X2=^maxFreq}
return
!************************************************
procedure setInstructions
  res instructions "Our DSP option tree has numerous DSP commands, &
                    including NEWRATE, various FIR filters, TUNER, &
                    SIGSTATISTICS, PEAKPICK, CONVOLVE, and CORRELATE.\n\n&
                    Here we use NEWRATE to illustrate the Nyquist Sampling Theorem:\n&
                    To be properly sampled, a signal must be sampled over twice as &
                    fast as its highest frequency component.\n\n&
                    row 1: ^{freq_1}, ^{freq_2}, & ^{freq_3}hz components\n\n&
                    row 2: combined signal\n\n&
                    row 3: under sampled at ^{underSampleFreq}hz\n    &
                           ^{maxFreq}hz shows up as 1hz (folding \n    &
                           over the sampling frequency)\n\n&
                    row 4: adequately sampled"
return
!**************************************************
procedure eraseFiles
  erase sig_1 sig_2 sig_3 signal
  erase fft_signal aliased_sig fft_aliased_sig
  erase ok_signal fft_ok_signal
return