Skip to content

Commit e75ff3e

Browse files
committed
Channelizer/ChannelSynthesizer (#64)
* Add polyphase FFT filter banks * Add `zadoff_chu` function * Update tests
1 parent 724df96 commit e75ff3e

File tree

13 files changed

+664
-6
lines changed

13 files changed

+664
-6
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ set(DSPLIB_SOURCES
4545
lib/fft.cpp
4646
lib/ifft.cpp
4747
lib/czt.cpp
48+
lib/subband.cpp
4849
)
4950

5051
if (DSPLIB_EXCLUDE_FFT)

benchs/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ set(SOURCES
4343
resample.cpp
4444
slice.cpp
4545
fir.cpp
46+
subband.cpp
4647
)
4748

4849
add_executable(${PROJECT_NAME} ${SOURCES})

benchs/subband.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <benchmark/benchmark.h>
2+
#include <dsplib.h>
3+
4+
#include "dsplib/subband.h"
5+
6+
constexpr int M = 4;
7+
constexpr int N = 1024;
8+
constexpr int D = 2;
9+
10+
static void BM_Channelizer(benchmark::State& state) {
11+
auto chan = dsplib::Channelizer(N, D, M);
12+
auto x = dsplib::randn(N / D);
13+
for (auto _ : state) {
14+
auto y = chan.process(x);
15+
benchmark::DoNotOptimize(y);
16+
}
17+
}
18+
19+
static void BM_ChannelSynthesizer(benchmark::State& state) {
20+
auto chan = dsplib::ChannelSynthesizer(N, D, M);
21+
dsplib::arr_cmplx x = dsplib::complex(dsplib::randn(N));
22+
for (auto _ : state) {
23+
auto y = chan.process(x);
24+
benchmark::DoNotOptimize(y);
25+
}
26+
}
27+
28+
BENCHMARK(BM_Channelizer)->Unit(benchmark::kMicrosecond)->MinTime(5);
29+
BENCHMARK(BM_ChannelSynthesizer)->Unit(benchmark::kMicrosecond)->MinTime(5);

include/dsplib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <dsplib/spectrum.h>
2727
#include <dsplib/stft.h>
2828
#include <dsplib/assert.h>
29+
#include <dsplib/subband.h>
2930

3031
#include <dsplib/audio/noise-gate.h>
3132
#include <dsplib/audio/compressor.h>

include/dsplib/subband.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#pragma once
2+
3+
#include <dsplib/array.h>
4+
5+
#include <cassert>
6+
#include <memory>
7+
8+
namespace dsplib {
9+
10+
class ChannelizerImpl;
11+
12+
//TODO: use decim factor in matlab style (M/D)
13+
14+
/**
15+
* @brief Polyphase FFT analysis filter bank
16+
* @details Separates a broadband input signal into multiple narrow subbands
17+
* @see Matlab dsp.Channelizer
18+
* @todo Add `Range` parameter [OneSided, Twosided, Centered]
19+
*/
20+
class Channelizer
21+
{
22+
public:
23+
Channelizer(const Channelizer&) = delete;
24+
25+
/**
26+
* @brief Construct Channelizer
27+
*
28+
* @param filter Multirate FIR coeffs [num_bands * ntaps]
29+
* @param num_bands Number of frequency bands
30+
* @param decim_factor Decimation factor [1 : M-1]
31+
*/
32+
explicit Channelizer(const arr_real& filter, int num_bands, int decim_factor);
33+
34+
/**
35+
* @brief Construct Channelizer
36+
* @details Use this function to save memory if multiple Channelizer/ChannelSynthesizer objects can exist at the same time
37+
* @param filter Pointer to multirate FIR coeffs
38+
* @param num_bands Number of frequency bands
39+
* @param decim_factor Decimation factor [1 : M-1]
40+
*/
41+
explicit Channelizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor);
42+
43+
/**
44+
* @brief Construct Channelizer
45+
* @details The filter will be calculated using the `design_multirate_fir(1, num_bands, ceil(num_taps / 2.0))`
46+
* @param num_bands Number of frequency bands
47+
* @param decim_factor Decimation factor [1 : M-1]
48+
* @param num_taps Number of filter coefficients per frequency band (expected to be even)
49+
*/
50+
explicit Channelizer(int num_bands, int decim_factor, int num_taps);
51+
52+
/**
53+
* @brief Filter bank processing (analysis)
54+
* @param x Input broadband signal [num_bands / decim_factor]
55+
* @return arr_cmplx Subband signal [num_bands]
56+
*/
57+
[[nodiscard]] arr_cmplx process(const arr_real& x);
58+
59+
arr_cmplx operator()(const arr_real& x) {
60+
return this->process(x);
61+
}
62+
63+
/**
64+
* @brief Processing frame size
65+
* @return int frame len
66+
*/
67+
[[nodiscard]] int frame_len() const noexcept;
68+
69+
private:
70+
std::shared_ptr<ChannelizerImpl> d_;
71+
};
72+
73+
class ChannelSynthesizerImpl;
74+
75+
/**
76+
* @brief Polyphase FFT synthesis filter bank
77+
* @details Ideally ChannelSynthesizer(Channelizer(x)) == x.
78+
* @see Matlab dsp.ChannelSynthesizer
79+
* @warning This implementation differs from matlab in the decimation parameter. For decim_factor=1, the results should be identical.
80+
* @todo remove num_taps if filter is calculated
81+
* @todo params order (bands, decim, ntaps/coeffs)
82+
*/
83+
class ChannelSynthesizer
84+
{
85+
public:
86+
ChannelSynthesizer(const ChannelSynthesizer&) = delete;
87+
88+
/**
89+
* @brief Construct ChannelSynthesizer
90+
*
91+
* @param filter Multirate FIR coeffs [num_bands * ntaps]
92+
* @param num_bands Number of frequency bands
93+
* @param decim_factor Decimation factor [1 : M-1]
94+
*/
95+
explicit ChannelSynthesizer(const arr_real& filter, int num_bands, int decim_factor);
96+
97+
/**
98+
* @brief Construct ChannelSynthesizer
99+
* @details Use this function to save memory if multiple Channelizer/ChannelSynthesizer objects can exist at the same time
100+
* @param filter Pointer to multirate FIR coeffs
101+
* @param num_bands Number of frequency bands
102+
* @param decim_factor Decimation factor [1 : M-1]
103+
*/
104+
explicit ChannelSynthesizer(std::shared_ptr<const arr_real> filter, int num_bands, int decim_factor);
105+
106+
/**
107+
* @brief Construct ChannelSynthesizer
108+
* @details The filter will be calculated using the `design_multirate_fir(1, num_bands, ceil(num_taps / 2.0))`
109+
* @param num_bands Number of frequency bands
110+
* @param decim_factor Decimation factor [1 : M-1]
111+
* @param num_taps Number of filter coefficients per frequency band (expected to be even)
112+
*/
113+
explicit ChannelSynthesizer(int num_bands, int decim_factor, int num_taps);
114+
115+
/**
116+
* @brief Filter bank processing (synthesis)
117+
* @param x Input subband signal [num_bands]
118+
* @return arr_cmplx Restored broadband signal [num_bands / decim_factor]
119+
*/
120+
[[nodiscard]] arr_real process(const arr_cmplx& x);
121+
122+
arr_real operator()(const arr_cmplx& x) {
123+
return this->process(x);
124+
}
125+
126+
/**
127+
* @brief Processing frame size
128+
* @return int frame len
129+
*/
130+
[[nodiscard]] int frame_len() const noexcept;
131+
132+
private:
133+
std::shared_ptr<ChannelSynthesizerImpl> d_;
134+
};
135+
136+
} // namespace dsplib

include/dsplib/utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,4 +240,12 @@ arr_cmplx circshift(const arr_cmplx& x, int k);
240240
arr_real fftshift(const arr_real& x);
241241
arr_cmplx fftshift(const arr_cmplx& x);
242242

243+
/**
244+
* @brief generate Zadoff-Chu sequence
245+
* @param r root, from 1 to n-1
246+
* @param n length
247+
* @return Zadoff-Chu sequence
248+
*/
249+
arr_cmplx zadoff_chu(int r, int n);
250+
243251
} // namespace dsplib

lib/corr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ real_t corr(const arr_real& x, const arr_real& y, Correlation type) {
8484
default:
8585
return 0;
8686
}
87+
return 0;
8788
}
8889

8990
} // namespace dsplib

lib/czt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class CztPlanImpl
1515
: _n{n}
1616
, _m{m} {
1717
assert(abs(abs(w) - 1.0) < 2 * eps());
18-
auto t = abs2(arange(1 - n, max(m, n))) / 2;
18+
const auto t = abs2(arange(1 - n, max(m, n))) / 2;
1919
arr_cmplx chirp(t.size());
2020
const auto w_a = angle(w);
2121
for (int i = 0; i < t.size(); ++i) {

0 commit comments

Comments
 (0)