summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Frank Palazzolo <frank@avoidspikes.com>2020-04-14 10:10:38 -0400
committer GitHub <noreply@github.com>2020-04-14 10:10:38 -0400
commit16ed4f6108bee7d887cb54a470722cf3212a8968 (patch)
treee5d0aed335904319e3251977313c060b8dba7750
parent07b3e2b708712922cf42765df5c1c76c3de25d54 (diff)
Document DISCRETE_FILTER1 and DISCRETE_FILTER2 better (#6551)
-rw-r--r--src/devices/sound/disc_flt.hxx96
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);
}