1 /*
2
3 Copyright (C) 1995, 1998 Jake Janovetz <janovetz@uiuc.edu>
4 Copyright (C) 1999 Paul Kienzle <pkienzle@users.sf.net>
5 Copyright (C) 2000 Kai Habel <kahacjde@linux.zrz.tu-berlin.de>
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20
21 */
22
23 /**************************************************************************
24 * There appear to be some problems with the routine Search. See comments
25 * therein [search for PAK:]. I haven't looked closely at the rest
26 * of the code---it may also have some problems.
27 *************************************************************************/
28
29 #include <octave/oct.h>
30 #include <cmath>
31
32 #ifndef OCTAVE_LOCAL_BUFFER
33 #include <vector>
34 #define OCTAVE_LOCAL_BUFFER(T, buf, size) \
35 std::vector<T> buf ## _vector (size); \
36 T *buf = &(buf ## _vector[0])
37 #endif
38
39 #include "octave-compat.h"
40
41 #define CONST const
42 #define BANDPASS 1
43 #define DIFFERENTIATOR 2
44 #define HILBERT 3
45
46 #define NEGATIVE 0
47 #define POSITIVE 1
48
49 #define Pi 3.1415926535897932
50 #define Pi2 6.2831853071795865
51
52 #define GRIDDENSITY 16
53 #define MAXITERATIONS 40
54
55 /*******************
56 * CreateDenseGrid
57 *=================
58 * Creates the dense grid of frequencies from the specified bands.
59 * Also creates the Desired Frequency Response function (D[]) and
60 * the Weight function (W[]) on that dense grid
61 *
62 *
63 * INPUT:
64 * ------
65 * int r - 1/2 the number of filter coefficients
66 * int numtaps - Number of taps in the resulting filter
67 * int numband - Number of bands in user specification
68 * double bands[] - User-specified band edges [2*numband]
69 * double des[] - Desired response per band [2*numband]
70 * double weight[] - Weight per band [numband]
71 * int symmetry - Symmetry of filter - used for grid check
72 * int griddensity
73 *
74 * OUTPUT:
75 * -------
76 * int gridsize - Number of elements in the dense frequency grid
77 * double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize]
78 * double D[] - Desired response on the dense grid [gridsize]
79 * double W[] - Weight function on the dense grid [gridsize]
80 *******************/
81
CreateDenseGrid(int r,int numtaps,int numband,const double bands[],const double des[],const double weight[],int gridsize,double Grid[],double D[],double W[],int symmetry,int griddensity)82 void CreateDenseGrid(int r, int numtaps, int numband, const double bands[],
83 const double des[], const double weight[], int gridsize,
84 double Grid[], double D[], double W[],
85 int symmetry, int griddensity)
86 {
87 int i, j, k, band;
88 double delf, lowf, highf, grid0;
89
90 delf = 0.5/(griddensity*r);
91
92 /*
93 * For differentiator, hilbert,
94 * symmetry is odd and Grid[0] = max(delf, bands[0])
95 */
96 grid0 = (symmetry == NEGATIVE) && (delf > bands[0]) ? delf : bands[0];
97
98 j=0;
99 for (band=0; band < numband; band++)
100 {
101 lowf = (band==0 ? grid0 : bands[2*band]);
102 highf = bands[2*band + 1];
103 k = (int)((highf - lowf)/delf + 0.5); /* .5 for rounding */
104 if (band == 0 && symmetry == NEGATIVE)
105 k--;
106 for (i=0; i<k; i++)
107 {
108 D[j] = des[2*band] + i*(des[2*band+1]-des[2*band])/(k-1);
109 W[j] = weight[band];
110 Grid[j] = lowf;
111 lowf += delf;
112 j++;
113 }
114 Grid[j-1] = highf;
115 }
116
117 /*
118 * Similar to above, if odd symmetry, last grid point can't be .5
119 * - but, if there are even taps, leave the last grid point at .5
120 */
121 if ((symmetry == NEGATIVE) &&
122 (Grid[gridsize-1] > (0.5 - delf)) &&
123 (numtaps % 2))
124 {
125 Grid[gridsize-1] = 0.5-delf;
126 }
127 }
128
129
130 /********************
131 * InitialGuess
132 *==============
133 * Places Extremal Frequencies evenly throughout the dense grid.
134 *
135 *
136 * INPUT:
137 * ------
138 * int r - 1/2 the number of filter coefficients
139 * int gridsize - Number of elements in the dense frequency grid
140 *
141 * OUTPUT:
142 * -------
143 * int Ext[] - Extremal indexes to dense frequency grid [r+1]
144 ********************/
145
InitialGuess(int r,int Ext[],int gridsize)146 void InitialGuess(int r, int Ext[], int gridsize)
147 {
148 int i;
149
150 for (i=0; i<=r; i++)
151 Ext[i] = i * (gridsize-1) / r;
152 }
153
154
155 /***********************
156 * CalcParms
157 *===========
158 *
159 *
160 * INPUT:
161 * ------
162 * int r - 1/2 the number of filter coefficients
163 * int Ext[] - Extremal indexes to dense frequency grid [r+1]
164 * double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize]
165 * double D[] - Desired response on the dense grid [gridsize]
166 * double W[] - Weight function on the dense grid [gridsize]
167 *
168 * OUTPUT:
169 * -------
170 * double ad[] - 'b' in Oppenheim & Schafer [r+1]
171 * double x[] - [r+1]
172 * double y[] - 'C' in Oppenheim & Schafer [r+1]
173 ***********************/
174
CalcParms(int r,int Ext[],double Grid[],double D[],double W[],double ad[],double x[],double y[])175 void CalcParms(int r, int Ext[], double Grid[], double D[], double W[],
176 double ad[], double x[], double y[])
177 {
178 int i, j, k, ld;
179 double sign, xi, delta, denom, numer;
180
181 /*
182 * Find x[]
183 */
184 for (i=0; i<=r; i++)
185 x[i] = cos(Pi2 * Grid[Ext[i]]);
186
187 /*
188 * Calculate ad[] - Oppenheim & Schafer eq 7.132
189 */
190 ld = (r-1)/15 + 1; /* Skips around to avoid round errors */
191 for (i=0; i<=r; i++)
192 {
193 denom = 1.0;
194 xi = x[i];
195 for (j=0; j<ld; j++)
196 {
197 for (k=j; k<=r; k+=ld)
198 if (k != i)
199 denom *= 2.0*(xi - x[k]);
200 }
201 if (fabs(denom)<0.00001)
202 denom = 0.00001;
203 ad[i] = 1.0/denom;
204 }
205
206 /*
207 * Calculate delta - Oppenheim & Schafer eq 7.131
208 */
209 numer = denom = 0;
210 sign = 1;
211 for (i=0; i<=r; i++)
212 {
213 numer += ad[i] * D[Ext[i]];
214 denom += sign * ad[i]/W[Ext[i]];
215 sign = -sign;
216 }
217 delta = numer/denom;
218 sign = 1;
219
220 /*
221 * Calculate y[] - Oppenheim & Schafer eq 7.133b
222 */
223 for (i=0; i<=r; i++)
224 {
225 y[i] = D[Ext[i]] - sign * delta/W[Ext[i]];
226 sign = -sign;
227 }
228 }
229
230
231 /*********************
232 * ComputeA
233 *==========
234 * Using values calculated in CalcParms, ComputeA calculates the
235 * actual filter response at a given frequency (freq). Uses
236 * eq 7.133a from Oppenheim & Schafer.
237 *
238 *
239 * INPUT:
240 * ------
241 * double freq - Frequency (0 to 0.5) at which to calculate A
242 * int r - 1/2 the number of filter coefficients
243 * double ad[] - 'b' in Oppenheim & Schafer [r+1]
244 * double x[] - [r+1]
245 * double y[] - 'C' in Oppenheim & Schafer [r+1]
246 *
247 * OUTPUT:
248 * -------
249 * Returns double value of A[freq]
250 *********************/
251
ComputeA(double freq,int r,double ad[],double x[],double y[])252 double ComputeA(double freq, int r, double ad[], double x[], double y[])
253 {
254 int i;
255 double xc, c, denom, numer;
256
257 denom = numer = 0;
258 xc = cos(Pi2 * freq);
259 for (i=0; i<=r; i++)
260 {
261 c = xc - x[i];
262 if (fabs(c) < 1.0e-7)
263 {
264 numer = y[i];
265 denom = 1;
266 break;
267 }
268 c = ad[i]/c;
269 denom += c;
270 numer += c*y[i];
271 }
272 return numer/denom;
273 }
274
275
276 /************************
277 * CalcError
278 *===========
279 * Calculates the Error function from the desired frequency response
280 * on the dense grid (D[]), the weight function on the dense grid (W[]),
281 * and the present response calculation (A[])
282 *
283 *
284 * INPUT:
285 * ------
286 * int r - 1/2 the number of filter coefficients
287 * double ad[] - [r+1]
288 * double x[] - [r+1]
289 * double y[] - [r+1]
290 * int gridsize - Number of elements in the dense frequency grid
291 * double Grid[] - Frequencies on the dense grid [gridsize]
292 * double D[] - Desired response on the dense grid [gridsize]
293 * double W[] - Weight function on the desnse grid [gridsize]
294 *
295 * OUTPUT:
296 * -------
297 * double E[] - Error function on dense grid [gridsize]
298 ************************/
299
CalcError(int r,double ad[],double x[],double y[],int gridsize,double Grid[],double D[],double W[],double E[])300 void CalcError(int r, double ad[], double x[], double y[],
301 int gridsize, double Grid[],
302 double D[], double W[], double E[])
303 {
304 int i;
305 double A;
306
307 for (i=0; i<gridsize; i++)
308 {
309 A = ComputeA(Grid[i], r, ad, x, y);
310 E[i] = W[i] * (D[i] - A);
311 }
312 }
313
314 /************************
315 * Search
316 *========
317 * Searches for the maxima/minima of the error curve. If more than
318 * r+1 extrema are found, it uses the following heuristic (thanks
319 * Chris Hanson):
320 * 1) Adjacent non-alternating extrema deleted first.
321 * 2) If there are more than one excess extrema, delete the
322 * one with the smallest error. This will create a non-alternation
323 * condition that is fixed by 1).
324 * 3) If there is exactly one excess extremum, delete the smaller
325 * of the first/last extremum
326 *
327 *
328 * INPUT:
329 * ------
330 * int r - 1/2 the number of filter coefficients
331 * int Ext[] - Indexes to Grid[] of extremal frequencies [r+1]
332 * int gridsize - Number of elements in the dense frequency grid
333 * double E[] - Array of error values. [gridsize]
334 * OUTPUT:
335 * -------
336 * int Ext[] - New indexes to extremal frequencies [r+1]
337 ************************/
Search(int r,int Ext[],int gridsize,double E[])338 int Search(int r, int Ext[],
339 int gridsize, double E[])
340 {
341 int i, j, k, l, extra; /* Counters */
342 int up, alt;
343 int *foundExt; /* Array of found extremals */
344
345 /*
346 * Allocate enough space for found extremals.
347 */
348 foundExt = (int *)malloc((2*r) * sizeof(int));
349 k = 0;
350
351 /*
352 * Check for extremum at 0.
353 */
354 if (((E[0]>0.0) && (E[0]>E[1])) ||
355 ((E[0]<0.0) && (E[0]<E[1])))
356 foundExt[k++] = 0;
357
358 /*
359 * Check for extrema inside dense grid
360 */
361 for (i=1; i<gridsize-1; i++)
362 {
363 if (((E[i]>=E[i-1]) && (E[i]>E[i+1]) && (E[i]>0.0)) ||
364 ((E[i]<=E[i-1]) && (E[i]<E[i+1]) && (E[i]<0.0))) {
365 // PAK: we sometimes get too many extremal frequencies
366 if (k >= 2*r) return -3;
367 foundExt[k++] = i;
368 }
369 }
370
371 /*
372 * Check for extremum at 0.5
373 */
374 j = gridsize-1;
375 if (((E[j]>0.0) && (E[j]>E[j-1])) ||
376 ((E[j]<0.0) && (E[j]<E[j-1]))) {
377 if (k >= 2*r) return -3;
378 foundExt[k++] = j;
379 }
380
381 // PAK: we sometimes get not enough extremal frequencies
382 if (k < r+1) return -2;
383
384
385 /*
386 * Remove extra extremals
387 */
388 extra = k - (r+1);
389 assert(extra >= 0);
390
391 while (extra > 0)
392 {
393 if (E[foundExt[0]] > 0.0)
394 up = 1; /* first one is a maxima */
395 else
396 up = 0; /* first one is a minima */
397
398 l=0;
399 alt = 1;
400 for (j=1; j<k; j++)
401 {
402 if (fabs(E[foundExt[j]]) < fabs(E[foundExt[l]]))
403 l = j; /* new smallest error. */
404 if ((up) && (E[foundExt[j]] < 0.0))
405 up = 0; /* switch to a minima */
406 else if ((!up) && (E[foundExt[j]] > 0.0))
407 up = 1; /* switch to a maxima */
408 else
409 {
410 alt = 0;
411 // PAK: break now and you will delete the smallest overall
412 // extremal. If you want to delete the smallest of the
413 // pair of non-alternating extremals, then you must do:
414 //
415 // if (fabs(E[foundExt[j]]) < fabs(E[foundExt[j-1]])) l=j;
416 // else l=j-1;
417 break; /* Ooops, found two non-alternating */
418 } /* extrema. Delete smallest of them */
419 } /* if the loop finishes, all extrema are alternating */
420
421 /*
422 * If there's only one extremal and all are alternating,
423 * delete the smallest of the first/last extremals.
424 */
425 if ((alt) && (extra == 1))
426 {
427 if (fabs(E[foundExt[k-1]]) < fabs(E[foundExt[0]]))
428 /* Delete last extremal */
429 l = k-1;
430 // PAK: changed from l = foundExt[k-1];
431 else
432 /* Delete first extremal */
433 l = 0;
434 // PAK: changed from l = foundExt[0];
435 }
436
437 for (j=l; j<k-1; j++) /* Loop that does the deletion */
438 {
439 foundExt[j] = foundExt[j+1];
440 assert(foundExt[j]<gridsize);
441 }
442 k--;
443 extra--;
444 }
445
446 for (i=0; i<=r; i++)
447 {
448 assert(foundExt[i]<gridsize);
449 Ext[i] = foundExt[i]; /* Copy found extremals to Ext[] */
450 }
451
452 free(foundExt);
453 return 0;
454 }
455
456
457 /*********************
458 * FreqSample
459 *============
460 * Simple frequency sampling algorithm to determine the impulse
461 * response h[] from A's found in ComputeA
462 *
463 *
464 * INPUT:
465 * ------
466 * int N - Number of filter coefficients
467 * double A[] - Sample points of desired response [N/2]
468 * int symmetry - Symmetry of desired filter
469 *
470 * OUTPUT:
471 * -------
472 * double h[] - Impulse Response of final filter [N]
473 *********************/
FreqSample(int N,double A[],double h[],int symm)474 void FreqSample(int N, double A[], double h[], int symm)
475 {
476 int n, k;
477 double x, val, M;
478
479 M = (N-1.0)/2.0;
480 if (symm == POSITIVE)
481 {
482 if (N%2)
483 {
484 for (n=0; n<N; n++)
485 {
486 val = A[0];
487 x = Pi2 * (n - M)/N;
488 for (k=1; k<=M; k++)
489 val += 2.0 * A[k] * cos(x*k);
490 h[n] = val/N;
491 }
492 }
493 else
494 {
495 for (n=0; n<N; n++)
496 {
497 val = A[0];
498 x = Pi2 * (n - M)/N;
499 for (k=1; k<=(N/2-1); k++)
500 val += 2.0 * A[k] * cos(x*k);
501 h[n] = val/N;
502 }
503 }
504 }
505 else
506 {
507 if (N%2)
508 {
509 for (n=0; n<N; n++)
510 {
511 val = 0;
512 x = Pi2 * (n - M)/N;
513 for (k=1; k<=M; k++)
514 val += 2.0 * A[k] * sin(x*k);
515 h[n] = val/N;
516 }
517 }
518 else
519 {
520 for (n=0; n<N; n++)
521 {
522 val = A[N/2] * sin(Pi * (n - M));
523 x = Pi2 * (n - M)/N;
524 for (k=1; k<=(N/2-1); k++)
525 val += 2.0 * A[k] * sin(x*k);
526 h[n] = val/N;
527 }
528 }
529 }
530 }
531
532 /*******************
533 * isDone
534 *========
535 * Checks to see if the error function is small enough to consider
536 * the result to have converged.
537 *
538 * INPUT:
539 * ------
540 * int r - 1/2 the number of filter coefficients
541 * int Ext[] - Indexes to extremal frequencies [r+1]
542 * double E[] - Error function on the dense grid [gridsize]
543 *
544 * OUTPUT:
545 * -------
546 * Returns 1 if the result converged
547 * Returns 0 if the result has not converged
548 ********************/
549
isDone(int r,int Ext[],double E[])550 int isDone(int r, int Ext[], double E[])
551 {
552 int i;
553 double min, max, current;
554
555 min = max = fabs(E[Ext[0]]);
556 for (i=1; i<=r; i++)
557 {
558 current = fabs(E[Ext[i]]);
559 if (current < min)
560 min = current;
561 if (current > max)
562 max = current;
563 }
564 return (((max-min)/max) < 0.0001);
565 }
566
567 /********************
568 * remez
569 *=======
570 * Calculates the optimal (in the Chebyshev/minimax sense)
571 * FIR filter impulse response given a set of band edges,
572 * the desired response on those bands, and the weight given to
573 * the error in those bands.
574 *
575 * INPUT:
576 * ------
577 * int numtaps - Number of filter coefficients
578 * int numband - Number of bands in filter specification
579 * double bands[] - User-specified band edges [2 * numband]
580 * double des[] - User-specified band responses [numband]
581 * double weight[] - User-specified error weights [numband]
582 * int type - Type of filter
583 *
584 * OUTPUT:
585 * -------
586 * double h[] - Impulse response of final filter [numtaps]
587 * returns - true on success, false on failure to converge
588 ********************/
589
remez(double h[],int numtaps,int numband,const double bands[],const double des[],const double weight[],int type,int griddensity)590 int remez(double h[], int numtaps,
591 int numband, const double bands[],
592 const double des[], const double weight[],
593 int type, int griddensity)
594 {
595 double *Grid, *W, *D, *E;
596 int i, iter, gridsize, r, *Ext;
597 double *taps, c;
598 double *x, *y, *ad;
599 int symmetry;
600
601 if (type == BANDPASS)
602 symmetry = POSITIVE;
603 else
604 symmetry = NEGATIVE;
605
606 r = numtaps/2; /* number of extrema */
607 if ((numtaps%2) && (symmetry == POSITIVE))
608 r++;
609
610 /*
611 * Predict dense grid size in advance for memory allocation
612 * .5 is so we round up, not truncate
613 */
614 gridsize = 0;
615 for (i=0; i<numband; i++)
616 {
617 gridsize += (int)(2*r*griddensity*(bands[2*i+1] - bands[2*i]) + .5);
618 }
619 if (symmetry == NEGATIVE)
620 {
621 gridsize--;
622 }
623
624 /*
625 * Dynamically allocate memory for arrays with proper sizes
626 */
627 Grid = (double *)malloc(gridsize * sizeof(double));
628 D = (double *)malloc(gridsize * sizeof(double));
629 W = (double *)malloc(gridsize * sizeof(double));
630 E = (double *)malloc(gridsize * sizeof(double));
631 Ext = (int *)malloc((r+1) * sizeof(int));
632 taps = (double *)malloc((r+1) * sizeof(double));
633 x = (double *)malloc((r+1) * sizeof(double));
634 y = (double *)malloc((r+1) * sizeof(double));
635 ad = (double *)malloc((r+1) * sizeof(double));
636
637 /*
638 * Create dense frequency grid
639 */
640 CreateDenseGrid(r, numtaps, numband, bands, des, weight,
641 gridsize, Grid, D, W, symmetry, griddensity);
642 InitialGuess(r, Ext, gridsize);
643
644 /*
645 * For Differentiator: (fix grid)
646 */
647 if (type == DIFFERENTIATOR)
648 {
649 for (i=0; i<gridsize; i++)
650 {
651 /* D[i] = D[i]*Grid[i]; */
652 if (D[i] > 0.0001)
653 W[i] = W[i]/Grid[i];
654 }
655 }
656
657 /*
658 * For odd or Negative symmetry filters, alter the
659 * D[] and W[] according to Parks McClellan
660 */
661 if (symmetry == POSITIVE)
662 {
663 if (numtaps % 2 == 0)
664 {
665 for (i=0; i<gridsize; i++)
666 {
667 c = cos(Pi * Grid[i]);
668 D[i] /= c;
669 W[i] *= c;
670 }
671 }
672 }
673 else
674 {
675 if (numtaps % 2)
676 {
677 for (i=0; i<gridsize; i++)
678 {
679 c = sin(Pi2 * Grid[i]);
680 D[i] /= c;
681 W[i] *= c;
682 }
683 }
684 else
685 {
686 for (i=0; i<gridsize; i++)
687 {
688 c = sin(Pi * Grid[i]);
689 D[i] /= c;
690 W[i] *= c;
691 }
692 }
693 }
694
695 /*
696 * Perform the Remez Exchange algorithm
697 */
698 for (iter=0; iter<MAXITERATIONS; iter++)
699 {
700 CalcParms(r, Ext, Grid, D, W, ad, x, y);
701 CalcError(r, ad, x, y, gridsize, Grid, D, W, E);
702 int err = Search(r, Ext, gridsize, E);
703 if (err) return err;
704 for(i=0; i <= r; i++) assert(Ext[i]<gridsize);
705 if (isDone(r, Ext, E))
706 break;
707 }
708
709 CalcParms(r, Ext, Grid, D, W, ad, x, y);
710
711 /*
712 * Find the 'taps' of the filter for use with Frequency
713 * Sampling. If odd or Negative symmetry, fix the taps
714 * according to Parks McClellan
715 */
716 for (i=0; i<=numtaps/2; i++)
717 {
718 if (symmetry == POSITIVE)
719 {
720 if (numtaps%2)
721 c = 1;
722 else
723 c = cos(Pi * (double)i/numtaps);
724 }
725 else
726 {
727 if (numtaps%2)
728 c = sin(Pi2 * (double)i/numtaps);
729 else
730 c = sin(Pi * (double)i/numtaps);
731 }
732 taps[i] = ComputeA((double)i/numtaps, r, ad, x, y)*c;
733 }
734
735 /*
736 * Frequency sampling design with calculated taps
737 */
738 FreqSample(numtaps, taps, h, symmetry);
739
740 /*
741 * Delete allocated memory
742 */
743 free(Grid);
744 free(W);
745 free(D);
746 free(E);
747 free(Ext);
748 free(x);
749 free(y);
750 free(ad);
751 return iter<MAXITERATIONS?0:-1;
752 }
753
754
755 /* == Octave interface starts here ====================================== */
756
757 DEFUN_DLD (remez, args, ,
758 "-*- texinfo -*-\n\
759 @deftypefn {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a})\n\
760 @deftypefnx {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}, @var{w})\n\
761 @deftypefnx {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}, @var{w}, @var{ftype})\n\
762 @deftypefnx {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}, @var{w}, @var{ftype}, @var{griddensity})\n\
763 Parks-McClellan optimal FIR filter design.\n\
764 @table @var\n\
765 @item n\n\
766 gives the number of taps in the returned filter\n\
767 @item f\n\
768 gives frequency at the band edges [b1 e1 b2 e2 b3 e3 @dots{}]\n\
769 @item a\n\
770 gives amplitude at the band edges [a(b1) a(e1) a(b2) a(e2) @dots{}]\n\
771 @item w\n\
772 gives weighting applied to each band\n\
773 @item ftype\n\
774 is \"bandpass\", \"hilbert\" or \"differentiator\"\n\
775 @item griddensity\n\
776 determines how accurately the filter will be\n\
777 constructed. The minimum value is 16, but higher numbers are\n\
778 slower to compute.\n\
779 @end table\n\
780 \n\
781 Frequency is in the range (0, 1), with 1 being the Nyquist frequency.\n\
782 @end deftypefn")
783 {
784 octave_value_list retval;
785 int i;
786
787 int nargin = args.length();
788 if (nargin < 3 || nargin > 6) {
789 print_usage ();
790 return retval;
791 }
792
793 int numtaps = octave::math::nint (args(0).double_value ()) + 1;
794 if (numtaps < 4) {
795 error("remez: number of taps must be an integer greater than 3");
796 return retval;
797 }
798
799 ColumnVector o_bands(args(1).vector_value());
800 int numbands = o_bands.numel()/2;
801 OCTAVE_LOCAL_BUFFER(double, bands, numbands*2);
802 if (numbands < 1 || o_bands.numel()%2 == 1) {
803 error("remez: must have an even number of band edges");
804 return retval;
805 }
806 for (i=1; i < o_bands.numel(); i++) {
807 if (o_bands(i)<o_bands(i-1)) {
808 error("band edges must be nondecreasing");
809 return retval;
810 }
811 }
812 if (o_bands(0) < 0 || o_bands(1) > 1) {
813 error("band edges must be in the range [0,1]");
814 return retval;
815 }
816 for(i=0; i < 2*numbands; i++) bands[i] = o_bands(i)/2.0;
817
818 ColumnVector o_response(args(2).vector_value());
819 OCTAVE_LOCAL_BUFFER (double, response, numbands*2);
820 if (o_response.numel() != o_bands.numel()) {
821 error("remez: must have one response magnitude for each band edge");
822 return retval;
823 }
824 for(i=0; i < 2*numbands; i++) response[i] = o_response(i);
825
826 std::string stype = std::string("bandpass");
827 int density = 16;
828 OCTAVE_LOCAL_BUFFER (double, weight, numbands);
829 for (i=0; i < numbands; i++) weight[i] = 1.0;
830 if (nargin > 3) {
831 if (args(3).is_string())
832 stype = args(3).string_value();
833 else if (args(3).is_real_matrix() || args(3).is_real_scalar()) {
834 ColumnVector o_weight(args(3).vector_value());
835 if (o_weight.numel() != numbands) {
836 error("remez: need one weight for each band [=length(band)/2]");
837 return retval;
838 }
839 for (i=0; i < numbands; i++) weight[i] = o_weight(i);
840 }
841 else {
842 error("remez: incorrect argument list");
843 return retval;
844 }
845 }
846 if (nargin > 4) {
847 if (args(4).is_string() && !args(3).is_string())
848 stype = args(4).string_value();
849 else if (args(4).is_real_scalar())
850 density = octave::math::nint (args(4).double_value ());
851 else {
852 error("remez: incorrect argument list");
853 return retval;
854 }
855 }
856 if (nargin > 5) {
857 if (args(5).is_real_scalar()
858 && !args(4).is_real_scalar())
859 density = octave::math::nint (args(5).double_value ());
860 else {
861 error("remez: incorrect argument list");
862 return retval;
863 }
864 }
865
866 int itype;
867 if (stype == "bandpass")
868 itype = BANDPASS;
869 else if (stype == "differentiator")
870 itype = DIFFERENTIATOR;
871 else if (stype == "hilbert")
872 itype = HILBERT;
873 else {
874 error("remez: unknown ftype '%s'", stype.data());
875 return retval;
876 }
877
878 if (density < 16) {
879 error("remez: griddensity is too low; must be greater than 16");
880 return retval;
881 }
882
883 OCTAVE_LOCAL_BUFFER (double, coeff, numtaps+5);
884 int err = remez(coeff,numtaps,numbands,bands,response,weight,itype,density);
885
886 if (err == -1)
887 warning("remez: -- failed to converge -- returned filter may be bad.");
888 else if (err == -2) {
889 error("remez: insufficient extremals--cannot continue");
890 return retval;
891 }
892 else if (err == -3) {
893 error("remez: too many extremals--cannot continue");
894 return retval;
895 }
896
897 ColumnVector h(numtaps);
898 while(numtaps--) h(numtaps) = coeff[numtaps];
899
900 return octave_value(h);
901 }
902
903 /*
904 %!test
905 %! b = [
906 %! 0.0415131831103279
907 %! 0.0581639884202646
908 %! -0.0281579212691008
909 %! -0.0535575358002337
910 %! -0.0617245915143180
911 %! 0.0507753178978075
912 %! 0.2079018331396460
913 %! 0.3327160895375440
914 %! 0.3327160895375440
915 %! 0.2079018331396460
916 %! 0.0507753178978075
917 %! -0.0617245915143180
918 %! -0.0535575358002337
919 %! -0.0281579212691008
920 %! 0.0581639884202646
921 %! 0.0415131831103279];
922 %! assert(remez(15,[0,0.3,0.4,1],[1,1,0,0]),b,1e-14);
923
924 */
925