Complex and nonlinear-phase equiripple FIR filter design

`b = cfirpm(n,f,@`

* fresp*)

b = cfirpm(n,f,@

`fresp`

b = cfirpm(n,f,a)

b = cfirpm(n,f,a,w)

b = cfirpm(...,

`'sym'`

b = cfirpm(...,'skip_stage2')

b = cfirpm(...,

`'debug'`

b = cfirpm(...,{lgrid})

[b,delta] = cfirpm(...)

[b,delta,opt] = cfirpm(...)

`cfirpm`

allows arbitrary frequency-domain
constraints to be specified for the design of a possibly complex FIR filter. The Chebyshev (or minimax)
filter error is optimized, producing equiripple FIR filter designs.

`b = cfirpm(n,f,@`

returns
a length * fresp*)

`n+1`

FIR filter with the best approximation
to the desired frequency response as returned by function `fresp`

`@fresp`

`f`

is
a vector of frequency band edge pairs, specified in the range -1 and 1, where 1 corresponds to the normalized Nyquist frequency.
The frequencies must be in increasing order, and `f`

must
have even length. The frequency bands span `f(k)`

to `f(k+1)`

for `k`

odd;
the intervals `f(k+1)`

to `f(k+2)`

for `k`

odd
are “transition bands” or “don't care”
regions during optimization.Predefined `fresp`

frequency response functions
are included for a number of common filter designs, as described below.
(See Create Function Handle (MATLAB) for more information on how
to create a custom `fresp`

function.) For all of
the predefined frequency response functions, the symmetry option * 'sym'* defaults
to

`'even'`

if no negative frequencies are contained
in `f`

and `d`

= `0`

; otherwise `'sym'`

`'none'`

. (See the `'sym'`

`d`

specifies
a group-delay offset such that the filter response has a group delay
of `n/2+d`

in units of the sample interval. Negative
values create less delay; positive values create more delay. By default `d`

= `0`

:`@lowpass`

,`@highpass`

,`@allpass`

,`@bandpass`

,`@bandstop`

These functions share a common syntax, exemplified below by

`@lowpass`

.`b = cfirpm(n,f,@lowpass,...)`

and`b = cfirpm(n,f,{@lowpass,d},...)`

design a linear-phase (`n/2+d`

delay) filter.### Note

For

`@bandpass`

filters, the first element in the frequency vector must be less than or equal to zero and the last element must be greater than or equal to zero.`@multiband`

designs a linear-phase frequency response filter with arbitrary band amplitudes.`b = cfirpm(n,f,{@multiband,a},...)`

and`b = cfirpm(n,f,{@multiband,a,d},...)`

specify vector`a`

containing the desired amplitudes at the band edges in`f`

. The desired amplitude at frequencies between pairs of points`f(k)`

and`f(k+1)`

for`k`

odd is the line segment connecting the points`(f(k),a(k))`

and`(f(k+1),a(k+1))`

.`@differentiator`

designs a linear-phase differentiator. For these designs, zero-frequency must be in a transition band, and band weighting is set to be inversely proportional to frequency.`b = cfirpm(n,f,{@differentiator,fs},...)`

and`b = cfirpm(n,f,{@differentiator,fs,d},...)`

specify the sample rate`fs`

used to determine the slope of the differentiator response. If omitted,`fs`

defaults to 1.`@hilbfilt`

designs a linear-phase Hilbert transform filter response. For Hilbert designs, zero-frequency must be in a transition band.`b = cfirpm(n,f,@hilbfilt,...)`

and`b = cfirpm(N,F,{@hilbfilt,d},...)`

design a linear-phase (`n/2+d`

delay) Hilbert transform filter.`@invsinc`

designs a linear-phase inverse-sinc filter response.`b = cfirpm(n,f,{@invsinc,a},...)`

and`b = cfirpm(n,f,{@invsinc,a,d},...)`

specify gain`a`

for the sinc function, computed as sinc(`a`

**g*), where*g*contains the optimization grid frequencies normalized to the range [–1,1]. By default,`a`

= 1. The group-delay offset is`d`

, such that the filter response will have a group delay of*N*/2 +`d`

in units of the sample interval, where N is the filter order. Negative values create less delay and positive values create more delay. By default,`d`

= 0.

`b = cfirpm(n,f,@`

uses
the real, nonnegative weights in vector * fresp*,w)

`w`

to weight
the fit in each frequency band. The length of `w`

is
half the length of `f`

, so there is exactly one weight
per band.`b = cfirpm(n,f,a)`

is a synonym
for `b = cfirpm(n,f,{@multiband,a})`

.

`b = cfirpm(n,f,a,w)`

applies
an optional set of positive weights, one per band, for use during
optimization. If `w`

is not specified, the weights
are set to unity.

`b = cfirpm(...,`

imposes
a symmetry constraint on the impulse response of the design, where * 'sym'*)

`'sym'`

`'none'`

indicates no symmetry constraint. This is the default if any negative band edge frequencies are passed, or ifdoes not supply a default.`fresp`

`'even'`

indicates a real and even impulse response. This is the default for highpass, lowpass, allpass, bandpass, bandstop, inverse-sinc, and multiband designs.`'odd'`

indicates a real and odd impulse response. This is the default for Hilbert and differentiator designs.`'real'`

indicates conjugate symmetry for the frequency response

If any * 'sym'* option other than

`'none'`

is
specified, the band edges should be specified only over positive frequencies;
the negative frequency region is filled in from symmetry. If a `'sym'`

`fresp`

`fresp`

`'sym'`

`'defaults'`

as the filter order `N`

.`b = cfirpm(...,'skip_stage2')`

disables
the second-stage optimization algorithm, which executes only when `cfirpm`

determines
that an optimal solution has not been reached by the standard `firpm`

error-exchange.
Disabling this algorithm may increase the speed of computation, but
may incur a reduction in accuracy. By default, the second-stage optimization
is enabled.

`b = cfirpm(...,`

enables
the display of intermediate results during the filter design, where * 'debug'*)

