code: def multiply_frequencies(signal, fs, frange, calibration_frequencies, attendB):
      
      npts = len(signal)
      padto = 1 << (npts - 1).bit_length()
  
      X = np.fft.rfft(signal, n=padto)
  
      npts = padto
      f = np.arange((npts / 2) + 1) / (npts / fs)
  
      fidx_low = (np.abs(f - frange[0])).argmin()
      fidx_high = (np.abs(f - frange[1])).argmin()
  
      cal_func = interp1d(calibration_frequencies, attendB)
      roi = f[fidx_low:fidx_high]
      Hroi = cal_func(roi)
      H = np.zeros((len(X),))
      H[fidx_low:fidx_high] = Hroi
  
      H = smooth(H)
      # print 'H dB max', np.amax(H)
  
      H = 10 ** ((H).astype(float) / 20)
      # print 'H amp max', np.amax(H)
  
      # Xadjusted = X.copy()
      # Xadjusted[fidx_low:fidx_high] *= H
      # Xadjusted = smooth(Xadjusted)
  
      Xadjusted = X * H
      # print 'X max', np.amax(abs(X))
      # print 'Xadjusted max', np.amax(abs(Xadjusted))
  
      signal_calibrated = np.fft.irfft(Xadjusted)
      return signal_calibrated[:len(signal)]
docs: Given a vector of dB attenuations, adjust signal by 
         multiplication in the frequency domain