1 /*---------------------------------------------------------------------------*
2 * specnorm.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20
21 #ifndef _RTT
22 #include <stdio.h>
23 #endif
24 #include <stdlib.h>
25 #include <math.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "duk_err.h"
30 #include "specnorm.h"
31 #include "portable.h"
32
33 #define DEBUG 0
34
35 static const char specnorm[] = "$Id: specnorm.c,v 1.2.10.7 2007/10/15 18:06:24 dahan Exp $";
36
37 int copy_distribution_counts(spect_dist_info *spec, spect_dist_info *base);
38
39
add_distribution_data(spect_dist_info * spec,int spec_val)40 int add_distribution_data(spect_dist_info *spec, int spec_val)
41 {
42 /* Median calculations
43 */
44 ASSERT(spec);
45 #if USE_MEDIAN
46 if (spec_val < spec->low_entry) spec->low_counts += UNIT_SIZE;
47 else if (spec_val > spec->high_entry) spec->high_counts += UNIT_SIZE;
48 else spec->hist[spec_val - spec->low_entry] += UNIT_SIZE;
49 #endif
50
51 /* Mean calculations
52 */
53 #if 1
54 spec->running_total += spec_val - spec->mean;
55 spec->running_total_devn += (spec_val - spec->mean)
56 * (spec_val - spec->mean);
57 #else
58 spec->running_total += spec_val;
59 spec->running_total_devn += spec_val * spec_val;
60 #endif
61
62 spec->count++;
63 if (spec->estimate_period > 0 && spec->count >= spec->estimate_period)
64 {
65 evaluate_parameters(spec);
66 spec->gain_used = False;
67 spec->count = 0;
68 return (1);
69 }
70 return (0);
71 }
72
evaluate_parameters(spect_dist_info * spec)73 void evaluate_parameters(spect_dist_info *spec)
74 {
75 ASSERT(spec);
76 #if USE_MEDIAN
77 estimate_sv6(spec);
78 spec->median = estimate_percentile(spec, spec->estimate_percentile);
79 spec->perc_high = estimate_percentile(spec, 90); /* check this value */
80 #endif
81 #if USE_MEAN
82 estimate_mean(spec, spec->forget_factor);
83 #endif
84 #if USE_MEDIAN
85 forget_distribution_counts(spec, spec->forget_factor);
86 #endif
87 spec->count = 0;
88 return;
89 }
90
91 #if USE_MEDIAN
estimate_percentile(spect_dist_info * spec,int percentile)92 int estimate_percentile(spect_dist_info *spec, int percentile)
93 {
94 int ii, jj, count, cumval;
95 long accum = 0;
96
97 /* Calculate the median
98 */
99 ASSERT(spec);
100 if (spec->count < MIN_COUNT) return(spec->median);
101 if (percentile == 0)
102 percentile = spec->estimate_percentile;
103 count = spec->low_counts + spec->high_counts;
104 for (ii = 0; ii <= (spec->high_entry - spec->low_entry); ii++)
105 count += spec->hist[ii];
106 count = (count * percentile) / 100;
107
108 cumval = spec->low_counts;
109 for (ii = 0; ii <= (spec->high_entry - spec->low_entry)
110 && cumval < count; ii++)
111 cumval += spec->hist[ii];
112
113 count = 0;
114 for (jj = ii; jj <= (spec->high_entry - spec->low_entry); jj++)
115 {
116 count += spec->hist[jj];
117 accum += spec->hist[jj] * (jj - ii);
118 }
119 #if DEBUG
120 if (count > 0)
121 log_report("Median margin %d\n", accum / count);
122 #endif
123 return (spec->low_entry + ii);
124 }
125
estimate_sv6(spect_dist_info * spec)126 void estimate_sv6(spect_dist_info *spec)
127 {
128 int ii, jj, count, span, totcount;
129 long accum;
130
131 /* Calculate the median
132 */
133 ASSERT(spec);
134 if (spec->count < MIN_COUNT) return;
135 count = spec->high_counts;
136 accum = 0;
137 span = spec->high_entry - spec->low_entry;
138 for (ii = 0, jj = spec->high_entry - spec->low_entry;
139 ii <= span; ii++, jj--)
140 {
141 count += spec->hist[jj];
142 accum += spec->hist[jj] * ii;
143 if (count > 0 && (ii - accum / count) > spec->sv6_margin)
144 break;
145 }
146
147 totcount = count;
148 for (; ii <= span; ii++, jj--)
149 totcount += spec->hist[jj];
150 totcount += spec->high_counts;
151
152 #if DEBUG
153 log_report("SV6 (%d) Percentage %d, %d, %d\n", spec->sv6_margin,
154 (count * 100) / totcount,
155 totcount, spec->count);
156 #endif
157 if (count > 0)
158 spec->sv6 = spec->high_entry - accum / count;
159 return;
160 }
161 #endif
162
estimate_mean(spect_dist_info * spec,int forget_factor)163 void estimate_mean(spect_dist_info *spec, int forget_factor)
164 {
165 /* Calculate the mean and standard deviation
166 */
167 ASSERT(spec);
168 if (spec->count < MIN_COUNT) return;
169 #if DEBUG
170 log_report("old mean= %d, ", spec->mean);
171 #endif
172 spec->mean_count = (spec->mean_count * (100 - forget_factor)) / 100;
173 spec->mean_count += spec->count;
174 if (spec->mean_count > 0)
175 {
176 spec->devn = spec->running_total_devn / spec->mean_count
177 - (spec->running_total * spec->running_total)
178 / (spec->mean_count * spec->mean_count);
179 spec->devn = (int) sqrt((double) spec->devn);
180 if (spec->running_total >= 0)
181 spec->mean += (spec->running_total + spec->mean_count / 2)
182 / spec->mean_count;
183 else
184 spec->mean += (spec->running_total - spec->mean_count / 2)
185 / spec->mean_count;
186 }
187 #if DEBUG
188 log_report("accumulates= %d and %d (%d), ", spec->running_total,
189 spec->mean_count, spec->count);
190 log_report("new mean= %d\n", spec->mean);
191 #endif
192 spec->running_total = 0;
193 spec->running_total_devn = 0;
194
195 return;
196 }
197
198 #if USE_MEDIAN
median_normalize_data(spect_dist_info * spec,int spec_val)199 int median_normalize_data(spect_dist_info *spec, int spec_val)
200 {
201 return (spec_val - spec->median + spec->offset);
202 }
203
sv6_normalize_data(spect_dist_info * spec,int spec_val)204 int sv6_normalize_data(spect_dist_info *spec, int spec_val)
205 {
206 return (spec_val - spec->sv6 + spec->offset);
207 }
208 #endif
209
mean_normalize_data(spect_dist_info * spec,int spec_val)210 int mean_normalize_data(spect_dist_info *spec, int spec_val)
211 {
212 return (spec_val - spec->mean + spec->offset);
213 }
214
create_spectrum_distribution(int offset,int initial_median,int low_entry,int high_entry,int forget_factor,int estimate_period,int estimate_percentile,int sv6_margin)215 spect_dist_info *create_spectrum_distribution(int offset, int initial_median,
216 int low_entry, int high_entry,
217 int forget_factor, int estimate_period,
218 int estimate_percentile,
219 int sv6_margin)
220 {
221 spect_dist_info *spec;
222
223 if (high_entry < low_entry) return(NULL);
224
225 spec = (spect_dist_info *) CALLOC_CLR(1,
226 sizeof(spect_dist_info), "clib.spec");
227 if (estimate_period == 0) /* basically disable 0 as an estimate period */
228 spec->estimate_period = 1;
229 else
230 spec->estimate_period = estimate_period;
231 spec->forget_factor = forget_factor;
232 spec->offset = offset;
233
234 #if USE_MEDIAN
235 spec->hist = (long *) CALLOC_CLR(high_entry - low_entry + 1,
236 sizeof(int), "clib.spec.hist");
237 spec->low_entry = low_entry;
238 spec->high_entry = high_entry;
239 spec->median = initial_median;
240 spec->estimate_percentile = estimate_percentile;
241 spec->sv6_margin = sv6_margin;
242 clear_distribution_counts(spec);
243 #endif
244 #if USE_MEAN
245 spec->mean = initial_median;
246 spec->devn = 0;
247 clear_mean_counts(spec);
248 #endif
249 spec->sv6 = initial_median;
250
251 return (spec);
252 }
253
destroy_spectrum_distribution(spect_dist_info * spec)254 void destroy_spectrum_distribution(spect_dist_info *spec)
255 {
256 ASSERT(spec);
257 #if USE_MEDIAN
258 FREE((char *)spec->hist);
259 #endif
260 FREE((char *)spec);
261 return;
262 }
263
264 #if USE_MEDIAN
clear_distribution_counts(spect_dist_info * spec)265 void clear_distribution_counts(spect_dist_info *spec)
266 {
267 int ii;
268
269 ASSERT(spec);
270 spec->high_counts = 0;
271 spec->low_counts = 0;
272 spec->count = 0;
273 for (ii = 0; ii <= (spec->high_entry - spec->low_entry); ii++)
274 spec->hist[ii] = 0;
275 return;
276 }
277
copy_distribution_counts(spect_dist_info * spec,spect_dist_info * base)278 int copy_distribution_counts(spect_dist_info *spec, spect_dist_info *base)
279 {
280 int ii;
281
282 ASSERT(spec);
283 ASSERT(base);
284 ASSERT(spec->hist);
285 ASSERT(base->hist);
286 if (base->low_entry != spec->low_entry ||
287 base->high_entry != spec->high_entry)
288 return (False);
289 spec->high_counts = base->high_counts;
290 spec->low_counts = base->low_counts;
291 for (ii = 0; ii <= (spec->high_entry - spec->low_entry); ii++)
292 spec->hist[ii] = base->hist[ii];
293 return (True);
294 }
295
forget_distribution_counts(spect_dist_info * spec,int forget_factor)296 void forget_distribution_counts(spect_dist_info *spec, int forget_factor)
297 {
298 int ii, remember;
299
300 ASSERT(spec);
301 /* remember= 100 - (forget_factor * spec->count)/spec->estimate_period; */
302 remember = 100 - forget_factor;
303 spec->high_counts = (spec->high_counts * remember) / 100;
304 spec->low_counts = (spec->low_counts * remember) / 100;
305 for (ii = 0; ii <= (spec->high_entry - spec->low_entry); ii++)
306 spec->hist[ii] = (spec->hist[ii] * remember) / 100;
307 return;
308 }
309
shift_distribution_counts(spect_dist_info * spec,int shift)310 void shift_distribution_counts(spect_dist_info *spec, int shift)
311 {
312 int ii;
313
314 ASSERT(spec);
315 if (shift > 0)
316 {
317 if (shift > (spec->high_entry - spec->low_entry))
318 SERVICE_ERROR(UNEXPECTED_DATA_ERROR); /* TODO: find a new error code */
319 for (ii = 0; ii < shift; ii++)
320 spec->high_counts += spec->hist[spec->high_entry
321 - spec->low_entry - shift + ii];
322
323 MEMMOVE(&spec->hist[shift], spec->hist,
324 (spec->high_entry - spec->low_entry - shift + 1),
325 sizeof(int));
326 for (ii = 0; ii < shift; ii++)
327 spec->hist[ii] = 0;
328 }
329 else if (shift < 0)
330 {
331 if (shift < (spec->low_entry - spec->high_entry))
332 SERVICE_ERROR(UNEXPECTED_DATA_ERROR); /* TODO: find a new error code */
333 for (ii = 0; ii < -shift; ii++)
334 spec->low_counts += spec->hist[ii];
335
336 MEMMOVE(spec->hist, spec->hist - shift,
337 (spec->high_entry - spec->low_entry + shift + 1),
338 sizeof(int));
339 for (ii = shift; ii < 0; ii++)
340 spec->hist[ii + spec->high_entry - spec->low_entry + 1] = 0;
341 }
342 return;
343 }
344 #endif
345
clear_mean_counts(spect_dist_info * spec)346 void clear_mean_counts(spect_dist_info *spec)
347 {
348 ASSERT(spec);
349 spec->mean_count = 0;
350 spec->count = 0;
351 spec->running_total = 0;
352 spec->running_total_devn = 0;
353 return;
354 }
355
shift_parameters(spect_dist_info * spec,int shift)356 void shift_parameters(spect_dist_info *spec, int shift)
357 {
358 ASSERT(spec);
359 spec->mean += shift;
360 #if USE_MEDIAN
361 spec->median += shift;
362 spec->sv6 += shift;
363 #endif
364 return;
365 }
366