Skip to content

Commit 90faed7

Browse files
committed
Fix API. Normalize gain for ChannelSynthesizer out.
1 parent d70486c commit 90faed7

File tree

4 files changed

+163
-55
lines changed

4 files changed

+163
-55
lines changed

benchs/subband.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static void BM_Channelizer(benchmark::State& state) {
1818

1919
static void BM_ChannelSynthesizer(benchmark::State& state) {
2020
auto chan = dsplib::ChannelSynthesizer(N, D, M);
21-
dsplib::arr_cmplx x = dsplib::randn(N);
21+
dsplib::arr_cmplx x = dsplib::complex(dsplib::randn(N));
2222
for (auto _ : state) {
2323
auto y = chan.process(x);
2424
benchmark::DoNotOptimize(y);

include/dsplib/subband.h

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace dsplib {
99

1010
class ChannelizerImpl;
1111

12+
//TODO: use decim factor in matlab style (M/D)
13+
1214
/**
1315
* @brief Polyphase FFT analysis filter bank
1416
* @details Separates a broadband input signal into multiple narrow subbands
@@ -26,26 +28,24 @@ class Channelizer
2628
* @param filter Multirate FIR coeffs [num_bands * ntaps]
2729
* @param num_bands Number of frequency bands
2830
* @param decim_factor Decimation factor [1 : M-1]
29-
* @param num_taps Number of filter coefficients per frequency band
3031
*/
31-
explicit Channelizer(const arr_real& filter, int num_bands, int decim_factor, int num_taps);
32+
explicit Channelizer(const arr_real& filter, int num_bands, int decim_factor);
3233

3334
/**
3435
* @brief Construct Channelizer
3536
* @details Use this function to save memory if multiple Channelizer/ChannelSynthesizer objects can exist at the same time
3637
* @param filter Pointer to multirate FIR coeffs
3738
* @param num_bands Number of frequency bands
3839
* @param decim_factor Decimation factor [1 : M-1]
39-
* @param num_taps Number of filter coefficients per frequency band
4040
*/
41-
explicit Channelizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor, int num_taps);
41+
explicit Channelizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor);
4242

4343
/**
4444
* @brief Construct Channelizer
4545
* @details The filter will be calculated using the `design_multirate_fir(1, num_bands, ceil(num_taps / 2.0))`
4646
* @param num_bands Number of frequency bands
4747
* @param decim_factor Decimation factor [1 : M-1]
48-
* @param num_taps Number of filter coefficients per frequency band
48+
* @param num_taps Number of filter coefficients per frequency band (expected to be even)
4949
*/
5050
explicit Channelizer(int num_bands, int decim_factor, int num_taps);
5151

@@ -60,6 +60,12 @@ class Channelizer
6060
return this->process(x);
6161
}
6262

63+
/**
64+
* @brief Processing frame size
65+
* @return int frame len
66+
*/
67+
[[nodiscard]] int frame_len() const noexcept;
68+
6369
private:
6470
std::shared_ptr<ChannelizerImpl> d_;
6571
};
@@ -77,32 +83,33 @@ class ChannelSynthesizer
7783
public:
7884
ChannelSynthesizer(const ChannelSynthesizer&) = delete;
7985

86+
//TODO: remove num_taps if filter is calculated
87+
//TODO: params order (bands, decim, ntaps/coeffs)
88+
8089
/**
8190
* @brief Construct ChannelSynthesizer
8291
*
8392
* @param filter Multirate FIR coeffs [num_bands * ntaps]
8493
* @param num_bands Number of frequency bands
8594
* @param decim_factor Decimation factor [1 : M-1]
86-
* @param num_taps Number of filter coefficients per frequency band
8795
*/
88-
explicit ChannelSynthesizer(const arr_real& filter, int num_bands, int decim_factor, int num_taps);
96+
explicit ChannelSynthesizer(const arr_real& filter, int num_bands, int decim_factor);
8997

9098
/**
9199
* @brief Construct ChannelSynthesizer
92100
* @details Use this function to save memory if multiple Channelizer/ChannelSynthesizer objects can exist at the same time
93101
* @param filter Pointer to multirate FIR coeffs
94102
* @param num_bands Number of frequency bands
95103
* @param decim_factor Decimation factor [1 : M-1]
96-
* @param num_taps Number of filter coefficients per frequency band
97104
*/
98-
explicit ChannelSynthesizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor, int num_taps);
105+
explicit ChannelSynthesizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor);
99106

