• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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