Skip to content

Commit ca591f7

Browse files
authored
Merge pull request #77 from sp-nitech/goertzel
Add goertzel
2 parents b6d41b6 + eeb9070 commit ca591f7

File tree

9 files changed

+1245
-404
lines changed

9 files changed

+1245
-404
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ tools/**/
2121

2222
# misc
2323
*~
24+
*.bak
2425
*.swp
2526
\#*#
2627
.\#*

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ set(CC_SOURCES
6060
${SOURCE_DIR}/analysis/aperiodicity_extraction_by_world.cc
6161
${SOURCE_DIR}/analysis/autocorrelation_analysis.cc
6262
${SOURCE_DIR}/analysis/fast_fourier_transform_cepstral_analysis.cc
63+
${SOURCE_DIR}/analysis/goertzel_analysis.cc
6364
${SOURCE_DIR}/analysis/mel_cepstral_analysis.cc
6465
${SOURCE_DIR}/analysis/mel_filter_bank_analysis.cc
6566
${SOURCE_DIR}/analysis/mel_frequency_cepstral_coefficients_analysis.cc
@@ -287,6 +288,7 @@ set(MAIN_SOURCES
287288
${SOURCE_DIR}/main/gmm.cc
288289
${SOURCE_DIR}/main/gmmp.cc
289290
${SOURCE_DIR}/main/gnorm.cc
291+
${SOURCE_DIR}/main/goertzel.cc
290292
${SOURCE_DIR}/main/grpdelay.cc
291293
${SOURCE_DIR}/main/histogram.cc
292294
${SOURCE_DIR}/main/huffman.cc

doc/Doxyfile

Lines changed: 709 additions & 403 deletions
Large diffs are not rendered by default.

doc/main/goertzel.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.. _goertzel:
2+
3+
goertzel
4+
========
5+
6+
.. doxygenfile:: goertzel.cc
7+
8+
.. seealso::
9+
10+
:ref:`fftr`
11+
12+
.. doxygenclass:: sptk::GoertzelAnalysis
13+
:members:
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// ------------------------------------------------------------------------ //
2+
// Copyright 2021 SPTK Working Group //
3+
// //
4+
// Licensed under the Apache License, Version 2.0 (the "License"); //
5+
// you may not use this file except in compliance with the License. //
6+
// You may obtain a copy of the License at //
7+
// //
8+
// http://www.apache.org/licenses/LICENSE-2.0 //
9+
// //
10+
// Unless required by applicable law or agreed to in writing, software //
11+
// distributed under the License is distributed on an "AS IS" BASIS, //
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
13+
// See the License for the specific language governing permissions and //
14+
// limitations under the License. //
15+
// ------------------------------------------------------------------------ //
16+
17+
#ifndef SPTK_ANALYSIS_GOERTZEL_ANALYSIS_H_
18+
#define SPTK_ANALYSIS_GOERTZEL_ANALYSIS_H_
19+
20+
#include <vector> // std::vector
21+
22+
#include "SPTK/utils/sptk_utils.h"
23+
24+
namespace sptk {
25+
26+
/**
27+
* Calculate DFT values at specified frequencies using the Goertzel algorithm.
28+
*
29+
* The input is the @f$L@f$-length waveform signals:
30+
* @f[
31+
* \begin{array}{cccc}
32+
* x(0), & x(1), & \ldots, & x(L-1).
33+
* \end{array}
34+
* @f]
35+
* The outputs are the real and imaginary parts of the DFT values:
36+
* @f[
37+
* \begin{array}{cccc}
38+
* \mathrm{Re}(X(0)), & \mathrm{Re}(X(1)), & \ldots, & \mathrm{Re}(X(K-1)), \\
39+
* \mathrm{Im}(X(0)), & \mathrm{Im}(X(1)), & \ldots, & \mathrm{Im}(X(K-1)),
40+
* \end{array}
41+
* @f]
42+
* where @f$K@f$ is the number of frequencies to be analyzed.
43+
*/
44+
class GoertzelAnalysis {
45+
public:
46+
/**
47+
* @param[in] sampling_rate Sampling rate in Hz.
48+
* @param[in] frequencies @f$K@f$ frequencies in Hz to be analyzed.
49+
* @param[in] fft_length Number of points assumed in DFT. This is used to
50+
* determine frequency bin resolution.
51+
*/
52+
GoertzelAnalysis(double sampling_rate, const std::vector<double>& frequencies,
53+
int fft_length);
54+
55+
virtual ~GoertzelAnalysis() {
56+
}
57+
58+
/**
59+
* @return True if this object is valid.
60+
*/
61+
bool IsValid() const {
62+
return is_valid_;
63+
}
64+
65+
/**
66+
* @param[in] signals @f$L@f$-length waveform signals.
67+
* @param[out] real_part_output @f$K@f$ real parts.
68+
* @param[out] imag_part_output @f$K@f$ imaginary parts.
69+
* @return True on success, false on failure.
70+
*/
71+
bool Run(const std::vector<double>& signals,
72+
std::vector<double>* real_part_output,
73+
std::vector<double>* imag_part_output) const;
74+
75+
private:
76+
bool is_valid_;
77+
78+
std::vector<double> sine_table_;
79+
std::vector<double> cosine_table_;
80+
81+
DISALLOW_COPY_AND_ASSIGN(GoertzelAnalysis);
82+
};
83+
84+
} // namespace sptk
85+
86+
#endif // SPTK_ANALYSIS_GOERTZEL_ANALYSIS_H_

src/analysis/goertzel_analysis.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// ------------------------------------------------------------------------ //
2+
// Copyright 2021 SPTK Working Group //
3+
// //
4+
// Licensed under the Apache License, Version 2.0 (the "License"); //
5+
// you may not use this file except in compliance with the License. //
6+
// You may obtain a copy of the License at //
7+
// //
8+
// http://www.apache.org/licenses/LICENSE-2.0 //
9+
// //
10+
// Unless required by applicable law or agreed to in writing, software //
11+
// distributed under the License is distributed on an "AS IS" BASIS, //
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
13+
// See the License for the specific language governing permissions and //
14+
// limitations under the License. //
15+
// ------------------------------------------------------------------------ //
16+
17+
#include "SPTK/analysis/goertzel_analysis.h"
18+
19+
#include <cmath> // std::round
20+
#include <cstddef> // std::size_t
21+
#include <vector> // std::vector
22+
23+
namespace sptk {
24+
25+
GoertzelAnalysis::GoertzelAnalysis(double sampling_rate,
26+
const std::vector<double>& frequencies,
27+
int fft_length)
28+
: is_valid_(true) {
29+
if (sampling_rate <= 0.0 || frequencies.empty() || fft_length <= 0) {
30+
is_valid_ = false;
31+
return;
32+
}
33+
34+
const int table_size(frequencies.size());
35+
sine_table_.resize(table_size);
36+
cosine_table_.resize(table_size);
37+
for (int k(0); k < table_size; ++k) {
38+
if (frequencies[k] < 0.0 || 0.5 * sampling_rate <= frequencies[k]) {
39+
is_valid_ = false;
40+
break;
41+
}
42+
const double n(std::round(fft_length * frequencies[k] / sampling_rate));
43+
const double omega(sptk::kTwoPi * n / fft_length);
44+
sine_table_[k] = std::sin(omega);
45+
cosine_table_[k] = std::cos(omega);
46+
}
47+
}
48+
49+
bool GoertzelAnalysis::Run(const std::vector<double>& signals,
50+
std::vector<double>* real_part,
51+
std::vector<double>* imag_part) const {
52+
// Check inputs.
53+
if (!is_valid_ || NULL == real_part || NULL == imag_part) {
54+
return false;
55+
}
56+
57+
// Prepare memories.
58+
const int table_size(sine_table_.size());
59+
if (real_part->size() != static_cast<std::size_t>(table_size)) {
60+
real_part->resize(table_size);
61+
}
62+
if (imag_part->size() != static_cast<std::size_t>(table_size)) {
63+
imag_part->resize(table_size);
64+
}
65+
66+
const int signal_size(signals.size());
67+
const double* x(&(signals[0]));
68+
double* real(&((*real_part)[0]));
69+
double* imag(&((*imag_part)[0]));
70+
71+
for (int k(0); k < table_size; ++k) {
72+
// Perform second-order IIR filtering.
73+
const double c(2.0 * cosine_table_[k]);
74+
double s1(0.0), s2(0.0);
75+
{
76+
double s0;
77+
for (int t(0); t < signal_size; ++t) {
78+
s0 = x[t] + c * s1 - s2;
79+
s2 = s1;
80+
s1 = s0;
81+
}
82+
}
83+
// Perform first-order FIR filtering.
84+
real[k] = s1 * cosine_table_[k] - s2;
85+
imag[k] = s1 * sine_table_[k];
86+
}
87+
88+
return true;
89+
}
90+
91+
} // namespace sptk

0 commit comments

Comments
 (0)