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