Home | History | Annotate | Download | only in clib
      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 
     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 
     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
     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 
    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 
    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
    199 int median_normalize_data(spect_dist_info *spec, int spec_val)
    200 {
    201   return (spec_val - spec->median + spec->offset);
    202 }
    203 
    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 
    210 int mean_normalize_data(spect_dist_info *spec, int spec_val)
    211 {
    212   return (spec_val - spec->mean + spec->offset);
    213 }
    214 
    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 
    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
    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 
    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 
    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 
    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 
    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 
    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