// file: $isip/class/algo/Filter/filt_06.cc
// version: $Id: filt_06.cc 8388 2002-07-16 02:00:31Z gao $
//

// isip include files
//
#include "Filter.h"

// method: setMACoeffs
// 
// arguments: 
//  float val: (input) ma coefficients
//  long lag: (input) ma lag
//
// return: a boolean value indicating status
//
// a method that adds a moving average coefficient and its
// corresponding lag to the existing vector of moving average
// coefficients and the corresponding vector of lags
//
boolean Filter::setMACoeffs(float val_a, long lag_a) {

  long index = ma_coef_d.length();
  
  // set the length of ma coefficients
  //
  ma_coef_d.setLength(index + 1);
  
  // set the length of ma lag
  //
  ma_lag_d.setLength(index + 1);

  // assign the value
  //
  ma_coef_d(index) = val_a;
  ma_lag_d(index) = lag_a;

  // unset the boolean flag
  //
  is_valid_d = false;
  
  // exit gracefully
  //
  return true;
}

// method: setMACoeffs
// 
// arguments: 
//  const VectorFloat& ma_coef: (input) moving average coefficients
//
// return: a boolean value indicating status
//
// a method that sets a vector moving average coefficients and assumes
// their corresponding lags to be a ramp
//
boolean Filter::setMACoeffs(const VectorFloat& ma_coef_a) {
  
  // initialize moving average lags
  //
  VectorLong ma_lag;

  // set the length of ma lag
  //
  ma_lag.setLength(ma_coef_a.length());

  // assume ma lag to be ramp
  //
  ma_lag.ramp((long)0, (long)-1);
  
  // assign the values
  //
  ma_coef_d.assign(ma_coef_a);
  ma_lag_d.assign(ma_lag);

  // unset the boolean flag
  //
  is_valid_d = false;
  
  // exit gracefully
  //
  return true;
}

// method: setMACoeffs
// 
// arguments: 
//  const VectorFloat& ma_coef: (input) moving average coefficients
//  const VectorLong& ma_lag: (input) moving average lags
//
// return: a boolean value indicating status
//
// a method that set a vector of moving average coefficients and their
// corresponding vector of lags
//
boolean Filter::setMACoeffs(const VectorFloat& ma_coef_a, 
			    const VectorLong& ma_lag_a) {

  // assign the values
  //
  ma_coef_d.assign(ma_coef_a);
  ma_lag_d.assign(ma_lag_a);

  // unset the boolean flag
  //
  is_valid_d = false;
    
  // exit gracefully
  //
  return true;
}

// method: setARCoeffs
// 
// arguments: 
//  float val: (input) ar coefficients
//  long lag: (input) ar lag
//
// return: a boolean value indicating status
//
// a method that adds a auto regressive coefficient and its
// corresponding lag to the existing vector of auto regressive
// coefficients and the corresponding vector of lags
//
boolean Filter::setARCoeffs(float val_a, long lag_a) {

  long index = ar_coef_d.length();
  
  // set the length of ar coefficients
  //
  ar_coef_d.setLength(index + 1);
  
  // set the length of ar lag
  //
  ar_lag_d.setLength(index + 1);

  // assign the values
  //
  ar_coef_d(index) = val_a;
  ar_lag_d(index) = lag_a;

  // unset the boolean flag
  //
  is_valid_d = false;
  
  // exit gracefully
  //
  return true;
}

// method: setARCoeffs
// 
// arguments: 
//  const VectorFloat& ar_coef: (input) moving average coefficients
//
// return: a boolean value indicating status
//
// a method that sets a vector auto regressive coefficients and
// assumes their corresponding lags to be a ramp
//
boolean Filter::setARCoeffs(const VectorFloat& ar_coef_a) {

  // create a lag vector
  //
  VectorLong ar_lag;
  if (!ar_lag.setLength(ar_coef_a.length())) {
    return false;
  }

  // assume ramp lag, ar lag cannot be <= 0
  //
  if (!ar_lag.ramp((long)-1, (long)-1)) {
    return false;
  }

  // assign lag and coefficients
  //
  ar_lag_d.assign(ar_lag);
  ar_coef_d.assign(ar_coef_a);

  // unset the boolean flag
  //
  is_valid_d = false;
    
  // exit gracefully
  //
  return true;
}

