vircam_stats.c

00001 /* $Id: vircam_stats.c,v 1.16 2007/10/25 17:34:01 jim Exp $
00002  *
00003  * This file is part of the VIRCAM Pipeline
00004  * Copyright (C) 2005 Cambridge Astronomy Survey Unit
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: jim $
00023  * $Date: 2007/10/25 17:34:01 $
00024  * $Revision: 1.16 $
00025  * $Name:  $
00026  */
00027 
00028 /* Includes */
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033 
00034 #include <math.h>
00035 #include <string.h>
00036 #include <cpl.h>
00037 #include <cxtypes.h>
00038 
00039 #include "vircam_stats.h"
00040 #include "vircam_utils.h"
00041 
00042 /* Static subroutine prototypes */
00043 
00044 static float kselect(float *a, int n, int k);
00045 static double dkselect(double *a, int n, int k);
00046 static float histexam(int *histo, int nhist, int level);
00047 
00061 /*---------------------------------------------------------------------------*/
00087 /*---------------------------------------------------------------------------*/
00088 
00089 extern float vircam_med(float *data, unsigned char *bpm, long npts) {
00090     int i,j,is_even,ilevel;
00091     float *buf,value;
00092 
00093     /* If there is not BPM, then just do a straight forward median */
00094 
00095     buf = cpl_malloc(npts*sizeof(*buf));
00096     if (bpm == NULL) {
00097         is_even = !(npts & 1);
00098         memmove((char *)buf,(char *)data,npts*sizeof(float));
00099         if (is_even) {
00100             ilevel = npts/2 - 1;
00101             value = kselect(buf,npts,ilevel);
00102             ilevel = npts/2;
00103             value = 0.5*(value + kselect(buf,npts,ilevel));
00104         } else {
00105             ilevel = npts/2;
00106             value = kselect(buf,npts,ilevel);
00107         }
00108 
00109     /* Otherwise get rid of the dodgy values and then do the median */
00110 
00111     } else {
00112         j = 0;
00113         for (i = 0; i < npts; i++) {
00114             if (bpm[i] == 0)
00115                 buf[j++] = data[i];
00116         }
00117         if (j == 0) {
00118             cpl_free(buf);
00119             value = CX_MAXFLOAT;
00120             return(value);
00121         }
00122         is_even = !(j & 1);
00123         if (is_even) {
00124             ilevel = j/2 - 1;
00125             value = kselect(buf,j,ilevel);
00126             ilevel = j/2;
00127             value = 0.5*(value + kselect(buf,j,ilevel));
00128         } else {
00129             ilevel = j/2;
00130             value = kselect(buf,j,ilevel);
00131         }
00132     }
00133     cpl_free(buf);
00134     return(value);
00135 }
00136 
00137 /*---------------------------------------------------------------------------*/
00163 /*---------------------------------------------------------------------------*/
00164 
00165 extern double vircam_dmed(double *data, unsigned char *bpm, long npts) {
00166     int i,j,is_even,ilevel;
00167     double *buf,value;
00168 
00169     /* If there is not BPM, then just do a straight forward median */
00170 
00171     buf = cpl_malloc(npts*sizeof(*buf));
00172     if (bpm == NULL) {
00173         is_even = !(npts & 1);
00174         memmove((char *)buf,(char *)data,npts*sizeof(double));
00175         if (is_even) {
00176             ilevel = npts/2 - 1;
00177             value = dkselect(buf,npts,ilevel);
00178             ilevel = npts/2;
00179             value = 0.5*(value + dkselect(buf,npts,ilevel));
00180         } else {
00181             ilevel = npts/2;
00182             value = dkselect(buf,npts,ilevel);
00183         }
00184 
00185     /* Otherwise get rid of the dodgy values and then do the median */
00186 
00187     } else {
00188         j = 0;
00189         for (i = 0; i < npts; i++) {
00190             if (bpm[i] == 0)
00191                 buf[j++] = data[i];
00192         }
00193         if (j == 0) {
00194             cpl_free(buf);
00195             value = CX_MAXDOUBLE;
00196             return(value);
00197         }
00198         is_even = !(j & 1);
00199         if (is_even) {
00200             ilevel = j/2 - 1;
00201             value = dkselect(buf,j,ilevel);
00202             ilevel = j/2;
00203             value = 0.5*(value + dkselect(buf,j,ilevel));
00204         } else {
00205             ilevel = j/2;
00206             value = dkselect(buf,j,ilevel);
00207         }
00208     }
00209     cpl_free(buf);
00210     return(value);
00211 }
00212 
00213 /*---------------------------------------------------------------------------*/
00239 /*---------------------------------------------------------------------------*/
00240 
00241 extern float vircam_mean(float *data, unsigned char *bpm, long npts) {
00242     int i,n;
00243     float sum,value;
00244 
00245     /* Separate sections depending on whether there is a BPM or not */
00246 
00247     sum = 0.0;
00248     if (bpm == NULL) {
00249         n = npts;
00250         for (i = 0; i < npts; i++) 
00251             sum += data[i];
00252     } else {
00253         n = 0;
00254         for (i = 0; i < npts; i++) {
00255             if (bpm[i] == 0) {
00256                 sum += data[i];
00257                 n++;
00258             }
00259         }
00260     }
00261     if (n > 0)
00262         value = sum/(float)n;
00263     else
00264         value = CX_MAXFLOAT;
00265     return(value);
00266 }
00267 
00268 /*---------------------------------------------------------------------------*/
00294 /*---------------------------------------------------------------------------*/
00295 
00296 extern double vircam_dmean(double *data, unsigned char *bpm, long npts) {
00297     int i,n;
00298     double sum,value;
00299 
00300     /* Separate sections depending on whether there is a BPM or not */
00301 
00302     sum = 0.0;
00303     if (bpm == NULL) {
00304         n = npts;
00305         for (i = 0; i < npts; i++) 
00306             sum += data[i];
00307     } else {
00308         n = 0;
00309         for (i = 0; i < npts; i++) {
00310             if (bpm[i] == 0) {
00311                 sum += data[i];
00312                 n++;
00313             }
00314         }
00315     }
00316     if (n > 0)
00317         value = sum/(float)n;
00318     else
00319         value = CX_MAXDOUBLE;
00320     return(value);
00321 }
00322 
00323 /*---------------------------------------------------------------------------*/
00355 /*---------------------------------------------------------------------------*/
00356 
00357 extern int vircam_meansig(float *data, unsigned char *bpm, long npts, 
00358                           float *mean, float *sig) {
00359     int i,n;
00360     double sum,sum2,d;
00361     const char *fctid = "vircam_meansig";
00362 
00363     /* Separate sections depending on whether there is a BPM or not */
00364 
00365     sum = 0.0;
00366     sum2 = 0.0;
00367     if (bpm == NULL) {
00368         n = npts;
00369         for (i = 0; i < npts; i++) {
00370             d = (double)(data[i]);
00371             sum += d;
00372             sum2 += d*d;
00373         }
00374     } else {
00375         n = 0;
00376         for (i = 0; i < npts; i++) {
00377             if (bpm[i] == 0) {
00378                 d = (double)(data[i]);
00379                 sum += d;
00380                 sum2 += d*d;
00381                 n++;
00382             }
00383         }
00384     }
00385 
00386     /* Check whether we can do the mean and sigma calculations */
00387 
00388     switch (n) {
00389     case 0:
00390         *mean = CX_MAXFLOAT;
00391         *sig = CX_MAXFLOAT;
00392         cpl_msg_warning(fctid,"All values flagged as bad\n");
00393         return(VIR_WARN);
00394     case 1:
00395         *mean = (float)sum;
00396         *sig = 0.0;
00397         return(VIR_OK);
00398     default:
00399         sum /= (double)n;
00400         *mean = (float)sum;
00401         sum2 = sum2/(double)n - sum*sum;
00402         *sig = (float)sqrt(max(1.0e-12,sum2));
00403         return(VIR_OK);
00404     }
00405 }
00406 
00407 /*---------------------------------------------------------------------------*/
00444 /*---------------------------------------------------------------------------*/
00445 
00446 extern int vircam_meansigcut(float *data, unsigned char *bpm, long npts,
00447                              float lcut, float hcut, float *mean, float *sig) {
00448     int i,n;
00449     double sum,sum2;
00450     const char *fctid = "vircam_meansigcut";
00451 
00452     /* Separate sections depending on whether there is a BPM or not */
00453 
00454     sum = 0.0;
00455     sum2 = 0.0;
00456     if (bpm == NULL) {
00457         n = 0;
00458         for (i = 0; i < npts; i++) {
00459             if (data[i] > lcut && data[i] < hcut) {
00460                 sum += data[i];
00461                 sum2 += data[i]*data[i];
00462                 n++;
00463             }
00464         }
00465     } else {
00466         n = 0;
00467         for (i = 0; i < npts; i++) {
00468             if (bpm[i] == 0 && data[i] > lcut && data[i] < hcut) {
00469                 sum += data[i];
00470                 sum2 += data[i]*data[i];
00471                 n++;
00472             }
00473         }
00474     }
00475 
00476     /* Check whether we can do the mean and sigma calculations */
00477 
00478     switch (n) {
00479     case 0:
00480         *mean = CX_MAXFLOAT;
00481         *sig = CX_MAXFLOAT;
00482         cpl_msg_warning(fctid,"All values flagged as bad\n");
00483         return(VIR_WARN);
00484     case 1:
00485         *mean = (float)sum;
00486         *sig = 0.0;
00487         return(VIR_OK);
00488     default:
00489         sum /= (double)n;
00490         *mean = (float)sum;
00491         sum2 = sum2/(double)n - sum*sum;
00492         *sig = (float)sqrt(max(1.0e-12,sum2));
00493         return(VIR_OK);
00494     }
00495 }
00496 
00497 /*---------------------------------------------------------------------------*/
00535 /*---------------------------------------------------------------------------*/
00536 
00537 extern void vircam_qmedsig(float *data, unsigned char *bpm, long npts,
00538                            float thresh, int niter, float lowv, float highv,
00539                            float *median, float *sigma) {
00540     int *histo,nbins,nhist,ilev,iclip,nhist2,halflev,quartlev;
00541     int irej,jst,j;
00542     long i;
00543     float mlev,qlev;
00544     unsigned char *b;
00545 
00546     /* Right, first thing is to histogram the data.  Cut values below
00547        and above the 'ceiling' values */
00548 
00549     if (bpm == NULL) 
00550         b = cpl_calloc(npts,sizeof(unsigned char));
00551     else
00552         b = bpm;
00553     nbins = vircam_nint(highv - lowv + 1.0);
00554     histo = cpl_calloc(nbins,sizeof(*histo));
00555     nhist = 0;
00556     for (i = 0; i < npts; i++) {
00557         if (b[i] || data[i] < lowv || data[i] > highv)
00558             continue;
00559         ilev = vircam_nint(data[i] - lowv);
00560         ilev = max(0,min(nbins-1,ilev));
00561         histo[ilev] += 1;
00562         nhist += 1;
00563     }
00564     if (bpm == NULL)
00565         freespace(b);
00566 
00567     /* Right, find the median value and the first quartile. */
00568 
00569     iclip = nbins - 1;
00570     nhist2 = nhist;
00571     for (i = 0; i <= niter; i++) {
00572         halflev = (nhist2 + 1)/2;
00573         quartlev = (nhist2 + 3)/4;
00574         mlev = histexam(histo,nbins,halflev);
00575         *median = mlev + lowv;
00576         qlev = histexam(histo,nbins,quartlev);
00577         *sigma = (mlev - qlev)*1.48;
00578         if (i == niter)
00579             break;
00580         irej = 0;
00581         jst = vircam_nint(mlev + thresh*(*sigma));
00582         for (j = jst; j <= iclip; j++)
00583             irej += histo[j];
00584         if (irej == 0)
00585             break;
00586         iclip = jst - 1;
00587         nhist2 -= irej;
00588     }
00589     cpl_free(histo);
00590 }
00591 
00592 /*---------------------------------------------------------------------------*/
00618 /*---------------------------------------------------------------------------*/
00619 
00620 extern void vircam_medmad(float *data, unsigned char *bpm, long np, float *med,
00621                           float *mad) {
00622     int i;
00623     float *work;
00624 
00625     /* First find the median value */
00626 
00627     *med = vircam_med(data,bpm,np);
00628 
00629     /* Now work out the MAD. Start by getting a bit of workspace and filling
00630        it with absolute residuals */
00631     
00632     work = cpl_malloc(np*sizeof(*work));
00633     for (i = 0; i < np; i++)
00634         work[i] = (float)fabs((double)(data[i] - *med));
00635 
00636     /* Now get the median value of the absolute deviations */
00637 
00638     *mad = vircam_med(work,bpm,np);
00639 
00640     /* Tidy and exit */
00641 
00642     cpl_free(work);
00643 }
00644 
00645 /*---------------------------------------------------------------------------*/
00677 /*---------------------------------------------------------------------------*/
00678 
00679 extern void vircam_medmadcut(float *data, unsigned char *bpm, long np, 
00680                              float lcut, float hcut, float *med, float *mad) {
00681     int i;
00682     float *work;
00683     unsigned char *bad;
00684 
00685     /* Get a workspace for the pseudo-bad pixel mask... */
00686 
00687     bad = cpl_calloc(np,sizeof(*bad));
00688     if (bpm != NULL) {
00689         for (i = 0; i < np; i++)
00690             if (bpm[i] != 0 || data[i] < lcut || data[i] > hcut)
00691                 bad[i] = 1;
00692     } else {
00693         for (i = 0; i < np; i++) 
00694             if (data[i] < lcut || data[i] > hcut)
00695                 bad[i] = 1;
00696     }
00697 
00698     /* First find the median value */
00699 
00700     *med = vircam_med(data,bad,np);
00701 
00702     /* Now work out the MAD. Start by getting a bit of workspace and filling
00703        it with absolute residuals */
00704     
00705     work = cpl_malloc(np*sizeof(*work));
00706     for (i = 0; i < np; i++)
00707         work[i] = (float)fabs((double)(data[i] - *med));
00708 
00709     /* Now get the median value of the absolute deviations */
00710 
00711     *mad = vircam_med(work,bad,np);
00712 
00713     /* Tidy and exit */
00714 
00715     cpl_free(work);
00716     cpl_free(bad);
00717 }
00718 
00719 /*---------------------------------------------------------------------------*/
00744 /*---------------------------------------------------------------------------*/
00745 
00746 extern void vircam_medsig(float *data, unsigned char *bpm, long np, float *med,
00747                           float *sig) {
00748     int i,n;
00749     float sum,resid;
00750 
00751     /* First find the median value */
00752 
00753     *med = vircam_med(data,bpm,np);
00754 
00755     /* If no bpm is present the just use them all */
00756 
00757     if (bpm == NULL) {
00758         sum = 0.0;
00759         for (i = 0; i < np; i++) {
00760             resid = data[i] - *med;
00761             sum += resid*resid;
00762         }
00763         *sig = sqrt(sum/(float)np);
00764 
00765     /* Otherwise test the bpm */
00766 
00767     } else {
00768         sum = 0.0;
00769         n = 0;
00770         for (i = 0; i < np; i++) {
00771             if (bpm[i] == 0) {
00772                 n++;
00773                 resid = data[i] - *med;
00774                 sum += resid*resid;
00775             }
00776         }
00777         if (n > 0) 
00778             *sig = sqrt(sum/(float)n);
00779         else
00780             *sig = 0.0;
00781     }
00782 }
00783 
00784 /*---------------------------------------------------------------------------*/
00806 /*---------------------------------------------------------------------------*/
00807 
00808 extern int vircam_sumbpm(unsigned char *bpm, int npts, int *sumb) {
00809     int j;
00810 
00811     *sumb = 0;
00812     for (j = 0; j < npts; j++)
00813         *sumb += bpm[j];
00814     return(VIR_OK);
00815 }
00816 
00819 static float histexam(int *histo, int nhist, int level) {
00820     int ilev,ii;
00821     float value;
00822 
00823     ii = 0;
00824     ilev = -1;
00825     while (ii < level && ilev < nhist-1)
00826         ii += histo[++ilev];
00827     value = (float)ilev - (float)(ii - level)/(float)histo[ilev] + 0.5;
00828     return(value);
00829 }
00830 
00831 /*
00832  * given an array a of n elements, return the element that would be at
00833  * position k, (0 <= k < n), if the array were sorted.  from Algorithms
00834  * and Data Structures in C++ by Leendert Ammeraal, pg. 82.  O(n).
00835  *
00836  * NB: partially reorders data in array
00837  */
00838 
00839 /* Stolen from C. Sabbey */
00840 
00841 
00842 static float kselect(float *a, int n, int k) {
00843     while (n > 1) {
00844         int i = 0, j = n - 1;
00845         float x = a[j/2], w;
00846 
00847         do {
00848             while (a[i] < x) i++;
00849             while (a[j] > x) j--;
00850             if (i < j) {
00851                 w = a[i]; a[i] = a[j]; a[j] = w;
00852             } else {
00853                 if (i == j) i++;
00854                 break;
00855             }
00856         } while (++i <= --j);
00857 
00858         if (k < i)
00859             n = i;
00860         else {
00861             a += i; n -= i; k -= i;
00862         }
00863     }
00864 
00865     return a[0];
00866 }
00867 
00868 static double dkselect(double *a, int n, int k) {
00869     while (n > 1) {
00870         int i = 0, j = n - 1;
00871         double x = a[j/2], w;
00872 
00873         do {
00874             while (a[i] < x) i++;
00875             while (a[j] > x) j--;
00876             if (i < j) {
00877                 w = a[i]; a[i] = a[j]; a[j] = w;
00878             } else {
00879                 if (i == j) i++;
00880                 break;
00881             }
00882         } while (++i <= --j);
00883 
00884         if (k < i)
00885             n = i;
00886         else {
00887             a += i; n -= i; k -= i;
00888         }
00889     }
00890 
00891     return a[0];
00892 }
00893 
00894 /*
00895 
00896 $Log: vircam_stats.c,v $
00897 Revision 1.16  2007/10/25 17:34:01  jim
00898 Modified to remove lint warnings
00899 
00900 Revision 1.15  2007/03/01 12:42:42  jim
00901 Modified slightly after code checking
00902 
00903 Revision 1.14  2007/02/06 11:59:17  jim
00904 Added vircam_medmadcut
00905 
00906 Revision 1.13  2006/12/19 13:29:06  jim
00907 Fixed medsig and medsigcut to take care of low number stats
00908 
00909 Revision 1.12  2006/09/08 09:22:19  jim
00910 Fixed vircam_qmedsig so that an input BPM could be NULL
00911 
00912 Revision 1.11  2006/06/06 13:06:48  jim
00913 Added vircam_medsig
00914 
00915 Revision 1.10  2006/05/26 19:33:29  jim
00916 Fixed a doc problem
00917 
00918 Revision 1.9  2006/05/24 13:36:48  jim
00919 Fixed warning message
00920 
00921 Revision 1.8  2006/05/08 14:53:16  jim
00922 Fixed problem negative variances by making sure that floats were cast to
00923 doubles properly
00924 
00925 Revision 1.6  2006/03/03 14:29:46  jim
00926 Modified definition of vir_fits and channel table
00927 
00928 Revision 1.5  2006/02/18 11:48:55  jim
00929 *** empty log message ***
00930 
00931 Revision 1.4  2006/01/23 10:30:49  jim
00932 Mainly documentation mods
00933 
00934 Revision 1.3  2005/12/14 22:17:33  jim
00935 Updated docs
00936 
00937 Revision 1.2  2005/10/14 13:19:13  jim
00938 Added vircam_medmad
00939 
00940 Revision 1.1.1.1  2005/08/05 08:29:09  jim
00941 Initial import
00942 
00943 
00944 */

Generated on Wed Apr 10 04:01:57 2013 for VIRCAM Pipeline by  doxygen 1.5.1