100107
/**
101108
* @brief Construct ChannelSynthesizer
102109
* @details The filter will be calculated using the `design_multirate_fir(1, num_bands, ceil(num_taps / 2.0))`
103110
* @param num_bands Number of frequency bands
104111
* @param decim_factor Decimation factor [1 : M-1]
105-
* @param num_taps Number of filter coefficients per frequency band
112+
* @param num_taps Number of filter coefficients per frequency band (expected to be even)
106113
*/
107114
explicit ChannelSynthesizer(int num_bands, int decim_factor, int num_taps);
108115

@@ -117,6 +124,12 @@ class ChannelSynthesizer
117124
return this->process(x);
118125
}
119126

127+
/**
128+
* @brief Processing frame size
129+
* @return int frame len
130+
*/
131+
[[nodiscard]] int frame_len() const noexcept;
132+
120133
private:
121134
std::shared_ptr<ChannelSynthesizerImpl> d_;
122135
};

lib/subband.cpp

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include "dsplib/subband.h"
2-
#include "dsplib/throw.h"
2+
#include "dsplib/assert.h"
33
#include "dsplib/resample.h"
44
#include "dsplib/fft.h"
55
#include "dsplib/ifft.h"
@@ -124,7 +124,6 @@ class DFTFilterBank
124124
public:
125125
virtual ~DFTFilterBank() = default;
126126

127-
protected:
128127
explicit DFTFilterBank(int num_bands, int decim_factor, int num_taps, bool synthesis = false)
129128
: nbands_{num_bands}
130129
, ntaps_{num_taps}
@@ -139,19 +138,21 @@ class DFTFilterBank
139138
const int decim_;
140139
const int d_;
141140

141+
//TODO: size optimization
142142
CircBuffer buf_;
143143
CircBuffer gsi_;
144144
};
145145

146146
arr_real _design_filter(int num_bands, int num_taps) {
147147
//TODO: cache last coeffs
148-
return design_multirate_fir(1, num_bands, std::ceil(num_taps / 2.0));
148+
assert(num_taps % 2 == 0);
149+
return design_multirate_fir(1, num_bands, num_taps / 2, 80);
149150
}
150151

151152
} // namespace
152153

153154
//--------------------------------------------------------------------------------------------------------
154-
class ChannelizerImpl : protected DFTFilterBank
155+
class ChannelizerImpl : public DFTFilterBank
155156
{
156157
public:
157158
explicit ChannelizerImpl(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor, int num_taps)
@@ -173,8 +174,6 @@ class ChannelizerImpl : protected DFTFilterBank
173174
convert[k + i * d_] = gsi[k];
174175
}
175176
}
176-
177-
//TODO: move or use `convert` array
178177
buf_.push(convert, true);
179178

180179
// calculate outputs of polyphase filters
@@ -198,7 +197,7 @@ class ChannelizerImpl : protected DFTFilterBank
198197
};
199198

200199
//--------------------------------------------------------------------------------------------------------------
201-
class ChannelSynthesizerImpl : private DFTFilterBank
200+
class ChannelSynthesizerImpl : public DFTFilterBank
202201
{
203202
public:
204203
explicit ChannelSynthesizerImpl(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor,
@@ -212,7 +211,7 @@ class ChannelSynthesizerImpl : private DFTFilterBank
212211
arr_real process(const dsplib::arr_cmplx& x) {
213212
DSPLIB_ASSERT(x.size() == nbands_, "input vector size error");
214213

215-
const auto xx = ifft_(x * nbands_);
214+
const auto xx = ifft_(x) * nbands_;
216215
buf_.push(xx, true);
217216

218217
// calculate outputs of polyphase filters
@@ -237,7 +236,10 @@ class ChannelSynthesizerImpl : private DFTFilterBank
237236
out[d_ - k - 1] += gsi[k + i * d_];
238237
}
239238
}
240-
return out;
239+
240+
//normalize ouput
241+
//TODO: more precision, gain error ~ 1 dB
242+
return out * (nbands_ / decim_);
241243
}
242244