`'debug'`

`'trace'`

, `'plots'`

, `'both'`

,
or `'off'`

. By default it is set to `'off'`

.`b = cfirpm(...,{lgrid})`

uses
the integer `lgrid`

to control the density of the
frequency grid, which has roughly `2^nextpow2(lgrid*n)`

frequency
points. The default value for `lgrid`

is `25`

.
Note that the `{lgrid}`

argument must be a 1-by-1
cell array.

Any combination of the * 'sym'*,

`'skip_stage2'`

, `'debug'`

`{lgrid}`

options may be specified.`[b,delta] = cfirpm(...)`

returns
the maximum ripple height `delta`

.

`[b,delta,opt] = cfirpm(...)`

returns
a structure `opt`

of optional results computed by `cfirpm`

and
contains the following fields.

Field | Description |
---|---|

| Frequency grid vector used for the filter design optimization |

| Desired frequency response for each point in |

| Weighting for each point in |

| Actual frequency response for each point in |

| Error at each point in |

| Vector of indices into |

| Vector of extremal frequencies |

User-definable functions may be used, instead of the predefined
frequency response functions for @* fresp*.
The function is called from within

`cfirpm`

using
the following syntax[dh,dw] =fresp(n,f,gf,w,p1,p2,...)

where:

`n`

is the filter order.`f`

is the vector of frequency band edges that appear monotonically between -1 and 1, where 1 corresponds to the Nyquist frequency.`gf`

is a vector of grid points that have been linearly interpolated over each specified frequency band by`cfirpm`

.`gf`

determines the frequency grid at which the response function must be evaluated. This is the same data returned by`cfirpm`

in the`fgrid`

field of the`opt`

structure.`w`

is a vector of real, positive weights, one per band, used during optimization.`w`

is optional in the call to`cfirpm`

; if not specified, it is set to unity weighting before being passed to.`fresp`

`dh`

and`dw`

are the desired complex frequency response and band weight vectors, respectively, evaluated at each frequency in grid`gf`

.`p1`

,`p2`

,`...`

, are optional parameters that may be passed to.`fresp`

Additionally, a preliminary call is made to * fresp* to
determine the default symmetry property

`'sym'`

sym =fresp('defaults',{n,f,[],w,p1,p2,...})

The arguments may be used in determining an appropriate symmetry default as necessary. You can
use the local function `lowpass`

as a template for generating new
frequency response functions. To find the `lowpass`

function, type
`edit cfirpm`

at the command line and search for
`lowpass`

in the `cfirpm`

code. You can copy the
function, modify it, rename it, and save it in your path.

An extended version of the Remez exchange method is implemented
for the complex case. This exchange method obtains the optimal filter
when the equiripple nature of the filter is restricted to have `n+2`

extremals.
When it does not converge, the algorithm switches to an ascent-descent
algorithm that takes over to finish the convergence to the optimal
solution. See the references for further details.

[1] Karam, L.J., and J.H. McClellan. “Complex
Chebyshev Approximation for FIR Filter Design.” *IEEE ^{®} Trans.
on Circuits and Systems II,*March 1995. Pgs. 207-216.

[2] Karam, L.J. *Design of Complex
Digital FIR Filters in the Chebyshev Sense, *Ph.D. Thesis,
Georgia Institute of Technology, March 1995.

[3] Demjanjov, V.F., and V.N. Malozemov.* Introduction
to Minimax, *New York: John Wiley & Sons, 1974.