diff options
author | 2020-04-14 10:10:38 -0400 | |
---|---|---|
committer | 2020-04-14 10:10:38 -0400 | |
commit | 16ed4f6108bee7d887cb54a470722cf3212a8968 (patch) | |
tree | e5d0aed335904319e3251977313c060b8dba7750 | |
parent | 07b3e2b708712922cf42765df5c1c76c3de25d54 (diff) |
Document DISCRETE_FILTER1 and DISCRETE_FILTER2 better (#6551)
-rw-r--r-- | src/devices/sound/disc_flt.hxx | 96 |
1 files changed, 78 insertions, 18 deletions
diff --git a/src/devices/sound/disc_flt.hxx b/src/devices/sound/disc_flt.hxx index 346f18c04af..3a167137250 100644 --- a/src/devices/sound/disc_flt.hxx +++ b/src/devices/sound/disc_flt.hxx @@ -29,7 +29,6 @@ * ************************************************************************/ - /************************************************************************ * * DST_CRFILTER - Usage of node_description values for CR filter @@ -73,7 +72,6 @@ DISCRETE_RESET(dst_crfilter) set_output(0, DST_CRFILTER__IN); } - /************************************************************************ * * DST_FILTER1 - Generic 1st order filter @@ -83,6 +81,30 @@ DISCRETE_RESET(dst_crfilter) * input[2] - Frequency value (initialization only) * input[3] - Filter type (initialization only) * + * This creates an IIR Digital Filter from an Analog Filter, + * Using the Bilinear Transformation, with pre-warping + * + * wc = 2*pi*fc (cutoff frequency) + * (wc modified by pre-warping formula wc = (2/T)*tan(wc*T/2) + * + * Prototype filters come from "Active-Filter Cookbook" by Don Lancaster, Ch. 3 + * + * Low Pass: High Pass: + * + * K*wc K*s + * H(s) = ------ H(s) = ------ + * s + wc s + wc + * + * Apply bilinear transform: s = (2/T) * (1-z^-1) / (1+z^1) + * + * G*(b0 + b1*z^-1) + * H(z) = ---------------- + * 1 + a1*z^-1 + * + * Which gives: + * + * y(k) = -a1*y(k-1) + b0*K*x(k) + b1*K*x(k-1) + * ************************************************************************/ #define DST_FILTER1__ENABLE DISCRETE_INPUT(0) #define DST_FILTER1__IN DISCRETE_INPUT(1) @@ -92,18 +114,18 @@ DISCRETE_RESET(dst_crfilter) static void calculate_filter1_coefficients(discrete_base_node *node, double fc, double type, struct discrete_filter_coeff &coeff) { - double den, w, two_over_T; + double den, wc, two_over_T; /* calculate digital filter coefficents */ - /*w = 2.0*M_PI*fc; no pre-warping */ - w = node->sample_rate()*2.0*tan(M_PI*fc/node->sample_rate()); /* pre-warping */ + /*wc = 2.0*M_PI*fc; no pre-warping */ + wc = node->sample_rate()*2.0*tan(M_PI*fc/node->sample_rate()); /* pre-warping */ two_over_T = 2.0*node->sample_rate(); - den = w + two_over_T; - coeff.a1 = (w - two_over_T)/den; + den = wc + two_over_T; + coeff.a1 = (wc - two_over_T)/den; if (type == DISC_FILTER_LOWPASS) { - coeff.b0 = coeff.b1 = w/den; + coeff.b0 = coeff.b1 = wc/den; } else if (type == DISC_FILTER_HIGHPASS) { @@ -151,6 +173,44 @@ DISCRETE_RESET(dst_filter1) * input[3] - Damping value (initialization only) * input[4] - Filter type (initialization only) * + * This creates an IIR Digital Filter from an Analog Filter, + * Using the Bilinear Transformation, with pre-warping + * + * wc = 2*pi*fc (cutoff frequency) + * (wc modified by pre-warping formula wc = (2/T)*tan(wc*T/2) + * + * Prototype filters come from "Active-Filter Cookbook" by Don Lancaster, Ch. 3 + * (d is the Damping Factor, which is also 1/Q) + * + * Low Pass: + * + * K*wc^2 + * H(s) = ------------------- + * s^2 + d*wc*s + wc^2 + * + * Band Pass: + * + * K*wc*s + * H(s) = ------------------- + * s^2 + d*wc*s + wc^2 + * + * + * High Pass: + * + * K*s^2 + * H(s) = ------------------- + * s^2 + d*wc*s + wc^2 + * + * Apply bilinear transform: s = (2/T) * (1-z^-1) / (1+z^-1) + * + * K*(b0 + b1*z^-1 + b2*z^-2) + * H(z) = -------------------------- + * 1 + a1*z^-1 + a2*z^-2 + * + * Which gives: + * + * y(k) = -a1*y(k-1) - a2*y(k-2) + b0*K*x(k) + b1*K*x(k-1) + b2*K*x(k-2) + * ************************************************************************/ #define DST_FILTER2__ENABLE DISCRETE_INPUT(0) #define DST_FILTER2__IN DISCRETE_INPUT(1) @@ -162,30 +222,30 @@ static void calculate_filter2_coefficients(discrete_base_node *node, double fc, double d, double type, struct discrete_filter_coeff &coeff) { - double w; /* cutoff freq, in radians/sec */ - double w_squared; + double wc; /* cutoff freq, in radians/sec */ + double wc_squared; double den; /* temp variable */ double two_over_T = 2 * node->sample_rate(); double two_over_T_squared = two_over_T * two_over_T; /* calculate digital filter coefficents */ - /*w = 2.0*M_PI*fc; no pre-warping */ - w = node->sample_rate() * 2.0 * tan(M_PI * fc / node->sample_rate()); /* pre-warping */ - w_squared = w * w; + /*wc = 2.0*M_PI*fc; no pre-warping */ + wc = node->sample_rate() * 2.0 * tan(M_PI * fc / node->sample_rate()); /* pre-warping */ + wc_squared = wc * wc; - den = two_over_T_squared + d*w*two_over_T + w_squared; + den = two_over_T_squared + d*wc*two_over_T + wc_squared; - coeff.a1 = 2.0 * (-two_over_T_squared + w_squared) / den; - coeff.a2 = (two_over_T_squared - d * w * two_over_T + w_squared) / den; + coeff.a1 = 2.0 * (-two_over_T_squared + wc_squared) / den; + coeff.a2 = (two_over_T_squared - d * wc * two_over_T + wc_squared) / den; if (type == DISC_FILTER_LOWPASS) { - coeff.b0 = coeff.b2 = w_squared/den; + coeff.b0 = coeff.b2 = wc_squared/den; coeff.b1 = 2.0 * (coeff.b0); } else if (type == DISC_FILTER_BANDPASS) { - coeff.b0 = d * w * two_over_T / den; + coeff.b0 = d * wc * two_over_T / den; coeff.b1 = 0.0; coeff.b2 = -(coeff.b0); } |