spandsp  3.0.0
tone_detect.h
1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * tone_detect.h - General telephony tone detection.
5  *
6  * Written by Steve Underwood <steveu@coppice.org>
7  *
8  * Copyright (C) 2001, 2005 Steve Underwood
9  *
10  * All rights reserved.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 2.1,
14  * as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 
26 #if !defined(_SPANDSP_TONE_DETECT_H_)
27 #define _SPANDSP_TONE_DETECT_H_
28 
29 /*!
30  Goertzel filter descriptor.
31 */
33 {
34 #if defined(SPANDSP_USE_FIXED_POINT)
35  int16_t fac;
36 #else
37  float fac;
38 #endif
39  int samples;
40 };
41 
42 /*!
43  Goertzel filter state descriptor.
44 */
46 {
47 #if defined(SPANDSP_USE_FIXED_POINT)
48  int16_t v2;
49  int16_t v3;
50  int16_t fac;
51 #else
52  float v2;
53  float v3;
54  float fac;
55 #endif
56  int samples;
57  int current_sample;
58 };
59 
60 /* Convert a power level in dBm0 or dBov to the equivalent result from a Goertzel filter. This is len*len times the actual power, since
61  the DFT calculation accumulates at the square of the number of samples. */
62 #if defined(SPANDSP_USE_FIXED_POINT)
63 #define goertzel_threshold_dbm0(len,thresh) (int) ((len*len*256.0f*256.0f/2.0f)*powf(10.0f, (thresh - DBM0_MAX_SINE_POWER)/10.0f))
64 #define goertzel_threshold_dbmov(len,thresh) (int) ((len*len*256.0f*256.0f/2.0f)*powf(10.0f, (thresh - DBMOV_MAX_SINE_POWER)/10.0f))
65 #else
66 #define goertzel_threshold_dbm0(len,thresh) (float) ((len*len*32768.0f*32768.0f/2.0f)*powf(10.0f, (thresh - DBM0_MAX_SINE_POWER)/10.0f))
67 #define goertzel_threshold_dbmov(len,thresh) (float) ((len*len*32768.0f*32768.0f/2.0f)*powf(10.0f, (thresh - DBMOV_MAX_SINE_POWER)/10.0f))
68 #endif
69 
70 /*!
71  Goertzel filter descriptor.
72 */
74 
75 /*!
76  Goertzel filter state descriptor.
77 */
78 typedef struct goertzel_state_s goertzel_state_t;
79 
80 #if defined(__cplusplus)
81 extern "C"
82 {
83 #endif
84 
85 /*! \brief Create a descriptor for use with either a Goertzel transform */
87  float freq,
88  int samples);
89 
90 /*! \brief Initialise the state of a Goertzel transform.
91  \param s The Goertzel context. If NULL, a context is allocated.
92  \param t The Goertzel descriptor.
93  \return A pointer to the Goertzel state. */
96 
97 SPAN_DECLARE(int) goertzel_release(goertzel_state_t *s);
98 
99 SPAN_DECLARE(int) goertzel_free(goertzel_state_t *s);
100 
101 /*! \brief Reset the state of a Goertzel transform.
102  \param s The Goertzel context. */
103 SPAN_DECLARE(void) goertzel_reset(goertzel_state_t *s);
104 
105 /*! \brief Update the state of a Goertzel transform.
106  \param s The Goertzel context.
107  \param amp The samples to be transformed.
108  \param samples The number of samples.
109  \return The number of samples unprocessed */
110 SPAN_DECLARE(int) goertzel_update(goertzel_state_t *s,
111  const int16_t amp[],
112  int samples);
113 
114 /*! \brief Evaluate the final result of a Goertzel transform.
115  \param s The Goertzel context.
116  \return The result of the transform. The expected result for a pure sine wave
117  signal of level x dBm0, at the very centre of the bin is:
118  [Floating point] ((samples_per_goertzel_block*32768.0/1.4142)*10^((x - DBM0_MAX_SINE_POWER)/20.0))^2
119  [Fixed point] ((samples_per_goertzel_block*256.0/1.4142)*10^((x - DBM0_MAX_SINE_POWER)/20.0))^2 */
120 #if defined(SPANDSP_USE_FIXED_POINT)
121 SPAN_DECLARE(int32_t) goertzel_result(goertzel_state_t *s);
122 #else
123 SPAN_DECLARE(float) goertzel_result(goertzel_state_t *s);
124 #endif
125 
126 /*! \brief Update the state of a Goertzel transform.
127  \param s The Goertzel context.
128  \param amp The sample to be transformed. */
129 static __inline__ void goertzel_sample(goertzel_state_t *s, int16_t amp)
130 {
131 #if defined(SPANDSP_USE_FIXED_POINT)
132  int16_t x;
133  int16_t v1;
134 #else
135  float v1;
136 #endif
137 
138  v1 = s->v2;
139  s->v2 = s->v3;
140 #if defined(SPANDSP_USE_FIXED_POINT)
141  x = (((int32_t) s->fac*s->v2) >> 14);
142  /* Scale down the input signal to avoid overflows. 9 bits is enough to
143  monitor the signals of interest with adequate dynamic range and
144  resolution. In telephony we generally only start with 13 or 14 bits,
145  anyway. */
146  s->v3 = x - v1 + (amp >> 7);
147 #else
148  s->v3 = s->fac*s->v2 - v1 + amp;
149 #endif
150  s->current_sample++;
151 }
152 /*- End of function --------------------------------------------------------*/
153 
154 /* Scale down the input signal to avoid overflows. 9 bits is enough to
155  monitor the signals of interest with adequate dynamic range and
156  resolution. In telephony we generally only start with 13 or 14 bits,
157  anyway. This is sufficient for the longest Goertzel we currently use. */
158 #if defined(SPANDSP_USE_FIXED_POINT)
159 #define goertzel_preadjust_amp(amp) (((int16_t) amp) >> 7)
160 #else
161 #define goertzel_preadjust_amp(amp) ((float) amp)
162 #endif
163 
164 /* Minimal update the state of a Goertzel transform. This is similar to
165  goertzel_sample, but more suited to blocks of Goertzels. It assumes
166  the amplitude is pre-shifted, and does not update the per-state sample
167  count.
168  \brief Update the state of a Goertzel transform.
169  \param s The Goertzel context.
170  \param amp The adjusted sample to be transformed. */
171 #if defined(SPANDSP_USE_FIXED_POINT)
172 static __inline__ void goertzel_samplex(goertzel_state_t *s, int16_t amp)
173 #else
174 static __inline__ void goertzel_samplex(goertzel_state_t *s, float amp)
175 #endif
176 {
177 #if defined(SPANDSP_USE_FIXED_POINT)
178  int16_t x;
179  int16_t v1;
180 #else
181  float v1;
182 #endif
183 
184  v1 = s->v2;
185  s->v2 = s->v3;
186 #if defined(SPANDSP_USE_FIXED_POINT)
187  x = (((int32_t) s->fac*s->v2) >> 14);
188  s->v3 = x - v1 + amp;
189 #else
190  s->v3 = s->fac*s->v2 - v1 + amp;
191 #endif
192 }
193 /*- End of function --------------------------------------------------------*/
194 
195 /*! Generate a Hamming weighted coefficient set, to be used for a periodogram analysis.
196  \param coeffs The generated coefficients.
197  \param freq The frequency to be matched by the periodogram, in Hz.
198  \param sample_rate The sample rate of the signal, in samples per second.
199  \param window_len The length of the periodogram window. This must be an even number.
200  \return The number of generated coefficients.
201 */
202 SPAN_DECLARE(int) periodogram_generate_coeffs(complexf_t coeffs[], float freq, int sample_rate, int window_len);
203 
204 /*! Generate the phase offset to be expected between successive periodograms evaluated at the
205  specified interval.
206  \param offset A point to the generated phase offset.
207  \param freq The frequency being matched by the periodogram, in Hz.
208  \param sample_rate The sample rate of the signal, in samples per second.
209  \param interval The interval between periodograms, in samples.
210  \return The scaling factor.
211 */
212 SPAN_DECLARE(float) periodogram_generate_phase_offset(complexf_t *offset, float freq, int sample_rate, int interval);
213 
214 /*! Evaluate a periodogram.
215  \param coeffs A set of coefficients generated by periodogram_generate_coeffs().
216  \param amp The complex amplitude of the signal.
217  \param len The length of the periodogram, in samples. This must be an even number.
218  \return The periodogram result.
219 */
220 SPAN_DECLARE(complexf_t) periodogram(const complexf_t coeffs[], const complexf_t amp[], int len);
221 
222 /*! Prepare data for evaluating a set of periodograms.
223  \param sum A vector of sums of pairs of signal samples. This will be half the length of len.
224  \param diff A vector of differences between pairs of signal samples. This will be half the length of len.
225  \param amp The complex amplitude of the signal.
226  \param len The length of the periodogram, in samples. This must be an even number.
227  \return The length of the vectors sum and diff.
228 */
229 SPAN_DECLARE(int) periodogram_prepare(complexf_t sum[], complexf_t diff[], const complexf_t amp[], int len);
230 
231 /*! Evaluate a periodogram, based on data prepared by periodogram_prepare(). This is more efficient
232  than using periodogram() when several periodograms are to be applied to the same signal.
233  \param coeffs A set of coefficients generated by periodogram_generate_coeffs().
234  \param sum A vector of sums produced by periodogram_prepare().
235  \param diff A vector of differences produced by periodogram_prepare().
236  \param len The length of the periodogram, in samples. This must be an even number.
237  \return The periodogram result.
238 */
239 SPAN_DECLARE(complexf_t) periodogram_apply(const complexf_t coeffs[], const complexf_t sum[], const complexf_t diff[], int len);
240 
241 /*! Apply a phase offset, to find the frequency error between periodogram evaluations.
242  specified interval.
243  \param phase_offset A point to the expected phase offset.
244  \param scale The scaling factor to be used.
245  \param last_result A pointer to the previous periodogram result.
246  \param result A pointer to the current periodogram result.
247  \return The frequency error, in Hz.
248 */
249 SPAN_DECLARE(float) periodogram_freq_error(const complexf_t *phase_offset, float scale, const complexf_t *last_result, const complexf_t *result);
250 
251 #if defined(__cplusplus)
252 }
253 #endif
254 
255 #endif
256 /*- End of file ------------------------------------------------------------*/
int goertzel_update(goertzel_state_t *s, const int16_t amp[], int samples)
Update the state of a Goertzel transform.
Definition: tone_detect.c:123
float periodogram_generate_phase_offset(complexf_t *offset, float freq, int sample_rate, int interval)
Definition: tone_detect.c:289
void make_goertzel_descriptor(goertzel_descriptor_t *t, float freq, int samples)
Create a descriptor for use with either a Goertzel transform.
Definition: tone_detect.c:60
complexf_t periodogram_apply(const complexf_t coeffs[], const complexf_t sum[], const complexf_t diff[], int len)
Definition: tone_detect.c:242
void goertzel_reset(goertzel_state_t *s)
Reset the state of a Goertzel transform.
Definition: tone_detect.c:110
float periodogram_freq_error(const complexf_t *phase_offset, float scale, const complexf_t *last_result, const complexf_t *result)
Definition: tone_detect.c:301
complexf_t periodogram(const complexf_t coeffs[], const complexf_t amp[], int len)
Definition: tone_detect.c:208
goertzel_state_t * goertzel_init(goertzel_state_t *s, goertzel_descriptor_t *t)
Initialise the state of a Goertzel transform.
Definition: tone_detect.c:71
Definition: complex.h:42
int periodogram_generate_coeffs(complexf_t coeffs[], float freq, int sample_rate, int window_len)
Definition: tone_detect.c:258
float goertzel_result(goertzel_state_t *s)
Evaluate the final result of a Goertzel transform.
Definition: tone_detect.c:162
Definition: tone_detect.h:45
int periodogram_prepare(complexf_t sum[], complexf_t diff[], const complexf_t amp[], int len)
Definition: tone_detect.c:228
Definition: tone_detect.h:32