Improve initial conditions
Compute the DC gain of the filter (assuming 0 if unstable) and use that to set the initial conditions of a filter as follows: x(t<0)=x(0) y(t<0)=x(0) × dc_gain
This commit is contained in:
parent
2031d084cc
commit
9a87889dd3
|
@ -18,8 +18,10 @@ This leads to a general IIR filter equation:
|
||||||
|
|
||||||
<code>y(t) = x(t).c[0] + x(t-1).c[1] + … + x(t-N).c[N] - y(t-1).d[0] - y(t-2).d[1] - … - y(t-1-M).d[M]</code>
|
<code>y(t) = x(t).c[0] + x(t-1).c[1] + … + x(t-N).c[N] - y(t-1).d[0] - y(t-2).d[1] - … - y(t-1-M).d[M]</code>
|
||||||
|
|
||||||
For initial conditions, the library sets <code>y(t)</code> for t < 0 to 0,
|
For initial conditions, the library sets <code>y(t)</code> for t < 0 to
|
||||||
and <code>x(t)</code> for t < 0 to <code>x(0)</code>.
|
<code>x(0).G</code> (where <code>G</code> is the DC gain of the filter, or 0 if
|
||||||
|
it looks like the filter is unstable at DC), and <code>x(t)</code> for t < 0
|
||||||
|
to <code>x(0)</code>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,6 @@ iir_filter_new(const struct iir_coeff_t* coeff)
|
||||||
/* allocate space for state */
|
/* allocate space for state */
|
||||||
fi->x = malloc(sizeof(double) * fi->nc);
|
fi->x = malloc(sizeof(double) * fi->nc);
|
||||||
fi->y = malloc(sizeof(double) * fi->nd);
|
fi->y = malloc(sizeof(double) * fi->nd);
|
||||||
memset(fi->y, 0, sizeof(double) * fi->nd);
|
|
||||||
|
|
||||||
return fi;
|
return fi;
|
||||||
}
|
}
|
||||||
|
@ -173,7 +172,6 @@ struct iir_filter_t* iir_filter_copy(const struct iir_filter_t* fi, int state)
|
||||||
copy->xpos = fi->xpos;
|
copy->xpos = fi->xpos;
|
||||||
copy->ypos = fi->ypos;
|
copy->ypos = fi->ypos;
|
||||||
} else {
|
} else {
|
||||||
memset(copy->y, 0, sizeof(double) * fi->nd);
|
|
||||||
copy->ready = copy->xpos = copy->ypos = 0;
|
copy->ready = copy->xpos = copy->ypos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,15 +201,42 @@ iir_get_xy(const double* xy, int pos, int max, int step)
|
||||||
return xy[pos];
|
return xy[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
iir_dc_gain(const struct iir_filter_t* fi)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double sum, gain;
|
||||||
|
|
||||||
|
/* If the forward path DC gain is less than a threshold then we assume ‘fi’
|
||||||
|
* has high pass characteristics.
|
||||||
|
*/
|
||||||
|
sum = 0;
|
||||||
|
for(i = 0; i < fi->nc; ++i) sum += fi->c[i];
|
||||||
|
gain = sum;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for(i = 0; i < fi->nd; ++i) sum += fi->d[i];
|
||||||
|
if(fabs(sum - 1) < 0.001) {
|
||||||
|
/* ergh, looks unstable at DC; pretend DC gain is 0 */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gain /= (1 + sum);
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
iir_filter(struct iir_filter_t* fi, double samp)
|
iir_filter(struct iir_filter_t* fi, double samp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
double gain;
|
||||||
|
|
||||||
while(fi) {
|
while(fi) {
|
||||||
if(!fi->ready) {
|
if(!fi->ready) {
|
||||||
/* initial conditions */
|
/* initial conditions */
|
||||||
|
gain = iir_dc_gain(fi);
|
||||||
for(i = 0; i < fi->nc; ++i) fi->x[i] = samp;
|
for(i = 0; i < fi->nc; ++i) fi->x[i] = samp;
|
||||||
|
for(i = 0; i < fi->nd; ++i) fi->y[i] = samp * gain;
|
||||||
fi->ready = 1;
|
fi->ready = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ is copied into the returned structure, meaning the coefficients can be freed
|
||||||
after this function returns if they will not be needed again.
|
after this function returns if they will not be needed again.
|
||||||
|
|
||||||
The first sample passed through \ref iir_filter() will be used to set initial
|
The first sample passed through \ref iir_filter() will be used to set initial
|
||||||
conditions.
|
conditions (see \ref iir_structure).
|
||||||
|
|
||||||
An arbitrary number of further filters may be chained on to the end of this
|
An arbitrary number of further filters may be chained on to the end of this
|
||||||
instance through \ref iir_filter_chain().
|
instance through \ref iir_filter_chain().
|
||||||
|
|
Loading…
Reference in New Issue