// method: setARCoeffs
// 
// arguments: 
//  const VectorFloat& ar_coef: (input) moving average coefficients
//  const VectorLong& ar_lag: (input) moving average lags
//
// return: a boolean value indicating status
//
// a method that sets a vector auto regressive coefficients and a
// their corresponding lags to be a ramp
//
boolean Filter::setARCoeffs(const VectorFloat& ar_coef_a, 
			    const VectorLong& ar_lag_a) {
  
  // assign lag and coefficients
  //
  ar_lag_d.assign(ar_lag_a);
  ar_coef_d.assign(ar_coef_a);

  // unset the boolean flag
  //
  is_valid_d = false;
    
  // exit gracefully
  //
  return true;
}

// method: setCoeffs
// 
// arguments: 
//  const VectorFloat& ma_coef: (input) moving average coefficients
//  const VectorFloat& ar_coef: (input) autoregressive coefficients
//
// return: a boolean value indicating status
//
// this method sets up the moving average and auto regressive
// coefficients and assumes the corresponding lags to be ramps
//
boolean Filter::setCoeffs(const VectorFloat& ma_coef_a, 
			  const VectorFloat& ar_coef_a) {
  
  // create a lag vector
  //
  VectorLong ma_lag(ma_coef_a.length());
  
  if (!ma_lag.ramp((long)0, (long)-1)) {
    return false;
  }

  // ar lag cannot be <= 0
  //
  VectorLong ar_lag(ar_coef_a.length());
  if (!ar_lag.ramp((long)-1, (long)-1)) {
    return false;
  }
 
  // unset the boolean flag
  //
  is_valid_d = false;
   
  // create a filter
  //
  return setCoeffs(ma_coef_a, ma_lag, ar_coef_a, ar_lag);
  
}

// method: setCoeffs
// 
// arguments: 
//  const VectorFloat& ma_coef: (input) moving average coefficients
//  const VectorLong& ma_lag: (input) moving average lags
//  const VectorFloat& ar_coef: (input) autoregressive coefficients
//  const VectorLong& ar_lag: (input) autoregressive lags
//
// return: a boolean value indicating status
//
// this method sets up the moving average coefficients and the auto
// regressive coefficients and their corresponding lags
//
boolean Filter::setCoeffs(const VectorFloat& ma_coef_a,
			  const VectorLong& ma_lag_a,
			  const VectorFloat& ar_coef_a,
			  const VectorLong& ar_lag_a) {
  
  // check arguments
  //
  if ((ma_coef_a.length() != ma_lag_a.length()) ||
      (ar_coef_a.length() != ar_lag_a.length())) {
    return Error::handle(name(), L"setCoeffs", Error::ARG, __FILE__, __LINE__);
  }
  
  // set moving average coefficients
  //
  ma_coef_d.assign(ma_coef_a);
  ma_lag_d.assign(ma_lag_a);
    
  // set autoregressive coefficients
  //
  ar_coef_d.assign(ar_coef_a);
  ar_lag_d.assign(ar_lag_a);

  // unset the boolean flag
  //
  is_valid_d = false;
    
  // exit gracefully
  //
  return true;
}

// method: getLeadingPad
// 
// arguments: none
//
// return: the number of future frames needed if the filter is anti-causal
//
long Filter::getLeadingPad() const {
  
  // for FRAME_INTERNAL mode, no future frames needed
  //
  if (cmode_d == FRAME_INTERNAL) {
    return long(0);
  }
  
  // compute the number of samples per frame
  //
  double frame_num_samp = frame_dur_d * sample_freq_d;
  
  // return the number of frames needed to cover the lag
  //
  return (long)Integral::ceil((double)getLeadingNumSamp() / frame_num_samp);
}

// method: getTrailingPad
// 
// arguments: none
//
// return: the number of past frames needed
//
long Filter::getTrailingPad() const {
  
  // past frames are already stored in the buffer
  //
  return long(0);

}

// method: getLeadingNumSamp
// 
// arguments: none
//
// return: the number of advance (future) samples
//
long Filter::getLeadingNumSamp() const {
  
  if (cmode_d == FRAME_INTERNAL) {
    return (long)0;
  }

  // find the maximum lag in future for anti-causal filter
  //
  Long max_lag;
  max_lag = ma_lag_d.max();
  
  // return zero samples from future if the filter is causal
  //
  if (max_lag < (long)0) {
    max_lag = 0;
  }
  
  // return the lag
  //
  return (long)max_lag;
}

// method: getTrailingNumSamp
// 
// arguments: none
//
// return: the number of past samples
//
long Filter::getTrailingNumSamp() const {
  
  // find the maximum lag
  //
  Long max_lag;
  Long max_ma_lag = ma_lag_d.min();
  Long max_ar_lag = ar_lag_d.min();
  max_lag = max_ma_lag.min(max_ar_lag);
  max_lag = abs(max_lag);
  
  // return the lag
  //
  return (long)max_lag;
}
