This library provides the ability to compute the median, circular median, mean and standard deviation of a dataset stored in a circular buffer

Dependents:   Ni-MH_V3

Committer:
greletj
Date:
Thu Nov 29 22:45:41 2012 +0000
Revision:
1:a4c87bc5b008
Parent:
0:b3a2e39a13ad
Child:
2:809d085bf2cb
add MIT License and date revision

Who changed what in which revision?

UserRevisionLine numberNew contents of line
greletj 1:a4c87bc5b008 1 /* Copyright (c) <2012> <copyright J. Grelet>, MIT License
greletj 1:a4c87bc5b008 2 *
greletj 1:a4c87bc5b008 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
greletj 1:a4c87bc5b008 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
greletj 1:a4c87bc5b008 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
greletj 1:a4c87bc5b008 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
greletj 1:a4c87bc5b008 7 * furnished to do so, subject to the following conditions:
greletj 1:a4c87bc5b008 8 *
greletj 1:a4c87bc5b008 9 * The above copyright notice and this permission notice shall be included in all copies or
greletj 1:a4c87bc5b008 10 * substantial portions of the Software.
greletj 1:a4c87bc5b008 11 *
greletj 1:a4c87bc5b008 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
greletj 1:a4c87bc5b008 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
greletj 1:a4c87bc5b008 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
greletj 1:a4c87bc5b008 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
greletj 1:a4c87bc5b008 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
greletj 1:a4c87bc5b008 17 */
greletj 1:a4c87bc5b008 18
greletj 1:a4c87bc5b008 19 /*****************************************************************************
greletj 0:b3a2e39a13ad 20 * Statis.c *
greletj 0:b3a2e39a13ad 21 * *
greletj 0:b3a2e39a13ad 22 * Module de calcul statistique utilisees par le logiciel THERMO *
greletj 0:b3a2e39a13ad 23 * Ce module dans la version 1.0 calcule : la mediane *
greletj 0:b3a2e39a13ad 24 * la moyenne *
greletj 0:b3a2e39a13ad 25 * l'ecart type *
greletj 0:b3a2e39a13ad 26 * Les fonctions prennent toutes comme argumemts un tableau FAR list[] *
greletj 0:b3a2e39a13ad 27 * et les n_elem sur lequel est realise le calcul. *
greletj 0:b3a2e39a13ad 28 * *
greletj 0:b3a2e39a13ad 29 * Jacques Grelet Mars 1992 *
greletj 0:b3a2e39a13ad 30 * Bruno Buisson Aout 92 *
greletj 0:b3a2e39a13ad 31 * Septembre 1992 *
greletj 0:b3a2e39a13ad 32 * Septembre 1994 *
greletj 1:a4c87bc5b008 33 * Adapted for mbed ARM cortex Novembre 2012 *
greletj 0:b3a2e39a13ad 34 *****************************************************************************/
greletj 0:b3a2e39a13ad 35 #define DEBUG
greletj 0:b3a2e39a13ad 36 #include "mbed.h"
greletj 0:b3a2e39a13ad 37 extern Serial pc;
greletj 0:b3a2e39a13ad 38
greletj 0:b3a2e39a13ad 39 //#undef DEBUG
greletj 0:b3a2e39a13ad 40
greletj 0:b3a2e39a13ad 41 #include <debug.h>
greletj 0:b3a2e39a13ad 42 #include <math.h>
greletj 0:b3a2e39a13ad 43 #include <stdlib.h> // cf. qsort(),fabs()
greletj 0:b3a2e39a13ad 44
greletj 0:b3a2e39a13ad 45 // ring
greletj 0:b3a2e39a13ad 46 #include "ring.h" // cf. statis.h
greletj 0:b3a2e39a13ad 47
greletj 0:b3a2e39a13ad 48 // statis
greletj 0:b3a2e39a13ad 49
greletj 0:b3a2e39a13ad 50 #include "bitmsk.h" // cf. statis.h
greletj 0:b3a2e39a13ad 51 #define _STATIS
greletj 0:b3a2e39a13ad 52 #include "statis.h"
greletj 0:b3a2e39a13ad 53 #undef _STATIS
greletj 0:b3a2e39a13ad 54
greletj 0:b3a2e39a13ad 55 /*****************************************************************************
greletj 0:b3a2e39a13ad 56 * classe Mediane_item *
greletj 0:b3a2e39a13ad 57 *****************************************************************************/
greletj 0:b3a2e39a13ad 58
greletj 0:b3a2e39a13ad 59 /*****************************************************************************
greletj 0:b3a2e39a13ad 60 *****************************************************************************/
greletj 0:b3a2e39a13ad 61 void Mediane_item::raz( void )
greletj 0:b3a2e39a13ad 62 {
greletj 0:b3a2e39a13ad 63 valeur = FLOAT_ERREUR;
greletj 0:b3a2e39a13ad 64 indice = 0;
greletj 0:b3a2e39a13ad 65 }
greletj 0:b3a2e39a13ad 66
greletj 0:b3a2e39a13ad 67 /*****************************************************************************
greletj 0:b3a2e39a13ad 68 *****************************************************************************/
greletj 0:b3a2e39a13ad 69 Mediane_item::Mediane_item( void )
greletj 0:b3a2e39a13ad 70 {
greletj 0:b3a2e39a13ad 71 raz();
greletj 0:b3a2e39a13ad 72 }
greletj 0:b3a2e39a13ad 73
greletj 0:b3a2e39a13ad 74 /*****************************************************************************
greletj 0:b3a2e39a13ad 75 * fonction utilitaire de qsort(),donc pas membre de classe *
greletj 0:b3a2e39a13ad 76 * si a < b retourne -1 *
greletj 0:b3a2e39a13ad 77 * si a = b 0 *
greletj 0:b3a2e39a13ad 78 * si a > b 1 *
greletj 0:b3a2e39a13ad 79 *****************************************************************************/
greletj 0:b3a2e39a13ad 80 static int compare( const void *a,const void *b )
greletj 0:b3a2e39a13ad 81 {
greletj 0:b3a2e39a13ad 82 register float c = ((Mediane_item *)a)->valeur - ((Mediane_item *)b)->valeur;
greletj 0:b3a2e39a13ad 83
greletj 0:b3a2e39a13ad 84 return( ( c == 0.0 ) ? 0 : ( ( c > 0.0 ) ? 1 : -1 ) );
greletj 0:b3a2e39a13ad 85 }
greletj 0:b3a2e39a13ad 86
greletj 0:b3a2e39a13ad 87 /*****************************************************************************
greletj 0:b3a2e39a13ad 88 * classe Mediane *
greletj 0:b3a2e39a13ad 89 *****************************************************************************/
greletj 0:b3a2e39a13ad 90
greletj 0:b3a2e39a13ad 91 /*****************************************************************************
greletj 0:b3a2e39a13ad 92 * n_elem est forcement impair (protege par Statis_data::mediane()) *
greletj 0:b3a2e39a13ad 93 *****************************************************************************/
greletj 0:b3a2e39a13ad 94 Mediane_item &Mediane::mediane( Mediane_item list[],unsigned n_elem )
greletj 0:b3a2e39a13ad 95 {
greletj 0:b3a2e39a13ad 96 switch( n_elem ) {
greletj 0:b3a2e39a13ad 97 case 1 : return( list[ 0 ] );
greletj 0:b3a2e39a13ad 98 default : qsort( (Mediane_item *)list,n_elem,sizeof( list[ 0 ] ),compare );
greletj 0:b3a2e39a13ad 99 return( list[ ( n_elem - 1 ) / 2 ] );
greletj 0:b3a2e39a13ad 100 }
greletj 0:b3a2e39a13ad 101 }
greletj 0:b3a2e39a13ad 102
greletj 0:b3a2e39a13ad 103 /*****************************************************************************
greletj 0:b3a2e39a13ad 104 * classe Mediane_circ *
greletj 0:b3a2e39a13ad 105 *****************************************************************************/
greletj 0:b3a2e39a13ad 106
greletj 0:b3a2e39a13ad 107 /*****************************************************************************
greletj 0:b3a2e39a13ad 108 * n_elem est forcement impair (protege par Statis_data::mediane()) *
greletj 0:b3a2e39a13ad 109 *****************************************************************************/
greletj 0:b3a2e39a13ad 110 Mediane_item &Mediane_circ::mediane( Mediane_item list[],unsigned n_elem )
greletj 0:b3a2e39a13ad 111 {
greletj 0:b3a2e39a13ad 112 int delta_nord,
greletj 0:b3a2e39a13ad 113 delta_sud,
greletj 0:b3a2e39a13ad 114 borne_25,
greletj 0:b3a2e39a13ad 115 borne_75;
greletj 0:b3a2e39a13ad 116 Mediane_item *result;
greletj 0:b3a2e39a13ad 117
greletj 0:b3a2e39a13ad 118 if( n_elem == 1 ) return( list[ 0 ] );
greletj 0:b3a2e39a13ad 119 qsort( (Mediane_item *)list,n_elem,sizeof( list[ 0 ] ),compare );
greletj 0:b3a2e39a13ad 120 borne_25 = n_elem / 4; // 25%
greletj 0:b3a2e39a13ad 121 borne_75 = 3 * n_elem / 4; // 75%
greletj 0:b3a2e39a13ad 122 delta_nord = int( list[ borne_75 ].valeur - list[ borne_25 ].valeur );
greletj 0:b3a2e39a13ad 123 delta_sud = abs( delta_nord - (int)(int)maxi );
greletj 0:b3a2e39a13ad 124 if( delta_sud < delta_nord ) { // si plus de 50% de valeurs dans
greletj 0:b3a2e39a13ad 125 for( unsigned i = 0; i < n_elem; i++ ) // le nord, on change de repere
greletj 0:b3a2e39a13ad 126 if( list[ i ].valeur > moitie && list[ i ].valeur < maxi ) // 180/360
greletj 0:b3a2e39a13ad 127 list[ i ].valeur -= maxi; // -180/180
greletj 0:b3a2e39a13ad 128 qsort( (Mediane_item *)list,n_elem,sizeof( list[ 0 ] ),compare );
greletj 0:b3a2e39a13ad 129 }
greletj 0:b3a2e39a13ad 130 result = &list[ ( n_elem - 1 ) / 2 ];
greletj 0:b3a2e39a13ad 131 if( result->valeur < 0 ) result->valeur += maxi;
greletj 0:b3a2e39a13ad 132 return( *result );
greletj 0:b3a2e39a13ad 133 }
greletj 0:b3a2e39a13ad 134
greletj 0:b3a2e39a13ad 135 /*****************************************************************************
greletj 0:b3a2e39a13ad 136 *****************************************************************************/
greletj 0:b3a2e39a13ad 137 Mediane_circ::Mediane_circ( float a_maxi )
greletj 0:b3a2e39a13ad 138 {
greletj 0:b3a2e39a13ad 139 moitie = ( maxi = fabs( a_maxi ) ) / 2;
greletj 0:b3a2e39a13ad 140 }
greletj 0:b3a2e39a13ad 141
greletj 0:b3a2e39a13ad 142 /*****************************************************************************
greletj 0:b3a2e39a13ad 143 * classe Statis_data *
greletj 0:b3a2e39a13ad 144 *****************************************************************************/
greletj 0:b3a2e39a13ad 145
greletj 0:b3a2e39a13ad 146 /*****************************************************************************
greletj 0:b3a2e39a13ad 147 *****************************************************************************/
greletj 0:b3a2e39a13ad 148 bool Statis_data::verifie( float &val )
greletj 0:b3a2e39a13ad 149 {
greletj 0:b3a2e39a13ad 150 if( ( borne_inf == borne_sup ) || ( val >= borne_inf && val <= borne_sup ) )
greletj 0:b3a2e39a13ad 151 return( true );
greletj 0:b3a2e39a13ad 152 val = FLOAT_ERREUR;
greletj 0:b3a2e39a13ad 153 return( false );
greletj 0:b3a2e39a13ad 154 }
greletj 0:b3a2e39a13ad 155
greletj 0:b3a2e39a13ad 156 /*****************************************************************************
greletj 0:b3a2e39a13ad 157 *****************************************************************************/
greletj 0:b3a2e39a13ad 158 Mediane_item *Statis_data::cons_liste( void )
greletj 0:b3a2e39a13ad 159 {
greletj 0:b3a2e39a13ad 160 for( unsigned i = 0; i < n_elem; i++ ) {
greletj 0:b3a2e39a13ad 161 mediane_liste[ i ].indice = i;
greletj 0:b3a2e39a13ad 162 mediane_liste[ i ].valeur = ring.list[ i ];
greletj 0:b3a2e39a13ad 163 }
greletj 0:b3a2e39a13ad 164 return( mediane_liste );
greletj 0:b3a2e39a13ad 165 }
greletj 0:b3a2e39a13ad 166
greletj 0:b3a2e39a13ad 167 /*****************************************************************************
greletj 0:b3a2e39a13ad 168 *****************************************************************************/
greletj 0:b3a2e39a13ad 169 bool Statis_data::mediane( void )
greletj 0:b3a2e39a13ad 170 {
greletj 0:b3a2e39a13ad 171 if( !mediane_methode || n_elem == 0 ) {
greletj 0:b3a2e39a13ad 172 med.raz();
greletj 0:b3a2e39a13ad 173 return( false );
greletj 0:b3a2e39a13ad 174 }
greletj 0:b3a2e39a13ad 175 med = mediane_methode->mediane( cons_liste(),
greletj 0:b3a2e39a13ad 176 ( n_elem % 2 == 0 ) ? n_elem - 1 : n_elem );
greletj 0:b3a2e39a13ad 177 return( verifie( med.valeur ) );
greletj 0:b3a2e39a13ad 178 }
greletj 0:b3a2e39a13ad 179
greletj 0:b3a2e39a13ad 180 /*****************************************************************************
greletj 0:b3a2e39a13ad 181 *****************************************************************************/
greletj 0:b3a2e39a13ad 182 bool Statis_data::moyenne( void )
greletj 0:b3a2e39a13ad 183 {
greletj 0:b3a2e39a13ad 184 if( n_elem == 0 ) {
greletj 0:b3a2e39a13ad 185 moy = FLOAT_ERREUR;
greletj 0:b3a2e39a13ad 186 return( false );
greletj 0:b3a2e39a13ad 187 }
greletj 0:b3a2e39a13ad 188 moy = 0;
greletj 0:b3a2e39a13ad 189 for( unsigned i = 0; i < n_elem; moy += ring.list[ i++ ] );
greletj 0:b3a2e39a13ad 190 moy /= (float) n_elem;
greletj 0:b3a2e39a13ad 191 return( verifie( moy ) );
greletj 0:b3a2e39a13ad 192 }
greletj 0:b3a2e39a13ad 193
greletj 0:b3a2e39a13ad 194 /*****************************************************************************
greletj 0:b3a2e39a13ad 195 *****************************************************************************/
greletj 0:b3a2e39a13ad 196 bool Statis_data::ecart_type( void )
greletj 0:b3a2e39a13ad 197 {
greletj 0:b3a2e39a13ad 198 float somme_xi_carre = 0.0,
greletj 0:b3a2e39a13ad 199 somme_xi = 0.0,
greletj 0:b3a2e39a13ad 200 x_bar = 0.0;
greletj 0:b3a2e39a13ad 201 float *ptxi;
greletj 0:b3a2e39a13ad 202 unsigned i;
greletj 0:b3a2e39a13ad 203
greletj 0:b3a2e39a13ad 204 switch( n_elem ) {
greletj 0:b3a2e39a13ad 205 case 0 :
greletj 0:b3a2e39a13ad 206 case 1 :
greletj 0:b3a2e39a13ad 207 case 2 : ecart = FLOAT_ERREUR;
greletj 0:b3a2e39a13ad 208 return( false );
greletj 0:b3a2e39a13ad 209 default : for( i = 0,ptxi = ring.list; i < n_elem;
greletj 0:b3a2e39a13ad 210 i++,ptxi++ ) {
greletj 0:b3a2e39a13ad 211 somme_xi += *ptxi;
greletj 0:b3a2e39a13ad 212 somme_xi_carre += *ptxi * *ptxi;
greletj 0:b3a2e39a13ad 213 }
greletj 0:b3a2e39a13ad 214 x_bar = somme_xi / (float) n_elem;
greletj 0:b3a2e39a13ad 215 ecart = sqrt( fabs( somme_xi_carre / (float) n_elem -
greletj 0:b3a2e39a13ad 216 x_bar * x_bar ) );
greletj 0:b3a2e39a13ad 217 return( true );
greletj 0:b3a2e39a13ad 218 }
greletj 0:b3a2e39a13ad 219 }
greletj 0:b3a2e39a13ad 220
greletj 0:b3a2e39a13ad 221 /*****************************************************************************
greletj 0:b3a2e39a13ad 222 *****************************************************************************/
greletj 0:b3a2e39a13ad 223 void Statis_data::calcule( void )
greletj 0:b3a2e39a13ad 224 {
greletj 0:b3a2e39a13ad 225 DPRINTF( ("\r\nStatis::calcule:stat_on=%u,calculs=%x\r\n",stat_on,calculs) );
greletj 0:b3a2e39a13ad 226 if( stat_on ) {
greletj 0:b3a2e39a13ad 227 n_elem = ring.store();
greletj 0:b3a2e39a13ad 228 DPRINTF( ("n_elem=%u.",n_elem) );
greletj 0:b3a2e39a13ad 229 if( calculs & STAT_MED ) mediane();
greletj 0:b3a2e39a13ad 230 if( calculs & STAT_MOYENNE ) {
greletj 0:b3a2e39a13ad 231 moyenne();
greletj 0:b3a2e39a13ad 232 if( calculs & STAT_ECART_TYPE ) ecart_type();
greletj 0:b3a2e39a13ad 233 }
greletj 0:b3a2e39a13ad 234 }
greletj 0:b3a2e39a13ad 235 else {
greletj 0:b3a2e39a13ad 236 ecart = 0;
greletj 0:b3a2e39a13ad 237 moy =
greletj 0:b3a2e39a13ad 238 med.valeur = ( n_elem > 0 ) ? instant : FLOAT_ERREUR;
greletj 0:b3a2e39a13ad 239 med.indice = 0;
greletj 0:b3a2e39a13ad 240 }
greletj 0:b3a2e39a13ad 241 DPRINTF( ("med=%5.4g,moy=%5.4g,instant=%5.4g\r\n",
greletj 0:b3a2e39a13ad 242 med.valeur,moy,instant) );
greletj 0:b3a2e39a13ad 243 n_elem = 0;
greletj 0:b3a2e39a13ad 244 }
greletj 0:b3a2e39a13ad 245
greletj 0:b3a2e39a13ad 246 /*****************************************************************************
greletj 0:b3a2e39a13ad 247 *****************************************************************************/
greletj 0:b3a2e39a13ad 248 float Statis_data::put( float val )
greletj 0:b3a2e39a13ad 249 {
greletj 0:b3a2e39a13ad 250 instant = val;
greletj 0:b3a2e39a13ad 251 if( stat_on ) ring.put( instant );
greletj 0:b3a2e39a13ad 252 else n_elem = 1;
greletj 0:b3a2e39a13ad 253 return( instant );
greletj 0:b3a2e39a13ad 254 }
greletj 0:b3a2e39a13ad 255
greletj 0:b3a2e39a13ad 256 /*****************************************************************************
greletj 0:b3a2e39a13ad 257 *****************************************************************************/
greletj 0:b3a2e39a13ad 258 Statis_data::Statis_data( BITMSK calc,unsigned taille,
greletj 0:b3a2e39a13ad 259 float b_inf /*= 0*/,float b_sup /*= 0*/ )
greletj 0:b3a2e39a13ad 260 : ring( taille ),
greletj 0:b3a2e39a13ad 261 med()
greletj 0:b3a2e39a13ad 262 {
greletj 0:b3a2e39a13ad 263 moy =
greletj 0:b3a2e39a13ad 264 ecart =
greletj 0:b3a2e39a13ad 265 instant = FLOAT_ERREUR;
greletj 0:b3a2e39a13ad 266 borne_inf = b_inf;
greletj 0:b3a2e39a13ad 267 borne_sup = b_sup;
greletj 0:b3a2e39a13ad 268 n_elem = 0;
greletj 0:b3a2e39a13ad 269
greletj 0:b3a2e39a13ad 270 stat_on = taille > 1 ? true : false;
greletj 0:b3a2e39a13ad 271 if( stat_on ) {
greletj 0:b3a2e39a13ad 272 // init_ring_d( &ring,taille );
greletj 0:b3a2e39a13ad 273 mediane_methode = ( ( calculs = calc ) & STAT_MED_NORM )
greletj 0:b3a2e39a13ad 274 ? new Mediane
greletj 0:b3a2e39a13ad 275 : ( calc & STAT_MED_CIRC ) ? new Mediane_circ( b_sup )
greletj 0:b3a2e39a13ad 276 : NULL;
greletj 0:b3a2e39a13ad 277 if( mediane_methode )
greletj 0:b3a2e39a13ad 278 mediane_liste = new Mediane_item[ taille ];
greletj 0:b3a2e39a13ad 279 else
greletj 0:b3a2e39a13ad 280 mediane_liste = NULL;
greletj 0:b3a2e39a13ad 281 }
greletj 0:b3a2e39a13ad 282 else {
greletj 0:b3a2e39a13ad 283 mediane_methode = NULL;
greletj 0:b3a2e39a13ad 284 mediane_liste = NULL;
greletj 0:b3a2e39a13ad 285 }
greletj 0:b3a2e39a13ad 286 }
greletj 0:b3a2e39a13ad 287
greletj 0:b3a2e39a13ad 288 /*****************************************************************************
greletj 0:b3a2e39a13ad 289 *****************************************************************************/
greletj 0:b3a2e39a13ad 290 Statis_data::~Statis_data()
greletj 0:b3a2e39a13ad 291 {
greletj 0:b3a2e39a13ad 292 if( stat_on ) {
greletj 0:b3a2e39a13ad 293 // term_ring_d( &ring );
greletj 0:b3a2e39a13ad 294 if( mediane_methode ) delete mediane_methode;
greletj 0:b3a2e39a13ad 295 if( mediane_liste ) delete [] mediane_liste;
greletj 0:b3a2e39a13ad 296 }
greletj 0:b3a2e39a13ad 297 }