source: SH_SHM/trunk/source/recfiltr.c @ 374

Revision 16, 18.3 KB checked in by marcus, 15 years ago (diff)

r1 | svn | 2007-12-13 11:10:29 +0100 (Do, 13 Dez 2007) | 2 lines

Initial import

Line 
1
2/* file RECFILTR.C
3 *      ==========
4 *
5 * version 15, 1-Nov-2006
6 *  (corrected rf_filter_single since version 2)
7 *  (normalization error corrected in version 7, 2-Jun-92)
8 *  (startup error in rf_filter_single corrected in version 8, 21-Jan-94)
9 *  (removing of mean value on every stage since version 10, 26-Jan-94)
10 *  (filter dt == -1.0 allows all sample rates, 21-Jun-94)
11 *  very slow if input values are constant due to underflow exceptions
12 *     introduced constant sample counter, 5-Dec-2001
13 *
14 * recursive filtering of traces
15 * K. Stammler, 3-JUL-1990
16 */
17
18
19/*
20 *
21 *  SeismicHandler, seismic analysis software
22 *  Copyright (C) 1992,  Klaus Stammler, Federal Institute for Geosciences
23 *                                       and Natural Resources (BGR), Germany
24 *
25 *  This program is free software; you can redistribute it and/or modify
26 *  it under the terms of the GNU General Public License as published by
27 *  the Free Software Foundation; either version 2 of the License, or
28 *  (at your option) any later version.
29 *
30 *  This program is distributed in the hope that it will be useful,
31 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
32 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33 *  GNU General Public License for more details.
34 *
35 *  You should have received a copy of the GNU General Public License
36 *  along with this program; if not, write to the Free Software
37 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
38 *
39 */
40
41
42#include <stdio.h>
43#include <string.h>
44#include "basecnst.h"
45#ifdef BC_INC_STDLIB
46#include BC_INC_STDLIB
47#endif
48#include BC_SYSBASE
49#include "shconst.h"
50#include "shvars.h"
51#include "erusrdef.h"
52#include "numres.h"
53#include "rfusrdef.h"
54#include "flerrors.h"
55#include "globalparams.h"
56
57
58/* global constants */
59#define MAXDEGREE 15
60        /* maximum number of coefficients */
61#define FILMAGIC 1357913578L
62        /* magic number in filter files */
63#define FILID_COEFF 3
64        /* recursive filter file ID */
65#define FILTERMCH '@'
66        /* termination character between filters */
67#define FILCOMMENTCH '!'
68        /* comment character */
69#define FORALL_DT -1.0
70        /* dt in filter valid for all sample rates */
71#define PI 3.141592653
72        /* pi */
73
74/* filter type */
75typedef struct rf_coeff {
76        int       deg_input;        /* degree of input coefficients */
77        REAL      ic[MAXDEGREE];    /* input coefficients */
78        int       deg_output;       /* degree of output coefficients */
79        REAL      oc[MAXDEGREE];    /* output coefficients */
80        REAL      norm;             /* normalisation */
81        REAL      dt;               /* sample distance in sec */
82} RECFILTER;
83
84/* global variables */
85static RECFILTER    rfv_fct[RFC_MAXFILTER];   /* filter functions */
86static int          rfv_no_of_fil = 0;        /* number of filters */
87
88
89/* prototypes of local routines */
90void rf_readcoeff( FILE *f, int *no, REAL coeff[], int *status );
91void rf_read_filter( char *file, int pos, RECFILTER *filter, int *status );
92void rf_filter_single( RECFILTER *filter, RFT_STARTUP *startup,
93        REAL delta_t, long arrlth, SAMPLE in[], SAMPLE out[],
94        STATUS *status );
95static void rfh_demean( SAMPLE smp[], long lth );
96
97
98
99/*------------------------------------------------------------------------*/
100
101
102
103void rf_filter_input( int list_lth, char *flt_list[], int pos_list[],
104        int *status )
105
106/* reads one or more filters into memory
107 *
108 * paramters of routine
109 * int       list_lth;       input; number of filters to read
110 * char      *flt_list[];    input; list of filter names
111 * int       pos_list[];     input; positions of filters in files
112 * int       *status;        output; return status
113 */
114{
115        /* local variables */
116        int      i;        /* counter */
117        int      f;        /* filter counter */
118        int      pos;      /* position in file */
119
120        /* executable code */
121
122        if  (list_lth > RFC_MAXFILTER)  {
123                *status = FLE_TOOMANY;
124                err_setcontext( " ## number " ); err_setcontext_l( list_lth );
125                return;
126        } /*endif*/
127
128        f = 0;
129        for  (i=0;i<list_lth;i++)  {
130                if  (pos_list[i] == 0)  {   /* read all filters of file */
131                        pos = 1;
132                        *status = FLE_NOERROR;
133                        while  (*status == FLE_NOERROR)  {
134                                if  (f == RFC_MAXFILTER)  {
135                                        rfv_no_of_fil = RFC_MAXFILTER;
136                                        *status = FLE_TOOMANY;
137                                        return;
138                                } /*endif*/
139                                rf_read_filter( flt_list[i], pos++, rfv_fct+f, status );
140                                if  (*status == FLE_NOERROR)  f++;
141                        } /*endwhile*/
142                        if (*status == FLE_EOFF)  *status = FLE_NOERROR;
143                } else {
144                        rf_read_filter( flt_list[i], pos_list[i], rfv_fct+f, status );
145                        if  (*status == FLE_NOERROR)  f++;
146                } /*endif*/
147                if  (*status != FLE_NOERROR)  return;
148        } /*endfor*/
149
150        rfv_no_of_fil = f;
151
152} /* end of rf_filter_input */
153
154
155
156/*------------------------------------------------------------------------*/
157
158
159
160void rf_read_filter( char *file, int pos, RECFILTER *filter, int *status )
161
162/* reads single filter from file "file" at position "pos".  Negative
163 * position means that filter is inverted after reading
164 *
165 * parameters of routine
166 * char       *file;      input; name of filter file
167 * int        pos;        input; position number (negative = invert)
168 * RECFILTER  *filter;    output; filter read from file
169 * int        *status;    output; return status
170 */
171{
172        /* local variables */
173        FILE     *f;       /* filter file pointer */
174        char     *filpath; /* pointer to filter path */
175        int      pathcnt;  /* path counter */
176        int      i;        /* counter */
177        int      id;       /* store ID */
178        long     magic;    /* magic longword */
179        char     str[BC_LONGSTRLTH+1];  /* scratch */
180        REAL     b0;       /* normalisation */
181
182        /* executable code */
183
184        /* open file */
185        f = NULL;
186        for  (pathcnt=0;;pathcnt++)  {
187                filpath = GpGetStringElem( cGpL_defpath_filter, pathcnt );
188                if  (filpath == NULL)  break;
189                if  ((strlen(str)+strlen(filpath)+1) > BC_LONGSTRLTH)  {
190                        *status = FLE_STROVFL;
191                        err_setcontext( " ## filename too long" );
192                        return;
193                } /*endif*/
194                strcpy( str, filpath );
195                strcat( str, "/" );
196                strcat( str, file );
197                strcat( str, SHC_DE_RFILT );
198                f = sy_fopen( str, "r" );
199                if  (f != NULL)  break;
200        } /*endfor*/
201        if  (f == NULL)  {
202                *status = FLE_OPNREAD;
203                err_setcontext( " ## file " ); err_setcontext( str );
204                return;
205        } /*endif*/
206
207        /* read off comments */
208        do  {
209                if  (fgets(str,BC_LONGSTRLTH,f) == NULL)  {
210                        *status = FLE_EOFF; fclose( f ); return;
211                } /*endif*/
212        } while (*str == FILCOMMENTCH);
213
214        /* read magic longword */
215        i = sscanf( str, "%ld\n", &magic );
216        if  ((i != 1) || (magic != FILMAGIC))  {
217                *status = FLE_NOMAGIC; fclose( f ); return;
218        } /*endif*/
219
220        /* count position */
221        for  (i=2;i<=Abs(pos);i++)  {
222                do  {
223                        if  (fgets(str,BC_LONGSTRLTH,f) == NULL)  {
224                                *status = FLE_EOFF; fclose( f ); return;
225                        } /*endif*/
226                } while (*str != FILTERMCH);
227        } /*endfor*/
228
229        /* check store ID */
230        i = fscanf( f, "%d\n", &id );
231        if  ((i != 1) || (id != FILID_COEFF))  {
232                *status = FLE_NORECFIL; fclose( f ); return;
233        } /*endif*/
234
235        /* read sample distance */
236        if  (fscanf( f, "%e\n", &(filter->dt) ) != 1)  {
237                *status = FLE_FREAD; fclose( f ); return;
238        } /*endif*/
239
240        /* read normalisation */
241        if  (fscanf( f, "%e\n", &(filter->norm) ) != 1)  {
242                *status = FLE_FREAD; fclose( f ); return;
243        } /*endif*/
244
245        /* read input (output) coefficients */
246        if  (pos > 0)  {
247                rf_readcoeff( f, &(filter->deg_input), filter->ic, status );
248                if  (*status != FLE_NOERROR)  return;
249                rf_readcoeff( f, &(filter->deg_output), filter->oc, status );
250                if  (*status != FLE_NOERROR)  return;
251        } else {
252                rf_readcoeff( f, &(filter->deg_output), filter->oc, status );
253                if  (*status != FLE_NOERROR)  return;
254                rf_readcoeff( f, &(filter->deg_input), filter->ic, status );
255                if  (*status != FLE_NOERROR)  return;
256        } /*endif*/
257
258        fclose( f );
259
260        /* divide all coefficients by b[0] */
261        if  (filter->oc[0] != 1.0)  {
262                b0 = filter->oc[0];
263                filter->oc[0] = 1.0;
264                for  (i=0;i<filter->deg_input;i++)
265                        filter->ic[i] /= b0;
266                for  (i=1;i<filter->deg_output;i++)
267                        filter->oc[i] /= b0;
268        } /*endif*/
269
270} /* end of rf_read_filter */
271
272
273
274
275/*------------------------------------------------------------------------*/
276
277
278
279void rf_readcoeff( FILE *f, int *no, REAL coeff[], int *status )
280
281/* read coefficients from file
282 *
283 * parameters of routine
284 * FILE       *f;       input; file pointer
285 * int        *no;      output; number of coefficients
286 * REAL       coeff[];  output; coefficients read
287 * int        *status;  output; return status
288 */
289{
290        /* local variables */
291        int      i;        /* counter */
292
293        /* executable code */
294
295        if  (fscanf( f, "%d,\n", no ) != 1)  {
296                *status = FLE_FREAD; fclose( f ); return;
297        } /*endif*/
298        if  (*no > MAXDEGREE)  {
299                *status = FLE_DEGOVFL; fclose( f ); return;
300        } /*endif*/
301        for  ( i = 0; i < *no; i++ )  {
302                if  (fscanf( f, "%e\n", coeff+i ) != 1)  {
303                        *status = FLE_FREAD; fclose( f ); return;
304                } /*endif*/
305        } /*endfor*/
306
307} /* end of rf_readcoeff */
308
309
310
311/*------------------------------------------------------------------------*/
312
313
314
315void rf_filter( SAMPLE src[], long trclth, REAL dt, RFT_STARTUP *lpc,
316        SAMPLE dst[], STATUS *status )
317
318/* filters the seismogram "src" from index "start" to index "end"
319 * with all the filters in rfv_fct.  The result is returned in "dst"
320 *
321 * parameters of routine
322 * SAMPLE     src[];     input; input signal to be filtered
323 * long       trclth;    input length of trace in samples
324 * REAL       dt;        input; sample distance in sec
325 * RFT_STARTUP *lpc;     input; use special startup routine
326 * SAMPLE     dst[];     output; output signal
327 * STATUS     *status;   output; return status
328 */
329{
330        /* local variables */
331        SAMPLE   *work;        /* pointer to workspace */
332        int      i;            /* counter */
333
334        /* executable code */
335
336        if  (trclth <= 0)  {
337                *status = FLE_ZEROLTH;
338                return;
339        } else if  (rfv_no_of_fil <= 0)  {
340                *status = FLE_NOFILTER;
341                return;
342        } /*endif*/
343
344        if  (rfv_no_of_fil == 1)  {  /* only one filter */
345
346                rf_filter_single( rfv_fct, lpc, dt, trclth, src, dst, status );
347
348        } else {
349
350                /* allocate memory */
351                work = (SAMPLE *)sy_allocmem( trclth, (int)sizeof(SAMPLE), status );
352                if  (*status != FLE_NOERROR)  return;
353
354                if  ((rfv_no_of_fil % 2) == 0)  {  /* even number of filters */
355                        /* first output trace is workspace */
356                        rf_filter_single( rfv_fct, lpc, dt, trclth, src, work, status );
357                        if  (Severe(status))  {sy_deallocmem( work ); return;}
358                        if  (lpc->demean)  rfh_demean( work, trclth );
359                        for  ( i = 1; i <= (rfv_no_of_fil/2)-1; i++ )  {
360                                rf_filter_single( rfv_fct+(2*i-1), lpc, dt, trclth, work, dst,
361                                        status );
362                                if  (Severe(status))  {sy_deallocmem( work ); return;}
363                                if  (lpc->demean)  rfh_demean( dst, trclth );
364                                rf_filter_single( rfv_fct+(2*i), lpc, dt, trclth, dst, work,
365                                        status );
366                                if  (Severe(status))  {sy_deallocmem( work ); return;}
367                                if  (lpc->demean)  rfh_demean( work, trclth );
368                        } /*endfor*/
369                } else {   /* odd number of filters */
370                        /* first output is dst */
371                        rf_filter_single( rfv_fct, lpc, dt, trclth, src, dst, status );
372                        if  (Severe(status))  {sy_deallocmem( work ); return;}
373                        if  (lpc->demean)  rfh_demean( dst, trclth );
374                        rf_filter_single( rfv_fct+1, lpc, dt, trclth, dst, work, status );
375                        if  (Severe(status))  {sy_deallocmem( work ); return;}
376                        if  (lpc->demean)  rfh_demean( work, trclth );
377                        for  ( i = 1; i <= ((rfv_no_of_fil-1)/2)-1; i++ )  {
378                                rf_filter_single( rfv_fct+(2*i), lpc, dt, trclth, work, dst,
379                                        status );
380                                if  (Severe(status))  {sy_deallocmem( work ); return;}
381                                if  (lpc->demean)  rfh_demean( dst, trclth );
382                                rf_filter_single( rfv_fct+(2*i+1), lpc, dt, trclth, dst, work,
383                                        status );
384                                if  (Severe(status))  {sy_deallocmem( work ); return;}
385                                if  (lpc->demean)  rfh_demean( work, trclth );
386                        } /*endfor*/
387                } /*endif*/
388
389                rf_filter_single( rfv_fct+rfv_no_of_fil-1, lpc, dt, trclth, work, dst,
390                        status );
391
392                /* deallocate memory */
393                sy_deallocmem( work );
394
395        } /*endif*/
396
397} /* end of rf_filter */
398
399
400
401/*------------------------------------------------------------------------*/
402
403
404
405void rf_filter_single( RECFILTER *filter, RFT_STARTUP *startup,
406        REAL delta_t, long arrlth,      SAMPLE in[], SAMPLE out[],
407        STATUS *status )
408
409/* traces are filtered using following formula
410 * r[n] = a[0]*f[n] + a[1]*f[n-1] + ... + a[k]*f[n-k] -
411 *        b[1]*r[n-1] - b[2]*r[n-2] - ... - b[l]*r[n-l]
412 *
413 * where
414 *   f[n]   input signal at time n*dt  (dt = sample distance)
415 *   r[n]   output signal at time n*dt
416 *   a[i]   coefficients of numerator polynomial of z-transform of filter
417 *   b[i]   coefficients of denominator polynomial of z-transform of filter
418 *
419 * these variables are represented in the routine by
420 *   k     =  filter->deg_input - 1
421 *   a[i]  =  filter->ic[i]
422 *   l     =  filter->deg_output - 1
423 *   b[i]  =  filter->oc[i]
424 *   f[n]  =  in[n]
425 *   r[n]  =  out[n]
426 *
427 * The startup procedure is described in "startup".  If
428 * startup->use_lpc is FALSE then ordinary startup is executed.  That is
429 * all unknown values (indices smaller than 0) are set to zero.
430 * To decrease ringing of filtered trace the unknown trace values
431 * with indices < 0 are guessed by a prediction backwards in time
432 * (startup->use_lpc == TRUE).  The startup->pred_length specifies
433 * the prediction length in samples, startup->pred_order the order
434 * of the spectral estimation function (maximum entropy method) and
435 * startup->src_length gives the number of samples used as input
436 * for spectral estimation.
437 *
438 * If the input trace has constant values underflow exception occur
439 * and slow down speed considerably (on zero-sum filter coefficients).
440 * Introduced constant sample counter 5-Dec-2001. K.S.
441 *
442 *
443 * parameters of routine
444 * RECFILTER  *filter;    input; filter to be applied to "in"
445 * RFT_STARTUP *startup;  input; startup procedure
446 * REAL       delta_t;    input; sample distance of input trace in seconds
447 * long       arrlth;     input; length of input (and output) trace
448 * SAMPLE     in[];       modify; input signal
449 * SAMPLE     out[];      output; output signal
450 * int        *status;    output; return status
451 */
452{
453        /* local variables */
454        REAL     r;        /* scratch */
455        long     init;     /* index limit of start procedure */
456        long     n;        /* sample counter */
457        long     index;    /* scratch index */
458        int      i;        /* coeff counter */
459        SAMPLE   constval; /* constant value */
460        int      constcnt; /* constant value counter */
461        /* lpc variables */
462        float    dummy;    /* scratch */
463        float    *mc;             /* poles for approximation */
464        SAMPLE   *prd;            /* backward predicted values */
465        SAMPLE   *fprd;           /* filtered predicted values */
466        SAMPLE   *strt;           /* input for prediction */
467
468        /* executable code */
469
470        r = Abs( delta_t - filter->dt) * 100.0;
471        if  (filter->dt != FORALL_DT && r > delta_t)  {
472                *status = FLE_DTMISMCH;
473                return;
474        } /*endif*/
475
476        init = (long)filter->deg_input - 1;
477        if  ((filter->deg_output-1) > init)  init = filter->deg_output-1;
478
479        /* start procedure */
480        if  (startup->use_lpc)  {
481                /* check parameters */
482                if  (startup->src_length < 2 || startup->src_length > arrlth)  {
483                        *status = FLE_STARTUP;
484                        return;
485                } else if  (startup->pred_length < 0)  {
486                        *status = FLE_STARTUP;
487                        return;
488                } else if  (startup->pred_order < 1 || startup->pred_order > 100)  {
489                        *status = FLE_STARTUP;
490                        return;
491                } /*endif*/
492                /* get memory */
493                prd = (SAMPLE *)sy_allocmem(
494                        2*(MAXDEGREE+(startup->pred_length)) + startup->src_length,
495                        (int)sizeof(SAMPLE), status );
496                if  (Severe(status))  return;
497                fprd = prd + MAXDEGREE + startup->pred_length;
498                strt = fprd + MAXDEGREE + startup->pred_length;
499                mc = (float *)sy_allocmem( startup->pred_order,
500                        (int)sizeof(float), status );
501                if  (Severe(status))  {sy_deallocmem( prd );return;}
502                /* copy reversed input array */
503                for  (i=0; i<(startup->src_length); i++)
504                        strt[i] = in[(startup->src_length)-1-i];
505                /* compute poles */
506                nr_memcof( strt-1, startup->src_length, startup->pred_order,
507                        &dummy, mc-1 );
508                /* predict previous values */
509                nr_predic( strt-1, startup->src_length, mc-1, startup->pred_order,
510                        prd-1, (int)init+(startup->pred_length)+1 );
511                /* copy start values to filtered predicted values */
512                for  (i=(startup->pred_length)+(int)init;
513                        i>(startup->pred_length); i--)
514                        fprd[i] = prd[i];
515                /* do startup */
516                for  (n= -(startup->pred_length); n<init; n++)  {
517                        if  (n > arrlth)  return;
518                        r = 0.0;
519                        for  (i=0; i<filter->deg_input; i++ )  {
520                                index = n - i;
521                                if  (index >= 0)  {
522                                        r += filter->ic[i]*in[index];
523                                } else {
524                                        r += filter->ic[i]*prd[-index];
525                                } /*endif*/
526                        } /*endfor*/
527                        for  (i=1; i<filter->deg_output; i++ )  {
528                                index = n - i;
529                                if  (index >= 0)  {
530                                        r -= filter->oc[i]*out[index];
531                                } else {
532                                        r -= filter->oc[i]*fprd[-index];
533                                } /*endif*/
534                        } /*endfor*/
535                        if  (n >= 0)  {
536                                out[n] = r;
537                        } else {
538                                fprd[-n] = r;
539                        } /*endif*/
540                } /*endfor*/
541                sy_deallocmem( prd );
542                sy_deallocmem( mc );
543        } else {
544                /* start procedure */
545                out[0] = in[0]; /*(in[1] - in[0]) / delta_t;*/
546                for  (n=1; n<init; n++)  {
547                        if  (n > arrlth)  return;
548                        r = 0.0;
549                        for  (i=0; i<filter->deg_input; i++ )  {
550                                index = n - i;
551                                if  (index >= 0)  r += filter->ic[i]*in[index];
552                        } /*endfor*/
553                        for  (i=1; i<filter->deg_output; i++ )  {
554                                index = n - i;
555                                if  (index >= 0)  r -= filter->oc[i]*out[index];
556                        } /*endfor*/
557                        out[n] = r;
558                } /*endfor*/
559        } /*endif*/
560
561        constcnt = 0;
562        constval = 0.0;
563
564        /* now like in above formula */
565        for  (n=init; n<arrlth; n++ )  {
566                /* first check for constant input values */
567                if  (in[n] == constval)  {
568                        constcnt++;
569                } else {
570                        constcnt = 0;
571                        constval = in[n];
572                } /*endif*/
573                /* if input values are const. assign 0 to output otherwise apply formula*/
574                if  (constcnt < 50)  {
575                        r = 0.0;
576                        for  (i=0; i<filter->deg_input; i++ )
577                                r += filter->ic[i]*in[n-i];
578                        for  (i=1; i<filter->deg_output; i++ ) /* before version 2: */
579                                r -= filter->oc[i]*out[n-i];        /* for (i=0; i<...   */
580                        out[n] = r;
581                } else {
582                        out[n] = 0.0;
583                } /*endif*/
584                if  (!(n&0x3))  sy_sharecpu();
585        } /*endfor*/
586
587        if  (filter->norm != 1.0)
588                for  (n=0; n<arrlth; out[n++] *= filter->norm ) {}
589
590} /* end of rf_filter_single */
591
592
593
594/*------------------------------------------------------------------------*/
595
596
597
598static void rfh_demean( SAMPLE smp[], long lth )
599
600/* removes mean value from trace
601 *
602 * parameters of routine
603 * REAL       smp[];      modify; trace to remove mean value
604 * long       lth;        input; length of trace
605 */
606{
607        /* local variables */
608        SAMPLE   mean;       /* mean value */
609        SAMPLE   *s;         /* moving pointer */
610
611        /* executable code */
612
613        mean = 0.0;
614        for  (s=smp; s<(smp+lth); mean += *s++) {}
615        mean /= (float)lth;
616        for  (s=smp; s<(smp+lth); s++)  {*s -= mean;}
617
618} /* end of rfh_demean */
619
620
621
622/*------------------------------------------------------------------------*/
Note: See TracBrowser for help on using the repository browser.