I'm diving into "modern CPP", with wide usage of templates and containers, So I started with FIR filter.
In signal processing, a finite impulse response (FIR) filter is a filter whose impulse response (or response to any finite length input) is of finite duration, because it settles to zero in finite time. This is in contrast to infinite impulse response (IIR) filters, which may have internal feedback and may continue to respond indefinitely (usually decaying).
So I define FIR filter as a class and apply it to single scalar value or to the vector itself
Could you please review my code in terms of C++ coding?
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <complex>
#include <cmath>
#include <iomanip>
#include <sstream>
// - Class method : operator(), constructor, various methods
// - Templates class and function
// - List and vector containers
// - Functors
template <typename T> std::string to_str(T & arr){
std::ostringstream os;
os << "["; for (auto x: arr){ os<<" "<< x <<" "; } os << "]\n";
return os.str();
}
template <class T> class FIR {
public:
std::vector< T > coeff; // Array of coefficents is static all the time
std::list< T > taps; // Array of is are shifting each tick
int order;
FIR(std::vector< T > v)
{
coeff = v;
order = coeff.size();
taps = std::list< T > (coeff.size(), 0);
}
void reset(){
taps = std::list< T > (coeff.size(), 0);
}
void append( T x){
taps.push_front( x);
taps.pop_back();
}
auto sum_product(){
T psum = 0;
typename std::list< T >::iterator t;
typename std::vector< T >::iterator c;
// Can we do better here?
for ( c =coeff.begin(), t =taps.begin();
c!=coeff.end(), t !=taps.end();
++c , ++t ){
psum += (*c) * (*t);
}
return psum;
}
auto operator() ( T x){
append(x);
T psum = sum_product();
return psum;
}
auto operator() (std::vector< T > x){
std::vector< T > y( x.size(), 0);
for (int i = 0; i<x.size(); ++i){
y[i] = operator()(x[i]);
}
return y;
}
};
int main()
{
std::vector<double> coeff = {0.0,1.0,5.0, 1.0, 0.0};
FIR<double> fir(coeff);
std::cout <<"Coeff: " << to_str(fir.coeff);
std::cout <<"Taps : " << to_str(fir.taps);
std::cout<<"\nTRANSFORM IN THE LOOP \n";
std::vector<double> x_array = {0,1,2,3,4,5,6,0,0,0,0,0,0,13};
for (auto x:x_array){
auto p = fir(x);
std::cout<<p<<" ";
}
std::cout<<"\n";
fir.reset();
std::cout<<"\nTRANSFORM WITH FUNCTOR FOR SCALAR\n";
std::vector<double> y_array( x_array.size(), 0);
std::transform(x_array.begin(), x_array.end(), y_array.begin(), fir);
std::cout << to_str(y_array);
fir.reset();
std::cout<<"\nAPPLY FUNCTOR FOR CONTTAINER \n";
auto y_2 = fir(x_array);
std::cout << to_str(y_2);
fir.reset();
return 0;
}