LAL 7.6.1.1-4859cae
CreateIIRFilter.c
Go to the documentation of this file.
1/*
2* Copyright (C) 2007 Jolien Creighton, Teviet Creighton
3*
4* This program is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License as published by
6* the Free Software Foundation; either version 2 of the License, or
7* (at your option) any later version.
8*
9* This program is distributed in the hope that it will be useful,
10* but WITHOUT ANY WARRANTY; without even the implied warranty of
11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12* GNU General Public License for more details.
13*
14* You should have received a copy of the GNU General Public License
15* along with with program; see the file COPYING. If not, write to the
16* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17* MA 02110-1301 USA
18*/
19
20#include <complex.h>
21#include <lal/LALStdlib.h>
22#include <lal/LALConstants.h>
23#include <lal/AVFactories.h>
24#include <math.h>
25#include <lal/IIRFilter.h>
26
27/**
28 * \addtogroup CreateIIRFilter_c
29 * \author Creighton, T. D.
30 *
31 * \brief Creates IIR filter objects.
32 *
33 * ### Description ###
34 *
35 * These functions create an object <tt>**output</tt> of type
36 * <tt><datatype>IIRFilter</tt>, where <tt><datatype></tt> is \c REAL4 or
37 * \c REAL8. The filter coefficients are computed from the zeroes,
38 * poles, and gain of an input object <tt>*input</tt> of type
39 * \c COMPLEX8ZPGFilter or \c COMPLEX16ZPGFilter, respectively;
40 * the sampling time interval is taken directly from
41 * <tt>input->deltaT</tt>. The ZPG filter should express the factored
42 * transfer function in the \f$z=\exp(2\pi if)\f$ plane. Initially the
43 * output handle must be a valid handle (\c output\f$\neq\f$\c NULL)
44 * but should not point to an existing object
45 * (<tt>*output</tt>=\c NULL)
46 *
47 * ### Algorithm ###
48 *
49 * An IIR filter is a real time-domain filter, which imposes certain
50 * constraints on the zeros, poles, and gain of the filter transfer
51 * function. The function <tt>Create<datatype>IIRFilter()</tt> deals with
52 * the constraints either by aborting if they are not met, or by
53 * adjusting the filter response so that they are met. In the latter
54 * case, warning messages will be issued if the external parameter
55 * \c lalDebugLevel is set to allow such messages. The specific
56 * constraints, and how they are dealt with, are as follows:
57 *
58 * First, the filter must be \e causal; that is, the output at any
59 * time can be generated entirely from the input at previous times. In
60 * practice this means that the number of (finite) poles in the \f$z\f$ plane
61 * must equal or exceed the number of (finite) zeros. If this is not the
62 * case, <tt>Create<datatype>IIRFilter()</tt> will add additional poles at
63 * \f$z=0\f$. Effectively this is just adding a delay to the filter response
64 * in order to make it causal.
65 *
66 * Second, the filter should be \e stable, which means that all poles
67 * should be located on or within the circle \f$|z|=1\f$. This is not
68 * enforced by <tt>Create<datatype>IIRFilter()</tt>, which can be used to
69 * make unstable filters; however, warnings will be issued. (In some
70 * sense the first condition is a special case of this one, since a
71 * transfer function with more zeros than poles actually has
72 * corresponding poles at infinity.)
73 *
74 * Third, the filter must be <em>physically realizable</em>; that is, the
75 * transfer function should expand to a rational function of \f$z\f$ with
76 * real coefficients. Necessary and sufficient conditions for this are
77 * that the gain be real, and that all zeros and poles either be real or
78 * come in complex conjugate pairs. The routine
79 * <tt>Create<datatype>IIRFilter()</tt> enforces this by using only the
80 * real part of the gain, and only the real or positive-imaginary zeros
81 * and poles; it assumes that the latter are paired with
82 * negative-imaginary conjugates. The routine will abort if this
83 * assumption results in a change in the given number of zeros or poles.
84 * If \c lalDebugLevel is set to allow warnings, the routine will
85 * actually check to see that each pair of nonreal poles or zeros are in
86 * fact complex conjugates, and will issue a warning if an unmatched pair
87 * is detected; however, the algorithm will then simply proceed as if the
88 * negative-imaginary points were relocated to the "correct" positions.
89 *
90 * The code associated with the warning messages is potentially rather
91 * cumbersome for production algorithms; therefore, the value of
92 * \c lalDebugLevel is tested before performing any other tests
93 * associated with warning messages.
94 *
95 */
96/** @{ */
97
98/** \see See \ref CreateIIRFilter_c for documentation */
100{
102 INT4 i; /* Index counter for zeros and poles. */
103 INT4 numZeros; /* The number of zeros. */
104 INT4 numPoles; /* The number of poles. */
105 INT4 numDirect; /* The number of direct filter coefficients. */
106 INT4 numRecurs; /* The number of recursive filter coefficients. */
107 INT4 num; /* An extra counter for error checking. */
108 COMPLEX8 *zeros; /* The zeros of the transfer function. */
109 COMPLEX8 *poles; /* The poles of the transfer function. */
110 REAL4 *direct; /* The direct filter coefficients. */
111 REAL4 *recurs; /* The recursive filter coefficients. */
112 REAL4 *history; /* The filter history. */
113
114 /* Make sure all the input structures have been initialized. */
115 if ( ! input )
117 if ( ! input->zeros || ! input->poles
118 || ! input->zeros->data || ! input->poles->data )
120
121 numZeros=input->zeros->length;
122 numPoles=input->poles->length;
123 zeros=input->zeros->data;
124 poles=input->poles->data;
125
126 /* Check that zeros are appropriately paired. Also, keep track of
127 the number of zeros at z=0, since these will reduce the number of
128 direct coefficients required. */
129 numDirect=1;
130 for(i=0,num=0;i<numZeros;i++)
131 if(cimagf(zeros[i])==0.0){
132 num+=1;
133 if(crealf(zeros[i])==0.0)
134 numDirect-=1;
135 }
136 else if(cimagf(zeros[i])>0.0){
137 num+=2;
138
140 /* Check to see that another zero is an actual conjugate.
141 This is not a foolproof test, as it can be fooled by
142 multiple zeros at the same location. */
143 INT4 j=0;
144 INT4 k=0;
145 REAL4 x = crealf(zeros[i]) - crealf(zeros[0]);
146 REAL4 y = cimagf(zeros[i]) + cimagf(zeros[0]);
147 REAL4 sep = x*x + y*y;
148 for(j=1;j<numZeros;j++){
149 x=crealf(zeros[i])-crealf(zeros[j]);
150 y=cimagf(zeros[i])+cimagf(zeros[j]);
151 if(sep>x*x+y*y){
152 sep=x*x+y*y;
153 k=j;
154 }
155 }
156 if(sep>LAL_REAL4_EPS){
157 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
158 XLALPrintWarning("Complex zero has no conjugate pair\n");
159 XLALPrintWarning("\tUnmatched zero z_%i = %.8e + i*%.8e\n",i,
160 crealf(zeros[i]),cimagf(zeros[i]));
161 XLALPrintWarning("\tNearest pair z_%i = %.8e + i*%.8e\n",k,
162 crealf(zeros[k]),cimagf(zeros[k]));
163 }
164 }
165 }
166
167 if ( num != numZeros )
169
170 /* Check that poles are appropriately paired. Also, keep track of
171 the number of poles at z=0, since these will reduce the number of
172 recursive coefficients required. */
173 numRecurs=1;
174 for(i=0,num=0;i<numPoles;i++)
175 if(cimagf(poles[i])==0.0){
176 num+=1;
177 if(crealf(poles[i])==0.0)
178 numRecurs-=1;
179 }
180 else if(cimagf(poles[i])>0.0){
181 num+=2;
182
184 /* Check to see that another pole is an actual conjugate.
185 This is not a foolproof test, as it can be fooled by
186 multiple poles at the same location. */
187 INT4 j=0;
188 INT4 k=0;
189 REAL4 x = crealf(poles[i]) - crealf(poles[0]);
190 REAL4 y = cimagf(poles[i]) + cimagf(poles[0]);
191 REAL4 sep = x*x + y*y;
192 for(j=1;j<numPoles;j++){
193 x=crealf(poles[i])-crealf(poles[j]);
194 y=cimagf(poles[i])+cimagf(poles[j]);
195 if(sep>x*x+y*y){
196 sep=x*x+y*y;
197 k=j;
198 }
199 }
200 if(sep>LAL_REAL4_EPS){
201 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
202 XLALPrintWarning("Complex pole has no conjugate pair\n");
203 XLALPrintWarning("\tUnmatched pole p_%i = %.8e + i*%.8e\n",i,
204 crealf(poles[i]),cimagf(poles[i]));
205 XLALPrintWarning("\tNearest pair p_%i = %.8e + i*%.8e\n",k,
206 crealf(poles[k]),cimagf(poles[k]));
207 }
208 }
209 }
210
211 if ( num != numPoles )
213
215 /* Issue a warning if the gain is nonreal. */
216 if(fabs(cimag(input->gain))>fabs(LAL_REAL4_EPS*creal(input->gain))){
217 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
218 XLALPrintWarning("Gain is non-real\n");
219 XLALPrintWarning("\tg = %.8e + i*%.8e\n", crealf(input->gain), cimagf(input->gain));
220 }
221 /* Issue a warning if there are any ``removeable'' poles. */
222 for(i=0;i<numPoles;i++){
223 INT4 j=0;
224 for(;j<numZeros;j++)
225 if((crealf(poles[i])==crealf(zeros[j]))&&(cimagf(poles[i])==cimagf(zeros[j]))){
226 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
227 XLALPrintWarning("Removeable pole\n");
228 XLALPrintWarning("\tp_%i = z_%i = %.8e + i*%.8e\n",i,j,
229 crealf(poles[i]),cimagf(poles[i]));
230 }
231 }
232 /* Issue a warning if extra factors of 1/z will be applied. */
233 if(numPoles<numZeros){
234 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
235 XLALPrintWarning("Filter has more zeros than poles\n");
236 XLALPrintWarning("\t%i poles added at complex origin\n",
237 numZeros-numPoles);
238 }
239 /* Issue a warning if any poles are outside |z|=1. */
240 for(i=0;i<numPoles;i++){
241 REAL4 zAbs=crealf(poles[i])*crealf(poles[i])+cimagf(poles[i])*cimagf(poles[i]);
242 if(zAbs>1.0){
243 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
244 XLALPrintWarning("Filter has pole outside of unit circle\n");
245 XLALPrintWarning("\tp_%i = %.8e + i*%.8e, |p_%i| = %.8e\n",i,
246 crealf(poles[i]),cimagf(poles[i]),i,zAbs);
247 }
248 }
249 }
250
251 /* Everything seems okay, so initialize the filter. */
252 output=LALCalloc(1,sizeof(*output));
253 if ( ! output )
255 num = (numPoles>=numZeros) ? numZeros : numPoles;
256 numDirect+=num;
257 numRecurs+=num;
258
259 output->deltaT=input->deltaT;
260 output->directCoef = XLALCreateREAL4Vector( numDirect );
261 output->recursCoef = XLALCreateREAL4Vector( numRecurs );
262 if ( ! output->directCoef || ! output->recursCoef )
263 {
266 }
267 direct=output->directCoef->data;
268 recurs=output->recursCoef->data;
269
270 /* Expand the denominator as a polynomial in z. */
271 *recurs=-1.0;
272 for(i=1;i<numRecurs;i++)
273 recurs[i]=0.0;
274 for(i=0;i<numPoles;i++){
275 INT4 j=numRecurs-1;
276 REAL4 x=crealf(poles[i]);
277 REAL4 y=cimagf(poles[i]);
278 if(y==0.0)
279 for(;j>0;j--)
280 recurs[j]-=x*recurs[j-1];
281 else if(y>0.0){
282 for(;j>1;j--)
283 recurs[j]-=2.0*x*recurs[j-1]-(x*x+y*y)*recurs[j-2];
284 recurs[j]-=2.0*x*recurs[j-1];
285 }
286 }
287
288 /* Expand the numerator as a polynomial in z. */
289 for(i=0;i<numDirect;i++)
290 direct[i]=0.0;
291 direct[num-numZeros]=crealf(input->gain);
292 for(i=0;i<numZeros;i++){
293 INT4 j=numDirect-1;
294 REAL4 x=crealf(zeros[i]);
295 REAL4 y=cimagf(zeros[i]);
296 if(y==0.0)
297 for(;j>num-numZeros;j--)
298 direct[j]-=x*direct[j-1];
299 else if(y>0.0){
300 for(;j>num-numZeros+1;j--)
301 direct[j]-=2.0*x*direct[j-1]-(x*x+y*y)*direct[j-2];
302 direct[j]-=2.0*x*direct[j-1];
303 }
304 }
305
306 /* Initialize filter history. */
307 if(numDirect>=numRecurs)
308 num=numDirect-1;
309 else
310 num=numRecurs-1;
311 output->history = XLALCreateREAL4Vector( numRecurs );
312 if ( ! output->history )
313 {
316 }
317 history=output->history->data;
318 for(i=0;i<num;i++)
319 history[i]=0.0;
320
321 /* Normal exit */
322 return output;
323}
324
325/** \see See \ref CreateIIRFilter_c for documentation */
327{
329 INT4 i; /* Index counter for zeros and poles. */
330 INT4 numZeros; /* The number of zeros. */
331 INT4 numPoles; /* The number of poles. */
332 INT4 numDirect; /* The number of direct filter coefficients. */
333 INT4 numRecurs; /* The number of recursive filter coefficients. */
334 INT4 num; /* An extra counter for error checking. */
335 COMPLEX16 *zeros; /* The zeros of the transfer function. */
336 COMPLEX16 *poles; /* The poles of the transfer function. */
337 REAL8 *direct; /* The direct filter coefficients. */
338 REAL8 *recurs; /* The recursive filter coefficients. */
339 REAL8 *history; /* The filter history. */
340
341 /* Make sure all the input structures have been initialized. */
342 if ( ! input )
344 if ( ! input->zeros || ! input->poles
345 || ! input->zeros->data || ! input->poles->data )
347
348 numZeros=input->zeros->length;
349 numPoles=input->poles->length;
350 zeros=input->zeros->data;
351 poles=input->poles->data;
352
353 /* Check that zeros are appropriately paired. Also, keep track of
354 the number of zeros at z=0, since these will reduce the number of
355 direct coefficients required. */
356 numDirect=1;
357 for(i=0,num=0;i<numZeros;i++)
358 if(cimag(zeros[i])==0.0){
359 num+=1;
360 if(creal(zeros[i])==0.0)
361 numDirect-=1;
362 }
363 else if(cimag(zeros[i])>0.0){
364 num+=2;
365
367 /* Check to see that another zero is an actual conjugate.
368 This is not a foolproof test, as it can be fooled by
369 multiple zeros at the same location. */
370 INT4 j=0;
371 INT4 k=0;
372 REAL8 x = creal(zeros[i]) - creal(zeros[0]);
373 REAL8 y = cimag(zeros[i]) + cimag(zeros[0]);
374 REAL8 sep = x*x + y*y;
375 for(j=1;j<numZeros;j++){
376 x=creal(zeros[i])-creal(zeros[j]);
377 y=cimag(zeros[i])+cimag(zeros[j]);
378 if(sep>x*x+y*y){
379 sep=x*x+y*y;
380 k=j;
381 }
382 }
383 if(sep>LAL_REAL8_EPS){
384 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
385 XLALPrintWarning("Complex zero has no conjugate pair\n");
386 XLALPrintWarning("\tUnmatched zero z_%i = %.8e + i*%.8e\n",i,
387 creal(zeros[i]),cimag(zeros[i]));
388 XLALPrintWarning("\tNearest pair z_%i = %.8e + i*%.8e\n",k,
389 creal(zeros[k]),cimag(zeros[k]));
390 }
391 }
392 }
393
394 if ( num != numZeros )
396
397 /* Check that poles are appropriately paired. Also, keep track of
398 the number of poles at z=0, since these will reduce the number of
399 recursive coefficients required. */
400 numRecurs=1;
401 for(i=0,num=0;i<numPoles;i++)
402 if(cimag(poles[i])==0.0){
403 num+=1;
404 if(creal(poles[i])==0.0)
405 numRecurs-=1;
406 }
407 else if(cimag(poles[i])>0.0){
408 num+=2;
409
411 /* Check to see that another pole is an actual conjugate.
412 This is not a foolproof test, as it can be fooled by
413 multiple poles at the same location. */
414 INT4 j=0;
415 INT4 k=0;
416 REAL8 x = creal(poles[i]) - creal(poles[0]);
417 REAL8 y = cimag(poles[i]) + cimag(poles[0]);
418 REAL8 sep = x*x + y*y;
419 for(j=1;j<numPoles;j++){
420 x=creal(poles[i])-creal(poles[j]);
421 y=cimag(poles[i])+cimag(poles[j]);
422 if(sep>x*x+y*y){
423 sep=x*x+y*y;
424 k=j;
425 }
426 }
427 if(sep>LAL_REAL8_EPS){
428 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
429 XLALPrintWarning("Complex pole has no conjugate pair\n");
430 XLALPrintWarning("\tUnmatched pole p_%i = %.8e + i*%.8e\n",i,
431 creal(poles[i]),cimag(poles[i]));
432 XLALPrintWarning("\tNearest pair p_%i = %.8e + i*%.8e\n",k,
433 creal(poles[k]),cimag(poles[k]));
434 }
435 }
436 }
437
438 if ( num != numPoles )
440
442 /* Issue a warning if the gain is nonreal. */
443 if(fabs(cimag(input->gain))>fabs(LAL_REAL8_EPS*creal(input->gain))){
444 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
445 XLALPrintWarning("Gain is non-real\n");
446 XLALPrintWarning("\tg = %.8e + i*%.8e\n", creal(input->gain), cimag(input->gain));
447 }
448 /* Issue a warning if there are any ``removeable'' poles. */
449 for(i=0;i<numPoles;i++){
450 INT4 j=0;
451 for(;j<numZeros;j++)
452 if((creal(poles[i])==creal(zeros[j]))&&(cimag(poles[i])==cimag(zeros[j]))){
453 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
454 XLALPrintWarning("Removeable pole\n");
455 XLALPrintWarning("\tp_%i = z_%i = %.8e + i*%.8e\n",i,j,
456 creal(poles[i]),cimag(poles[i]));
457 }
458 }
459 /* Issue a warning if extra factors of 1/z will be applied. */
460 if(numPoles<numZeros){
461 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
462 XLALPrintWarning("Filter has more zeros than poles\n");
463 XLALPrintWarning("\t%i poles added at complex origin\n",
464 numZeros-numPoles);
465 }
466 /* Issue a warning if any poles are outside |z|=1. */
467 for(i=0;i<numPoles;i++){
468 REAL8 zAbs=creal(poles[i])*creal(poles[i])+cimag(poles[i])*cimag(poles[i]);
469 if(zAbs>1.0){
470 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
471 XLALPrintWarning("Filter has pole outside of unit circle\n");
472 XLALPrintWarning("\tp_%i = %.8e + i*%.8e, |p_%i| = %.8e\n",i,
473 creal(poles[i]),cimag(poles[i]),i,zAbs);
474 }
475 }
476 }
477
478 /* Everything seems okay, so initialize the filter. */
479 output=LALCalloc(1,sizeof(*output));
480 if ( ! output )
482 num = (numPoles>=numZeros) ? numZeros : numPoles;
483 numDirect+=num;
484 numRecurs+=num;
485
486 output->deltaT=input->deltaT;
487 output->directCoef = XLALCreateREAL8Vector( numDirect );
488 output->recursCoef = XLALCreateREAL8Vector( numRecurs );
489 if ( ! output->directCoef || ! output->recursCoef )
490 {
493 }
494 direct=output->directCoef->data;
495 recurs=output->recursCoef->data;
496
497 /* Expand the denominator as a polynomial in z. */
498 *recurs=-1.0;
499 for(i=1;i<numRecurs;i++)
500 recurs[i]=0.0;
501 for(i=0;i<numPoles;i++){
502 INT4 j=numRecurs-1;
503 REAL8 x=creal(poles[i]);
504 REAL8 y=cimag(poles[i]);
505 if(y==0.0)
506 for(;j>0;j--)
507 recurs[j]-=x*recurs[j-1];
508 else if(y>0.0){
509 for(;j>1;j--)
510 recurs[j]-=2.0*x*recurs[j-1]-(x*x+y*y)*recurs[j-2];
511 recurs[j]-=2.0*x*recurs[j-1];
512 }
513 }
514
515 /* Expand the numerator as a polynomial in z. */
516 for(i=0;i<numDirect;i++)
517 direct[i]=0.0;
518 direct[num-numZeros]=creal(input->gain);
519 for(i=0;i<numZeros;i++){
520 INT4 j=numDirect-1;
521 REAL8 x=creal(zeros[i]);
522 REAL8 y=cimag(zeros[i]);
523 if(y==0.0)
524 for(;j>num-numZeros;j--)
525 direct[j]-=x*direct[j-1];
526 else if(y>0.0){
527 for(;j>num-numZeros+1;j--)
528 direct[j]-=2.0*x*direct[j-1]-(x*x+y*y)*direct[j-2];
529 direct[j]-=2.0*x*direct[j-1];
530 }
531 }
532
533 /* Initialize filter history. */
534 if(numDirect>=numRecurs)
535 num=numDirect-1;
536 else
537 num=numRecurs-1;
538 output->history = XLALCreateREAL8Vector( numRecurs );
539 if ( ! output->history )
540 {
543 }
544 history=output->history->data;
545 for(i=0;i<num;i++)
546 history[i]=0.0;
547
548 /* Normal exit */
549 return output;
550}
551
552/** \see See \ref CreateIIRFilter_c for documentation */
554{
556 INT4 i; /* Index counter for zeros and poles. */
557 INT4 numZeros; /* The number of zeros. */
558 INT4 numPoles; /* The number of poles. */
559 INT4 numDirect; /* The number of direct filter coefficients. */
560 INT4 numRecurs; /* The number of recursive filter coefficients. */
561 INT4 num; /* An extra counter for error checking. */
562 COMPLEX16 *zeros; /* The zeros of the transfer function. */
563 COMPLEX16 *poles; /* The poles of the transfer function. */
564 REAL8 *direct; /* The direct filter coefficients. */
565 REAL8 *recurs; /* The recursive filter coefficients. */
566 COMPLEX16 *history; /* The filter history. */
567
568 /* Make sure all the input structures have been initialized. */
569 if ( ! input )
571 if ( ! input->zeros || ! input->poles
572 || ! input->zeros->data || ! input->poles->data )
574
575 numZeros=input->zeros->length;
576 numPoles=input->poles->length;
577 zeros=input->zeros->data;
578 poles=input->poles->data;
579
580 /* Check that zeros are appropriately paired. Also, keep track of
581 the number of zeros at z=0, since these will reduce the number of
582 direct coefficients required. */
583 numDirect=1;
584 for(i=0,num=0;i<numZeros;i++)
585 if(cimag(zeros[i])==0.0){
586 num+=1;
587 if(creal(zeros[i])==0.0)
588 numDirect-=1;
589 }
590 else if(cimag(zeros[i])>0.0){
591 num+=2;
592
594 /* Check to see that another zero is an actual conjugate.
595 This is not a foolproof test, as it can be fooled by
596 multiple zeros at the same location. */
597 INT4 j=0;
598 INT4 k=0;
599 REAL8 x = creal(zeros[i]) - creal(zeros[0]);
600 REAL8 y = cimag(zeros[i]) + cimag(zeros[0]);
601 REAL8 sep = x*x + y*y;
602 for(j=1;j<numZeros;j++){
603 x=creal(zeros[i])-creal(zeros[j]);
604 y=cimag(zeros[i])+cimag(zeros[j]);
605 if(sep>x*x+y*y){
606 sep=x*x+y*y;
607 k=j;
608 }
609 }
610 if(sep>LAL_REAL8_EPS){
611 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
612 XLALPrintWarning("Complex zero has no conjugate pair\n");
613 XLALPrintWarning("\tUnmatched zero z_%i = %.8e + i*%.8e\n",i,
614 creal(zeros[i]),cimag(zeros[i]));
615 XLALPrintWarning("\tNearest pair z_%i = %.8e + i*%.8e\n",k,
616 creal(zeros[k]),cimag(zeros[k]));
617 }
618 }
619 }
620
621 if ( num != numZeros )
623
624 /* Check that poles are appropriately paired. Also, keep track of
625 the number of poles at z=0, since these will reduce the number of
626 recursive coefficients required. */
627 numRecurs=1;
628 for(i=0,num=0;i<numPoles;i++)
629 if(cimag(poles[i])==0.0){
630 num+=1;
631 if(creal(poles[i])==0.0)
632 numRecurs-=1;
633 }
634 else if(cimag(poles[i])>0.0){
635 num+=2;
636
638 /* Check to see that another pole is an actual conjugate.
639 This is not a foolproof test, as it can be fooled by
640 multiple poles at the same location. */
641 INT4 j=0;
642 INT4 k=0;
643 REAL8 x = creal(poles[i]) - creal(poles[0]);
644 REAL8 y = cimag(poles[i]) + cimag(poles[0]);
645 REAL8 sep = x*x + y*y;
646 for(j=1;j<numPoles;j++){
647 x=creal(poles[i])-creal(poles[j]);
648 y=cimag(poles[i])+cimag(poles[j]);
649 if(sep>x*x+y*y){
650 sep=x*x+y*y;
651 k=j;
652 }
653 }
654 if(sep>LAL_REAL8_EPS){
655 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
656 XLALPrintWarning("Complex pole has no conjugate pair\n");
657 XLALPrintWarning("\tUnmatched pole p_%i = %.8e + i*%.8e\n",i,
658 creal(poles[i]),cimag(poles[i]));
659 XLALPrintWarning("\tNearest pair p_%i = %.8e + i*%.8e\n",k,
660 creal(poles[k]),cimag(poles[k]));
661 }
662 }
663 }
664
665 if ( num != numPoles )
667
669 /* Issue a warning if the gain is nonreal. */
670 if(fabs(cimag(input->gain))>fabs(LAL_REAL8_EPS*creal(input->gain))){
671 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
672 XLALPrintWarning("Gain is non-real\n");
673 XLALPrintWarning("\tg = %.8e + i*%.8e\n", creal(input->gain), cimag(input->gain));
674 }
675 /* Issue a warning if there are any ``removeable'' poles. */
676 for(i=0;i<numPoles;i++){
677 INT4 j=0;
678 for(;j<numZeros;j++)
679 if((creal(poles[i])==creal(zeros[j]))&&(cimag(poles[i])==cimag(zeros[j]))){
680 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
681 XLALPrintWarning("Removeable pole\n");
682 XLALPrintWarning("\tp_%i = z_%i = %.8e + i*%.8e\n",i,j,
683 creal(poles[i]),cimag(poles[i]));
684 }
685 }
686 /* Issue a warning if extra factors of 1/z will be applied. */
687 if(numPoles<numZeros){
688 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
689 XLALPrintWarning("Filter has more zeros than poles\n");
690 XLALPrintWarning("\t%i poles added at complex origin\n",
691 numZeros-numPoles);
692 }
693 /* Issue a warning if any poles are outside |z|=1. */
694 for(i=0;i<numPoles;i++){
695 REAL8 zAbs=creal(poles[i])*creal(poles[i])+cimag(poles[i])*cimag(poles[i]);
696 if(zAbs>1.0){
697 XLALPrintWarning( "XLAL Warning - %s: ", __func__ );
698 XLALPrintWarning("Filter has pole outside of unit circle\n");
699 XLALPrintWarning("\tp_%i = %.8e + i*%.8e, |p_%i| = %.8e\n",i,
700 creal(poles[i]),cimag(poles[i]),i,zAbs);
701 }
702 }
703 }
704
705 /* Everything seems okay, so initialize the filter. */
706 output=LALCalloc(1,sizeof(*output));
707 if ( ! output )
709 num = (numPoles>=numZeros) ? numZeros : numPoles;
710 numDirect+=num;
711 numRecurs+=num;
712
713 output->deltaT=input->deltaT;
714 output->directCoef = XLALCreateREAL8Vector( numDirect );
715 output->recursCoef = XLALCreateREAL8Vector( numRecurs );
716 if ( ! output->directCoef || ! output->recursCoef )
717 {
720 }
721 direct=output->directCoef->data;
722 recurs=output->recursCoef->data;
723
724 /* Expand the denominator as a polynomial in z. */
725 *recurs=-1.0;
726 for(i=1;i<numRecurs;i++)
727 recurs[i]=0.0;
728 for(i=0;i<numPoles;i++){
729 INT4 j=numRecurs-1;
730 REAL8 x=creal(poles[i]);
731 REAL8 y=cimag(poles[i]);
732 if(y==0.0)
733 for(;j>0;j--)
734 recurs[j]-=x*recurs[j-1];
735 else if(y>0.0){
736 for(;j>1;j--)
737 recurs[j]-=2.0*x*recurs[j-1]-(x*x+y*y)*recurs[j-2];
738 recurs[j]-=2.0*x*recurs[j-1];
739 }
740 }
741
742 /* Expand the numerator as a polynomial in z. */
743 for(i=0;i<numDirect;i++)
744 direct[i]=0.0;
745 direct[num-numZeros]=creal(input->gain);
746 for(i=0;i<numZeros;i++){
747 INT4 j=numDirect-1;
748 REAL8 x=creal(zeros[i]);
749 REAL8 y=cimag(zeros[i]);
750 if(y==0.0)
751 for(;j>num-numZeros;j--)
752 direct[j]-=x*direct[j-1];
753 else if(y>0.0){
754 for(;j>num-numZeros+1;j--)
755 direct[j]-=2.0*x*direct[j-1]-(x*x+y*y)*direct[j-2];
756 direct[j]-=2.0*x*direct[j-1];
757 }
758 }
759
760 /* Initialize filter history. */
761 if(numDirect>=numRecurs)
762 num=numDirect-1;
763 else
764 num=numRecurs-1;
765 output->history = XLALCreateCOMPLEX16Vector( numRecurs );
766 if ( ! output->history )
767 {
770 }
771 history=output->history->data;
772 for(i=0;i<num;i++)
773 history[i]=0.0;
774
775 /* Normal exit */
776 return output;
777}
778
779
780/**
781 * Deprecated.
782 * \deprecated Use XLALCreateREAL4IIRFilter() instead
783 */
786 COMPLEX8ZPGFilter *input )
787{
788 INITSTATUS(stat);
789
790 /* Make sure all the input structures have been initialized. */
791 ASSERT(input,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
792 ASSERT(input->zeros,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
793 ASSERT(input->zeros->data,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
794 ASSERT(input->poles,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
795 ASSERT(input->poles->data,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
796
797 /* Make sure that the output handle exists, but points to a null
798 pointer. */
799 ASSERT(output,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
800 ASSERT(!*output,stat,IIRFILTERH_EOUT,IIRFILTERH_MSGEOUT);
801
803 if ( ! *output )
804 {
805 int code = xlalErrno & ~XLAL_EFUNC;
807 switch ( code )
808 {
809 case XLAL_EINVAL:
810 ABORT(stat,IIRFILTERH_EPAIR,IIRFILTERH_MSGEPAIR);
811 case XLAL_ENOMEM:
812 ABORT(stat,IIRFILTERH_EMEM,IIRFILTERH_MSGEMEM);
813 default:
814 ABORTXLAL(stat);
815 }
816 }
817
818 RETURN(stat);
819}
820
821
822/**
823 * Deprecated.
824 * \deprecated Use XLALCreateREAL8IIRFilter() instead
825 */
828 COMPLEX16ZPGFilter *input )
829{
830 INITSTATUS(stat);
831
832 /* Make sure all the input structures have been initialized. */
833 ASSERT(input,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
834 ASSERT(input->zeros,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
835 ASSERT(input->zeros->data,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
836 ASSERT(input->poles,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
837 ASSERT(input->poles->data,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
838
839 /* Make sure that the output handle exists, but points to a null
840 pointer. */
841 ASSERT(output,stat,IIRFILTERH_ENUL,IIRFILTERH_MSGENUL);
842 ASSERT(!*output,stat,IIRFILTERH_EOUT,IIRFILTERH_MSGEOUT);
843
845 if ( ! *output )
846 {
847 int code = xlalErrno & ~XLAL_EFUNC;
849 switch ( code )
850 {
851 case XLAL_EINVAL:
852 ABORT(stat,IIRFILTERH_EPAIR,IIRFILTERH_MSGEPAIR);
853 case XLAL_ENOMEM:
854 ABORT(stat,IIRFILTERH_EMEM,IIRFILTERH_MSGEMEM);
855 default:
856 ABORTXLAL(stat);
857 }
858 }
859
860 RETURN(stat);
861}
862/** @} */
#define LALCalloc(m, n)
Definition: LALMalloc.h:94
#define ABORT(statusptr, code, mesg)
#define ASSERT(assertion, statusptr, code, mesg)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define ABORTXLAL(sp)
int XLALPrintWarning(const char *fmt,...)
Definition: XLALError.c:79
REAL4IIRFilter * XLALCreateREAL4IIRFilter(COMPLEX8ZPGFilter *input)
void LALCreateREAL4IIRFilter(LALStatus *stat, REAL4IIRFilter **output, COMPLEX8ZPGFilter *input)
Deprecated.
REAL8IIRFilter * XLALCreateREAL8IIRFilter(COMPLEX16ZPGFilter *input)
COMPLEX16IIRFilter * XLALCreateCOMPLEX16IIRFilter(COMPLEX16ZPGFilter *input)
void LALCreateREAL8IIRFilter(LALStatus *stat, REAL8IIRFilter **output, COMPLEX16ZPGFilter *input)
Deprecated.
void XLALDestroyREAL4IIRFilter(REAL4IIRFilter *filter)
void XLALDestroyCOMPLEX16IIRFilter(COMPLEX16IIRFilter *filter)
void XLALDestroyREAL8IIRFilter(REAL8IIRFilter *filter)
#define IIRFILTERH_ENUL
Unexpected null pointer in arguments.
Definition: IIRFilter.h:131
#define IIRFILTERH_EPAIR
Input has unpaired nonreal poles or zeros.
Definition: IIRFilter.h:134
#define IIRFILTERH_EMEM
Memory allocation error.
Definition: IIRFilter.h:133
#define IIRFILTERH_EOUT
Output handle points to a non-null pointer.
Definition: IIRFilter.h:132
#define LAL_REAL8_EPS
Difference between 1 and the next resolvable REAL8 2^-52.
Definition: LALConstants.h:61
#define LAL_REAL4_EPS
Difference between 1 and the next resolvable REAL4 2^-23.
Definition: LALConstants.h:57
double complex COMPLEX16
Double-precision floating-point complex number (16 bytes total)
double REAL8
Double precision real floating-point number (8 bytes).
float complex COMPLEX8
Single-precision floating-point complex number (8 bytes total)
int32_t INT4
Four-byte signed integer.
float REAL4
Single precision real floating-point number (4 bytes).
#define lalDebugLevel
Definition: LALDebugLevel.h:58
@ LALWARNING
enable warning messages
Definition: LALDebugLevel.h:47
REAL4Vector * XLALCreateREAL4Vector(UINT4 length)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
COMPLEX16Vector * XLALCreateCOMPLEX16Vector(UINT4 length)
#define XLAL_ERROR_NULL(...)
Macro to invoke a failure from a XLAL routine returning a pointer.
Definition: XLALError.h:713
#define xlalErrno
Modifiable lvalue containing the XLAL error number.
Definition: XLALError.h:571
int XLALClearErrno(void)
Clears the XLAL error number, returns the old value.
Definition: XLALError.c:363
@ XLAL_ENOMEM
Memory allocation error.
Definition: XLALError.h:407
@ XLAL_EFAULT
Invalid pointer.
Definition: XLALError.h:408
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
@ XLAL_EINVAL
Invalid argument.
Definition: XLALError.h:409
This structure stores the direct and recursive REAL8 filter coefficients, as well as the complex-valu...
Definition: IIRFilter.h:184
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:176
COMPLEX16 * data
Pointer to the data array.
Definition: LALDatatypes.h:177
See DATATYPE-ZPGFilter types for details.
Definition: LALDatatypes.h:930
COMPLEX16Vector * poles
Definition: LALDatatypes.h:934
COMPLEX16Vector * zeros
Definition: LALDatatypes.h:933
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:167
COMPLEX8 * data
Pointer to the data array.
Definition: LALDatatypes.h:168
See DATATYPE-ZPGFilter types for details.
Definition: LALDatatypes.h:921
COMPLEX8Vector * poles
Definition: LALDatatypes.h:925
COMPLEX8Vector * zeros
Definition: LALDatatypes.h:924
LAL status structure, see The LALStatus structure for more details.
Definition: LALDatatypes.h:947
This structure stores the direct and recursive REAL4 filter coefficients, as well as the history of t...
Definition: IIRFilter.h:152
This structure stores the direct and recursive REAL8 filter coefficients, as well as the history of t...
Definition: IIRFilter.h:168
void output(int gps_sec, int output_type)
Definition: tconvert.c:440