Skip to content

Commit 4d9423a

Browse files
authored
make FftFilter as template class (#95)
1 parent 2527bde commit 4d9423a

File tree

7 files changed

+115
-72
lines changed

7 files changed

+115
-72
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ set(DSPLIB_SOURCES
2424
lib/detector.cpp
2525
lib/findpeaks.cpp
2626
lib/fir.cpp
27+
lib/fft-filter.cpp
2728
lib/gccphat.cpp
2829
lib/hilbert.cpp
2930
lib/math.cpp

include/dsplib/agc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace dsplib {
88
struct AgcImpl;
99

1010
//Adaptively adjust gain for constant signal level output
11+
//TODO: make as template
1112
class Agc
1213
{
1314
public:

include/dsplib/detector.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class PreambleDetectorImpl;
1717
// corr = filter(conj(h) / (nh * rms(h)), 1, x);
1818
// pagg = filter(ones(1, nh) / nh, 1, abs(x).^2);
1919
// res = sqrt((abs(corr) .^ 2) ./ pagg);
20+
//TODO: add real type implementation
2021
class PreambleDetector
2122
{
2223
public:

include/dsplib/fir.h

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
#include <dsplib/array.h>
44
#include <dsplib/keywords.h>
5+
#include <dsplib/math.h>
6+
#include <dsplib/fft.h>
7+
#include <dsplib/ifft.h>
58

69
namespace dsplib {
710

@@ -60,45 +63,37 @@ using FirFilterC = FirFilter<cmplx_t>;
6063
template<typename U>
6164
FirFilter(const base_array<U>&) -> FirFilter<U>;
6265

66+
template<typename T>
67+
class FftFilterImpl;
68+
6369
/*!
6470
* \brief FFT-based FIR filtering using overlap-add method
65-
* \details Fast fir implementation for IR len > 200
66-
* \todo make template (real version is faster)
71+
* \details Fast fir implementation for large IR length (usually > 200)
6772
*/
73+
template<typename T>
6874
class FftFilter
6975
{
7076
public:
71-
FftFilter() = default;
72-
explicit FftFilter(span_real h);
77+
explicit FftFilter(span_t<T> h);
7378

74-
explicit FftFilter(span_cmplx h);
75-
76-
//usually in.size() != out.size()
77-
arr_real process(span_real x);
78-
arr_cmplx process(span_cmplx x);
79-
80-
//optimal input size for y[nx] = process(x[nx])
81-
[[nodiscard]] int block_size() const {
82-
return _n;
83-
}
79+
base_array<T> process(span_t<T> x);
8480

85-
arr_real operator()(span_real x) {
81+
base_array<T> operator()(span_t<T> x) {
8682
return this->process(x);
8783
}
8884

89-
arr_cmplx operator()(span_cmplx x) {
90-
return this->process(x);
91-
}
85+
[[nodiscard]] int block_size() const;
9286

9387
private:
94-
arr_cmplx _x;
95-
arr_cmplx _h;
96-
arr_cmplx _olap;
97-
int _nx{0};
98-
int _m{0};
99-
int _n{0};
88+
std::shared_ptr<FftFilterImpl<T>> d_;
10089
};
10190

91+
using FftFilterR = FftFilter<real_t>;
92+
using FftFilterC = FftFilter<cmplx_t>;
93+
94+
template<typename U>
95+
FftFilter(const base_array<U>&) -> FftFilter<U>;
96+
10297
//Type of linear phase FIR filter
10398
FirType firtype(span_real h);
10499

lib/detector.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class PreambleDetectorImpl
8989

9090
void reset() {
9191
_pow_flt.process(zeros(frame_len()));
92-
_corr_flt.process(zeros(frame_len()));
92+
_corr_flt.process(complex(zeros(frame_len())));
9393
_delay.reset();
9494
}
9595

@@ -98,7 +98,7 @@ class PreambleDetectorImpl
9898
return flip(h) / (rms(h) * h.size());
9999
}
100100

101-
FftFilter _corr_flt;
101+
FftFilterC _corr_flt;
102102
MAFilterR _pow_flt;
103103
real_t _threshold{1.0};
104104
CDelay<cmplx_t> _delay;

lib/fft-filter.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "dsplib/fir.h"
2+
3+
namespace dsplib {
4+
5+
template<typename T>
6+
class FftFilterImpl
7+
{
8+
public:
9+
explicit FftFilterImpl(span_t<T> h)
10+
: _nfft{int(1) << nextpow2(2 * h.size())}
11+
, _m{h.size()}
12+
, _n{_nfft - h.size() + 1}
13+
, _x(_nfft)
14+
, _olap(_m - 1) {
15+
assert(_n > _m);
16+
_h = fft(conj(h), _nfft);
17+
}
18+
19+
base_array<T> process(span_t<T> x) {
20+
const int nr = (x.size() + _nx) / _n * _n;
21+
base_array<T> r(nr);
22+
auto* pr = r.data();
23+
for (const auto& val : x) {
24+
_x[_nx] = val;
25+
_nx += 1;
26+
if (_nx == _n) {
27+
base_array<T> ry;
28+
if constexpr (std::is_same_v<T, real_t>) {
29+
ry = std::move(irfft(fft(_x) * _h)); //TODO: use n/2+1 multiply
30+
} else {
31+
ry = std::move(ifft(fft(_x) * _h));
32+
}
33+
for (int i = 0; i < _n; i++) {
34+
pr[i] = ry[i];
35+
}
36+
for (int i = 0; i < (_m - 1); i++) {
37+
pr[i] += _olap[i];
38+
_olap[i] = ry[i + _n];
39+
}
40+
pr += _n;
41+
_nx = 0;
42+
}
43+
}
44+
return r;
45+
}
46+
47+
[[nodiscard]] int block_size() const {
48+
return _n;
49+
}
50+
51+
private:
52+
int _nx{0};
53+
int _nfft;
54+
int _m{0};
55+
int _n{0};
56+
base_array<T> _x;
57+
arr_cmplx _h;
58+
base_array<T> _olap;
59+
};
60+
61+
template<>
62+
FftFilter<real_t>::FftFilter(span_t<real_t> h) {
63+
d_ = std::make_shared<FftFilterImpl<real_t>>(h);
64+
}
65+
66+
template<>
67+
FftFilter<cmplx_t>::FftFilter(span_t<cmplx_t> h) {
68+
d_ = std::make_shared<FftFilterImpl<cmplx_t>>(h);
69+
}
70+
71+
template<>
72+
base_array<real_t> FftFilter<real_t>::process(span_t<real_t> x) {
73+
return d_->process(x);
74+
}
75+
76+
template<>
77+
base_array<cmplx_t> FftFilter<cmplx_t>::process(span_t<cmplx_t> x) {
78+
return d_->process(x);
79+
}
80+
81+
template<>
82+
int FftFilter<real_t>::block_size() const {
83+
return d_->block_size();
84+
}
85+
86+
template<>
87+
int FftFilter<cmplx_t>::block_size() const {
88+
return d_->block_size();
89+
}
90+
91+
} // namespace dsplib

lib/fir.cpp

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -119,52 +119,6 @@ void FirFilter<cmplx_t>::conv(mut_span_t<cmplx_t> x, span_t<cmplx_t> h) {
119119
_conv(x.data(), h.data(), h.size(), x.size());
120120
}
121121

122-
//-------------------------------------------------------------------------------------------------
123-
FftFilter::FftFilter(span_cmplx h)
124-
: _m{h.size()} {
125-
const int fft_len = 1L << nextpow2(2 * h.size());
126-
_n = fft_len - h.size() + 1;
127-
assert(_n > _m);
128-
_olap = complex(zeros(_m - 1));
129-
_h = fft(conj(h), fft_len);
130-
_x = complex(zeros(fft_len));
131-
}
132-
133-
FftFilter::FftFilter(span_real h)
134-
: FftFilter(complex(h)) {
135-
}
136-
137-
arr_cmplx FftFilter::process(span_cmplx x) {
138-
const int nr = (x.size() + _nx) / _n * _n;
139-
arr_cmplx r(nr);
140-
cmplx_t* pr = r.data();
141-
for (const auto& val : x) {
142-
_x[_nx] = val;
143-
_nx += 1;
144-
if (_nx == _n) {
145-
const auto ry = ifft(fft(_x) * _h);
146-
147-
for (int i = 0; i < _n; i++) {
148-
pr[i] = ry[i];
149-
}
150-
151-
for (int i = 0; i < (_m - 1); i++) {
152-
pr[i] += _olap[i];
153-
_olap[i] = ry[i + _n];
154-
}
155-
156-
pr += _n;
157-
_nx = 0;
158-
}
159-
}
160-
return r;
161-
}
162-
163-
arr_real FftFilter::process(span_real x) {
164-
//TODO: real optimization
165-
return real(process(complex(x)));
166-
}
167-
168122
//----------------------------------------------------------------------------------------------
169123
arr_real fir1(int n, real_t wn, FilterType ftype, const arr_real& win) {
170124
assert(n > 0);

0 commit comments

Comments
 (0)