View Raw SPL
/*****************************************************************************
* *
* FIRSAMP.SPL Copyright (C) 2000, 2017 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: FIR filter design using frequency sampling *
* *
* Revisions: 14 Mar 2000 RRR Creation *
* 16 Nov 2017 RRR interpolation factor *
* *
*****************************************************************************/
#if @HELP_FIRSAMP
FIRSAMP
Purpose: Designs an arbitrary FIR filter using frequency sampling
Syntax: FIRSAMP(f, m, fac)
f - An XY series specifying the desired frequencies
(in Hertz) and magnitudes of the filter OR an
explicit series specifying the frequencies only
m - An optional series, explicit desired magnitudes
fac - Optional. An integer, the interpolation factor used
to design the filter. Defaults to 2.
Returns: A series
Example:
W1: {0, 1, 10, 20, 30}
W2: {1, 1, 2, 0, 0}
W3: xy(w1, w2)
W4: firsamp(w3)
W5: mag(fft(w4, bestpow2(length(w4))))
W6: extract(w5, 1, int(length(w5)/2));overp(w3, lred)
W4 contains a 121 point linear phase FIR filter. The filter
has unity gain from at 0 and 1 Hz and a gain of 2 at
10 Hz. W5 shows the magnitude response of the filter. The
original specification is overplotted onto the actual
response in W6.
Example:
W1: {0, 1, 10, 20, 30}
W2: {1, 1, 2, 0, 0}
W3: xy(w1, w2)
W4: firsamp(w3, 10)
W5: mag(fft(w4, bestpow2(length(w4))))
W6: extract(w5, 1, int(length(w5)/2));overp(w3, lred)
Same as above except the interpolation factor is increased
to 10. W4 contains a 599 point linear phase FIR filter.
Example:
W7: firsamp(w1, w2, 10)
Same as above except the frequencies and magnitudes
are specified explicitly.
Remarks:
FIRSAMP sorts the input frequencies in ascending order.
If a frequency of 0 Hz is not specified, a 0 Hz term
equal to the magnitude of the frequency nearest 0
is added to the list.
FIRSAMP produces non-causal filters with linear phase.
The input filter frequency response specification is
interpolated to a regular interval and the IFFT is applied
to derive the filter coefficients. Increasing FAC
produces a filter with more coefficients but the frequency
response will match the input specification more closely.
To reduce ringing at sharp transitions, multiply the
resulting filter coefficients with a windowing function.
For example:
W1: xy({0, 0.3, 0.4, 0.6, 0.7, 0.9}, {0, 1, 0, 0, 0.5, 0.5})
W2: firsamp(w1, 5)
W3: hamming(w2)
W4: filtmag(w2, {1}, 32*1024)
W5: filtmag(w3, {1}, 32*1024)
Note: FILTMAG is available in DADiSP/Filters.
See Also:
Fft
Fftshift
Xyinterp
#endif
/* FIR design via frequency sampling */
firsamp(f, m, fac)
{
local s, h, dx;
/* inputs */
(f, m, fac) = firsamp_parse_args(f, m, fac);
/* sort values in ascending order */
h = grade(f, 1);
f = f[h];
m = m[h];
/* get XY plot so we can interpolate it */
m = xy(f, m);
/* add DC term if required */
if (f[1] != 0)
{
m = {xy({0}, {m[1]}), m};
printf("firsamp: Setting DC Value to %g", m[1]);
}
/* get automatic interpolation interval - one point series */
dx = xyinterp(m, -1, 1);
/* interpolate to equally spaced samples */
m = xyinterp(m, castreal(dx / fac));
/* form full magnitude response */
m = {m, (rev(extract(m, 2, -1)))};
/* inverse transform to get impulse response */
h = real(ifft(m));
/* shift to non causal - automatically sets linear phase */
h = fftshift(h);
return(h);
}
/* input args */
firsamp_parse_args(f, m, fac)
{
if (argc < 3)
{
if (argc < 2)
{
m = yvals(f);
f = xvals(f);
fac = -1;
}
else
{
if (isscalar(m))
{
fac = m;
m = yvals(f);
f = xvals(f);
}
else
{
fac = -1;
}
}
}
if (fac <= 0)
{
fac = 2;
}
return(f, m, fac);
}