243245
private:
@@ -247,40 +249,53 @@ class ChannelSynthesizerImpl : private DFTFilterBank
247249
};
248250

249251
//--------------------------------------------------------------------------------------------------------------
250-
Channelizer::Channelizer(const arr_real& filter, int num_bands, int decim_factor, int num_taps) {
251-
const auto fptr = std::make_shared<dsplib::arr_real>(filter);
252-
d_ = std::make_unique<ChannelizerImpl>(fptr, num_bands, decim_factor, num_taps);
252+
Channelizer::Channelizer(const arr_real& filter, int num_bands, int decim_factor)
253+
: Channelizer(std::make_shared<dsplib::arr_real>(filter), num_bands, decim_factor) {
253254
}
254255

255-
Channelizer::Channelizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor, int num_taps) {
256+
Channelizer::Channelizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor) {
257+
const int num_taps = filter->size() / num_bands;
258+
DSPLIB_ASSERT(num_taps % 2 == 0, "`num_taps` expected to be even");
259+
DSPLIB_ASSERT(num_bands % decim_factor == 0, "only integer ratio M/D supported");
260+
DSPLIB_ASSERT(filter->size() == num_bands * num_taps, "filter size must be equal `num_bands * num_taps`");
256261
d_ = std::make_unique<ChannelizerImpl>(std::move(filter), num_bands, decim_factor, num_taps);
257262
}
258263

259264
Channelizer::Channelizer(int num_bands, int decim_factor, int num_taps)
260-
: Channelizer(_design_filter(num_bands, num_taps), num_bands, decim_factor, num_taps) {
265+
: Channelizer(_design_filter(num_bands, num_taps), num_bands, decim_factor) {
261266
}
262267

263268
arr_cmplx Channelizer::process(const arr_real& x) {
264269
return d_->process(x);
265270
}
266271

272+
int Channelizer::frame_len() const noexcept {
273+
return (d_->nbands_ / d_->decim_);
274+
}
275+
267276
//--------------------------------------------------------------------------------------------------------------
268-
ChannelSynthesizer::ChannelSynthesizer(const arr_real& filter, int num_bands, int decim_factor, int num_taps) {
269-
const auto fptr = std::make_shared<dsplib::arr_real>(filter);
270-
d_ = std::make_unique<ChannelSynthesizerImpl>(fptr, num_bands, decim_factor, num_taps);
277+
ChannelSynthesizer::ChannelSynthesizer(const arr_real& filter, int num_bands, int decim_factor)
278+
: ChannelSynthesizer(std::make_shared<dsplib::arr_real>(filter), num_bands, decim_factor) {
271279
}
272280

273-
ChannelSynthesizer::ChannelSynthesizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor,
274-
int num_taps) {
281+
ChannelSynthesizer::ChannelSynthesizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor) {
282+
const int num_taps = filter->size() / num_bands;
283+
DSPLIB_ASSERT(num_taps % 2 == 0, "`num_taps` expected to be even");
284+
DSPLIB_ASSERT(num_bands % decim_factor == 0, "only integer ratio M/D supported");
285+
DSPLIB_ASSERT(filter->size() == num_bands * num_taps, "filter size must be equal `num_bands * num_taps`");
275286
d_ = std::make_unique<ChannelSynthesizerImpl>(std::move(filter), num_bands, decim_factor, num_taps);
276287
}
277288

278289
ChannelSynthesizer::ChannelSynthesizer(int num_bands, int decim_factor, int num_taps)
279-
: ChannelSynthesizer(_design_filter(num_bands, num_taps), num_bands, decim_factor, num_taps) {
290+
: ChannelSynthesizer(_design_filter(num_bands, num_taps), num_bands, decim_factor) {
280291
}
281292

282293
arr_real ChannelSynthesizer::process(const arr_cmplx& x) {
283294
return d_->process(x);
284295
}
285296

297+
int ChannelSynthesizer::frame_len() const noexcept {
298+
return (d_->nbands_ / d_->decim_);
299+
}
300+
286301
} // namespace dsplib

0 commit comments

Comments
 (0)