//DISCRETE_CLASS_DESTRUCTOR(_name) //~discrete_dst_sallen_key_node() { } // discrete_base_node //DISCRETE_RESET(dst_sallen_key) public override void reset() { discrete_op_amp_filt_info info = (discrete_op_amp_filt_info)custom_data(); //DISCRETE_DECLARE_INFO(discrete_op_amp_filt_info); double freq = 0; double q = 0; switch ((int)DST_SALLEN_KEY__TYPE) { case DISC_SALLEN_KEY_LOW_PASS: freq = 1.0 / (2.0 * M_PI * std.sqrt(info.c1 * info.c2 * info.r1 * info.r2)); q = std.sqrt(info.c1 * info.c2 * info.r1 * info.r2) / (info.c2 * (info.r1 + info.r2)); break; default: fatalerror("Unknown sallen key filter type\n"); break; } calculate_filter2_coefficients(this, freq, 1.0 / q, DISC_FILTER_LOWPASS, ref m_fc); set_output(0, 0); }
//DISCRETE_STEP(dst_op_amp_filt) public void step() { //DISCRETE_DECLARE_INFO(discrete_op_amp_filt_info) discrete_op_amp_filt_info info = (discrete_op_amp_filt_info)custom_data(); double v_out = 0; double i; double v = 0; if (DST_OP_AMP_FILT__ENABLE() != 0) { if (m_is_norton != 0) { v = DST_OP_AMP_FILT__INP1() - OP_AMP_NORTON_VBE; if (v < 0) { v = 0; } } else { /* Millman the input voltages. */ i = m_iFixed; switch (m_type) { case DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A: i += (DST_OP_AMP_FILT__INP1() - DST_OP_AMP_FILT__INP2()) / info.r1; if (info.r2 != 0) { i += (m_vP - DST_OP_AMP_FILT__INP2()) / info.r2; } if (info.r3 != 0) { i += (m_vN - DST_OP_AMP_FILT__INP2()) / info.r3; } break; default: i += (DST_OP_AMP_FILT__INP1() - m_vRef) / info.r1; if (info.r2 != 0) { i += (DST_OP_AMP_FILT__INP2() - m_vRef) / info.r2; } break; } v = i * m_rTotal; } switch (m_type) { case DISC_OP_AMP_FILTER_IS_LOW_PASS_1: m_vC1 += (v - m_vC1) * m_exponentC1; v_out = m_vC1 * m_gain + info.vRef; break; case DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A: m_vC1 += (v - m_vC1) * m_exponentC1; v_out = m_vC1 * m_gain + DST_OP_AMP_FILT__INP2(); break; case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1: v_out = (v - m_vC1) * m_gain + info.vRef; m_vC1 += (v - m_vC1) * m_exponentC1; break; case DISC_OP_AMP_FILTER_IS_BAND_PASS_1: v_out = (v - m_vC2); m_vC2 += (v - m_vC2) * m_exponentC2; m_vC1 += (v_out - m_vC1) * m_exponentC1; v_out = m_vC1 * m_gain + info.vRef; break; case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON: m_vC1 += (v - m_vC1) * m_exponentC1; m_vC2 += (m_vC1 - m_vC2) * m_exponentC2; v = m_vC2; v_out = v - m_vC3; m_vC3 += (v - m_vC3) * m_exponentC3; i = v_out / m_rTotal; v_out = (m_iFixed - i) * info.rF; break; case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON: v_out = v - m_vC1; m_vC1 += (v - m_vC1) * m_exponentC1; i = v_out / m_rTotal; v_out = (m_iFixed - i) * info.rF; break; case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M: case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON: v_out = -m_fc.a1 * m_fc.y1 - m_fc.a2 * m_fc.y2 + m_fc.b0 * v + m_fc.b1 * m_fc.x1 + m_fc.b2 * m_fc.x2 + m_vRef; m_fc.x2 = m_fc.x1; m_fc.x1 = v; m_fc.y2 = m_fc.y1; break; } /* Clip the output to the voltage rails. * This way we get the original distortion in all it's glory. */ if (v_out > m_vP) { v_out = m_vP; } if (v_out < m_vN) { v_out = m_vN; } m_fc.y1 = v_out - m_vRef; set_output(0, v_out); } else { set_output(0, 0); } }
//DISCRETE_CLASS_DESTRUCTOR(_name) //~discrete_dst_op_amp_filt_node() { } // discrete_base_node //DISCRETE_RESET(dst_op_amp_filt) public override void reset() { discrete_op_amp_filt_info info = (discrete_op_amp_filt_info)custom_data(); //DISCRETE_DECLARE_INFO(discrete_op_amp_filt_info) /* Convert the passed filter type into an int for easy use. */ m_type = (int)DST_OP_AMP_FILT__TYPE() & DISC_OP_AMP_FILTER_TYPE_MASK; m_is_norton = (int)DST_OP_AMP_FILT__TYPE() & DISC_OP_AMP_IS_NORTON; if (m_is_norton != 0) { m_vRef = 0; m_rTotal = info.r1; if (m_type == (DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON)) { m_rTotal += info.r2 + info.r3; } /* Setup the current to the + input. */ m_iFixed = (info.vP - OP_AMP_NORTON_VBE) / info.r4; /* Set the output max. */ m_vP = info.vP - OP_AMP_NORTON_VBE; m_vN = info.vN; } else { m_vRef = info.vRef; /* Set the output max. */ m_vP = info.vP - OP_AMP_VP_RAIL_OFFSET; m_vN = info.vN; /* Work out the input resistance. It is all input and bias resistors in parallel. */ m_rTotal = 1.0 / info.r1; /* There has to be an R1. Otherwise the table is wrong. */ if (info.r2 != 0) { m_rTotal += 1.0 / info.r2; } if (info.r3 != 0) { m_rTotal += 1.0 / info.r3; } m_rTotal = 1.0 / m_rTotal; m_iFixed = 0; m_rRatio = info.rF / (m_rTotal + info.rF); m_gain = -info.rF / m_rTotal; } switch (m_type) { case DISC_OP_AMP_FILTER_IS_LOW_PASS_1: case DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A: m_exponentC1 = RC_CHARGE_EXP(info.rF * info.c1); m_exponentC2 = 0; break; case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1: m_exponentC1 = RC_CHARGE_EXP(m_rTotal * info.c1); m_exponentC2 = 0; break; case DISC_OP_AMP_FILTER_IS_BAND_PASS_1: m_exponentC1 = RC_CHARGE_EXP(info.rF * info.c1); m_exponentC2 = RC_CHARGE_EXP(m_rTotal * info.c2); break; case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON: if (info.r2 == 0) { m_rTotal = info.r1; } else { m_rTotal = RES_2_PARALLEL(info.r1, info.r2); } goto case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M; //[[fallthrough]]; case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M: { double fc = 1.0 / (2 * M_PI * std.sqrt(m_rTotal * info.rF * info.c1 * info.c2)); double d = (info.c1 + info.c2) / std.sqrt(info.rF / m_rTotal * info.c1 * info.c2); double gain = -info.rF / m_rTotal * info.c2 / (info.c1 + info.c2); calculate_filter2_coefficients(this, fc, d, DISC_FILTER_BANDPASS, ref m_fc); m_fc.b0 *= gain; m_fc.b1 *= gain; m_fc.b2 *= gain; if (m_is_norton != 0) { m_vRef = (info.vP - OP_AMP_NORTON_VBE) / info.r3 * info.rF; } else { m_vRef = info.vRef; } break; } case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON: m_exponentC1 = RC_CHARGE_EXP(RES_2_PARALLEL(info.r1, info.r2 + info.r3 + info.r4) * info.c1); m_exponentC2 = RC_CHARGE_EXP(RES_2_PARALLEL(info.r1 + info.r2, info.r3 + info.r4) * info.c2); m_exponentC3 = RC_CHARGE_EXP((info.r1 + info.r2 + info.r3 + info.r4) * info.c3); break; case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON: m_exponentC1 = RC_CHARGE_EXP(info.r1 * info.c1); break; } /* At startup there is no charge on the caps and output is 0V in relation to vRef. */ m_vC1 = 0; m_vC1b = 0; m_vC2 = 0; m_vC3 = 0; set_output(0, info.vRef); }