blob: 678c7f91a94c21b37301cbd65941b11e375eb6b0 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/*
12 * Implementation of the peak detection used for finding correlation peaks.
13 */
14
15#include "dsp_helpfunctions.h"
16
17#include "signal_processing_library.h"
18
19/* Table of constants used in parabolic fit function WebRtcNetEQ_PrblFit */
20const WebRtc_Word16 WebRtcNetEQ_kPrblCf[17][3] = { { 120, 32, 64 }, { 140, 44, 75 },
21 { 150, 50, 80 }, { 160, 57, 85 },
22 { 180, 72, 96 }, { 200, 89, 107 },
23 { 210, 98, 112 }, { 220, 108, 117 },
24 { 240, 128, 128 }, { 260, 150, 139 },
25 { 270, 162, 144 }, { 280, 174, 149 },
26 { 300, 200, 160 }, { 320, 228, 171 },
27 { 330, 242, 176 }, { 340, 257, 181 },
28 { 360, 288, 192 } };
29
30WebRtc_Word16 WebRtcNetEQ_PeakDetection(WebRtc_Word16 *pw16_data, WebRtc_Word16 w16_dataLen,
31 WebRtc_Word16 w16_nmbPeaks, WebRtc_Word16 fs_mult,
32 WebRtc_Word16 *pw16_winIndex,
33 WebRtc_Word16 *pw16_winValue)
34{
35 /* Local variables */
36 int i;
37 WebRtc_Word16 w16_tmp;
38 WebRtc_Word16 w16_tmp2;
39 WebRtc_Word16 indMin = 0;
40 WebRtc_Word16 indMax = 0;
41
42 /* Peak detection */
43
44 for (i = 0; i <= (w16_nmbPeaks - 1); i++)
45 {
46 if (w16_nmbPeaks == 1)
47 {
48 /*
49 * Single peak
50 * The parabola fit assumes that an extra point is available; worst case it gets
51 * a zero on the high end of the signal.
52 */
53 w16_dataLen++;
54 }
55
56 pw16_winIndex[i] = WebRtcSpl_MaxIndexW16(pw16_data, (WebRtc_Word16) (w16_dataLen - 1));
57
58 if (i != w16_nmbPeaks - 1)
59 {
60 w16_tmp = pw16_winIndex[i] - 2; /* *fs_mult; */
61 indMin = WEBRTC_SPL_MAX(0, w16_tmp);
62 w16_tmp = pw16_winIndex[i] + 2; /* *fs_mult; */
63 w16_tmp2 = w16_dataLen - 1;
64 indMax = WEBRTC_SPL_MIN(w16_tmp2, w16_tmp);
65 }
66
67 if ((pw16_winIndex[i] != 0) && (pw16_winIndex[i] != (w16_dataLen - 2)))
68 {
69 /* Parabola fit*/
70 WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]), &(pw16_winIndex[i]),
71 &(pw16_winValue[i]), fs_mult);
72 }
73 else
74 {
75 if (pw16_winIndex[i] == (w16_dataLen - 2))
76 {
77 if (pw16_data[pw16_winIndex[i]] > pw16_data[pw16_winIndex[i] + 1])
78 {
79 WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]),
80 &(pw16_winIndex[i]), &(pw16_winValue[i]), fs_mult);
81 }
82 else if (pw16_data[pw16_winIndex[i]] <= pw16_data[pw16_winIndex[i] + 1])
83 {
84 pw16_winValue[i] = (pw16_data[pw16_winIndex[i]]
85 + pw16_data[pw16_winIndex[i] + 1]) >> 1; /* lin approx */
86 pw16_winIndex[i] = (pw16_winIndex[i] * 2 + 1) * fs_mult;
87 }
88 }
89 else
90 {
91 pw16_winValue[i] = pw16_data[pw16_winIndex[i]];
92 pw16_winIndex[i] = pw16_winIndex[i] * 2 * fs_mult;
93 }
94 }
95
96 if (i != w16_nmbPeaks - 1)
97 {
98 WebRtcSpl_MemSetW16(&(pw16_data[indMin]), 0, (indMax - indMin + 1));
99 /* for (j=indMin; j<=indMax; j++) pw16_data[j] = 0; */
100 }
101 }
102
103 return 0;
104}
105
106WebRtc_Word16 WebRtcNetEQ_PrblFit(WebRtc_Word16 *pw16_3pts, WebRtc_Word16 *pw16_Ind,
107 WebRtc_Word16 *pw16_outVal, WebRtc_Word16 fs_mult)
108{
109 /* Variables */
110 WebRtc_Word32 Num, Den;
111 WebRtc_Word32 temp;
112 WebRtc_Word16 flag, stp, strt, lmt;
113 WebRtc_UWord16 PFind[13];
114
115 if (fs_mult == 1)
116 {
117 PFind[0] = 0;
118 PFind[1] = 8;
119 PFind[2] = 16;
120 }
121 else if (fs_mult == 2)
122 {
123 PFind[0] = 0;
124 PFind[1] = 4;
125 PFind[2] = 8;
126 PFind[3] = 12;
127 PFind[4] = 16;
128 }
129 else if (fs_mult == 4)
130 {
131 PFind[0] = 0;
132 PFind[1] = 2;
133 PFind[2] = 4;
134 PFind[3] = 6;
135 PFind[4] = 8;
136 PFind[5] = 10;
137 PFind[6] = 12;
138 PFind[7] = 14;
139 PFind[8] = 16;
140 }
141 else
142 {
143 PFind[0] = 0;
144 PFind[1] = 1;
145 PFind[2] = 3;
146 PFind[3] = 4;
147 PFind[4] = 5;
148 PFind[5] = 7;
149 PFind[6] = 8;
150 PFind[7] = 9;
151 PFind[8] = 11;
152 PFind[9] = 12;
153 PFind[10] = 13;
154 PFind[11] = 15;
155 PFind[12] = 16;
156 }
157
158 /* Num = -3*pw16_3pts[0] + 4*pw16_3pts[1] - pw16_3pts[2]; */
159 /* Den = pw16_3pts[0] - 2*pw16_3pts[1] + pw16_3pts[2]; */
160 Num = WEBRTC_SPL_MUL_16_16(pw16_3pts[0],-3) + WEBRTC_SPL_MUL_16_16(pw16_3pts[1],4)
161 - pw16_3pts[2];
162
163 Den = pw16_3pts[0] + WEBRTC_SPL_MUL_16_16(pw16_3pts[1],-2) + pw16_3pts[2];
164
165 temp = (WebRtc_Word32) WEBRTC_SPL_MUL(Num, (WebRtc_Word32)120); /* need 32_16 really */
166 flag = 1;
167 stp = WebRtcNetEQ_kPrblCf[PFind[fs_mult]][0] - WebRtcNetEQ_kPrblCf[PFind[fs_mult - 1]][0];
168 strt = (WebRtcNetEQ_kPrblCf[PFind[fs_mult]][0]
169 + WebRtcNetEQ_kPrblCf[PFind[fs_mult - 1]][0]) >> 1;
170
171 if (temp < (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)strt))
172 {
173 lmt = strt - stp;
174 while (flag)
175 {
176 if ((flag == fs_mult) || (temp
177 > (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)lmt)))
178 {
179 *pw16_outVal
180 = (WebRtc_Word16)
181 (((WebRtc_Word32) ((WebRtc_Word32) WEBRTC_SPL_MUL(Den,(WebRtc_Word32)WebRtcNetEQ_kPrblCf[PFind[fs_mult-flag]][1])
182 + (WebRtc_Word32) WEBRTC_SPL_MUL(Num,(WebRtc_Word32)WebRtcNetEQ_kPrblCf[PFind[fs_mult-flag]][2])
183 + WEBRTC_SPL_MUL_16_16(pw16_3pts[0],256))) >> 8);
184 *pw16_Ind = (*pw16_Ind) * (fs_mult << 1) - flag;
185 flag = 0;
186 }
187 else
188 {
189 flag++;
190 lmt -= stp;
191 }
192 }
193 }
194 else if (temp > (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)(strt+stp)))
195 {
196 lmt = strt + (stp << 1);
197 while (flag)
198 {
199 if ((flag == fs_mult) || (temp
200 < (WebRtc_Word32) WEBRTC_SPL_MUL(-Den,(WebRtc_Word32)lmt)))
201 {
202 WebRtc_Word32 temp_term_1, temp_term_2, temp_term_3;
203
204 temp_term_1 = WEBRTC_SPL_MUL(Den,
205 (WebRtc_Word32) WebRtcNetEQ_kPrblCf[PFind[fs_mult+flag]][1]);
206 temp_term_2 = WEBRTC_SPL_MUL(Num,
207 (WebRtc_Word32) WebRtcNetEQ_kPrblCf[PFind[fs_mult+flag]][2]);
208 temp_term_3 = WEBRTC_SPL_MUL_16_16(pw16_3pts[0],256);
209
210 *pw16_outVal
211 = (WebRtc_Word16) ((temp_term_1 + temp_term_2 + temp_term_3) >> 8);
212
213 *pw16_Ind = (*pw16_Ind) * (fs_mult << 1) + flag;
214 flag = 0;
215 }
216 else
217 {
218 flag++;
219 lmt += stp;
220 }
221 }
222
223 }
224 else
225 {
226 *pw16_outVal = pw16_3pts[1];
227 *pw16_Ind = (*pw16_Ind) * 2 * fs_mult;
228 }
229
230 return 0;
231}
232