;+
; NAME:
;   rbsp_dfb_response (function)
;
; PURPOSE:
;   Calculate DFB responses at given frequencies. Two modes are suppored. If the
;   sample rate keyword, SAMPLE_RATE, is specified, it will calculate the
;   response of the low-pass output from DFB. If the the filter bank level
;   keyword, FBK_LEVEL, is specified, it will calculate the response of the
;   corresponding filter bank level. 
;
;   Warning: If both keywords are set, FBK_LEVEL is ignored. If neither is set,
;            a NaN will be returned.
;
;   Filter bank level look-up table:
;       Frequency range in Hz  |  Level
;           8192 - 4096        |    1
;           4096 - 2048        |    2
;           2048 - 1024        |    3
;           1024 -  512        |    4
;            512 -  256        |    5
;            256 -  128        |    6
;            128 -   64        |    7
;             64 -   32        |    8
;             32 -   16        |    9
;             16 -    8        |    10
;              8 -    4        |    11
;              4 -    2        |    12
;              2 -    1        |    13
;
; CATEGORIES:
;
; CALLING SEQUENCE:
;   result = rbsp_dfb_response(f, sample_rate = sample_rate, $
;                        fbk_level = fbk_level)
;
; ARGUMENTS:
;   f: (Input, required) A floating array of frequencies at which the responses
;           are calculated.
;
; KEYWORDS:
;   sample_rate: (Input, optional) See PURPOSE.
;   fbk_level: (Input, optional) See PURPOSE.
;
; COMMON BLOCKS:
;
; EXAMPLES:
;
; SEE ALSO:
;
; HISTORY:
;   2012-08-08: Created by Jianbao Tao (JBT), SSL, UC Berkley.
;
;
; Version:
;
; $LastChangedBy: aaronbreneman $
; $LastChangedDate: 2020-04-29 11:12:21 -0700 (Wed, 29 Apr 2020) $
; $LastChangedRevision: 28641 $
; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/trunk/general/missions/rbsp/efw/calibration_files/rbsp_dfb_response.pro $
;-


; rbsp_DFB_FIR_transfer uses Cully's code wrote for THEMIS.
function rbsp_DFB_FIR_transfer,omega, noavg = noavg
  compile_opt idl2, hidden

  ; Calculate transfer function of filter 1
  ; with coefficients [-8,0,72,128,72,0,-8]/256
  I = dcomplex(0,1)
  h = (-8)  + $
        72*(cos(2*omega)-I*sin(2*omega)) + $
       128*(cos(3*omega)-I*sin(3*omega)) + $
        72*(cos(4*omega)-I*sin(4*omega)) + $
      (-8)*(cos(6*omega)-I*sin(6*omega))
  h/=256.

  ; Multiply by transfer function of filter 2
  ; with coefficients [1/4, 1/2, 1/4]
  if ~keyword_set(noavg) then begin
      h *= 0.25 + $
            0.5*(cos(  omega)-I*sin( omega)) + $
           0.25*(cos(2*omega)-I*sin(2*omega))
   endif
return,h
end

;------------------------------------------------
; Calculates the transfer function for the DFB filters at a given level
;   Inputs: frequency normalized to sampling Nyquist frequency
;              (i.e. f/4096 or f/8192)
;           filter bank level
;   Output: complex transfer function at given frequencies
;------------------------------------------------
; rbsp_DFB_transfer uses Cully's code wrote for THEMIS.
function rbsp_DFB_transfer,f,level, fbk = fbk
; If fbk set, return filter bank response instead of low-pass filtered signals.
  compile_opt idl2, hidden

  ; Use normalized angular frequency
  omega = f*!dpi
  i_cmplx = dcomplex(0, 1)

  if level eq 0 then return, dcomplexarr(n_elements(f)) + dcomplex(1,0)

  ; For level 1, transfer function is just FIR transfer function
  if level eq 1 and keyword_set(fbk) then begin
    h = exp(-3d*i_cmplx*omega) - rbsp_DFB_FIR_transfer(omega, /noavg)
    return, h
  endif 

  h = rbsp_DFB_FIR_transfer(omega)

  ; For higher levels, multiply by all transfer functions,
  ; making sure to appropiately fold in aliasing
  if ~keyword_set(fbk) then begin
    for i=1,level-1 do h*= rbsp_DFB_FIR_transfer(omega*2^i)
  endif else begin
    for i=1,level-2 do h*= rbsp_DFB_FIR_transfer(omega*2^i)
    h *= exp(-3d*i_cmplx*omega*2^(level-1)) - $
          rbsp_DFB_FIR_transfer(omega*2^(level-1), /noavg)
  endelse

return,h
end

;-------------------------------------------------------------------------------
function rbsp_dfb_response, f, sample_rate = sample_rate, fbk_level = fbk_level
compile_opt idl2

adc_srate = 16384d  ; RBSP ADC sample rate
nyquist = adc_srate * 0.5  ; Highest nyquist from RBSP ADC

if keyword_set(sample_rate) then begin
  print, 'sample rate = ', sample_rate
  level = fix(alog(adc_srate/sample_rate)/alog(2) + 0.4)

  if level lt 0 then begin
    dprint, 'Invalid sample rate. A NaN is returned.'
    return, !values.f_nan
  endif

  resp = rbsp_dfb_transfer(f/nyquist, level)
  return, resp
endif

if keyword_set(fbk_level) then begin
  level = fbk_level
  if level lt 0 then begin
    dprint, 'Invalid filter bank level. A NaN is returned.'
    return, !values.f_nan
  endif

  resp = rbsp_dfb_transfer(f/nyquist, level, /fbk)
  return, resp
endif

dprint, 'Neither sample rate nor FBK level is supplied. A NaN is returned.'
return, !values.f_nan

end

