/// <summary> /// 2nd degree state variable lowpass notch or highpass notch filter /// 今田悟 and 深谷武彦,実用アナログフィルタ設計法,CQ出版,1989 /// p.63 and p.58 Figure 2.15(a) /// </summary> private void DrawStateVariableNotchSecondOrderFilter(int nStage, SecondOrderComplexRationalPolynomial ps, double r, double c) { /* * 有理多項式は周波数が正規化されているので、まず係数を周波数スケーリングする。 * * H(s) = { (s/ωc)^2 + n0 } { (s/ωc)^2 + d1*(s/ωc) + d0 } * * ⇩ 分子と分母にωc^2を掛ける。 * * H(s) = { s^2 + ωc^2 n0 } { s^2 + ωc * d1 + ωc^2 d0 } * ___ * ωp = ωc * √d0 * ___ * ωn = ωc * √n0 * * Q = ωp / { d1 * ωc } * * ωp^2 = R2/{R3R6R7C1C2} * * ωn^2 = R8ωp^2/R9 * * Q=(1+R4/R5)(1/{1/R1+1/R2+1/R3})sqrt(R6C1/R2R3R7C2) * * 設計法18 * * R1=R2=R3=R4=R9=R10=R * * C1=C2=C * * Rf=1 / { ωp*Cf } * * R6=R7=Rf * * R5=R/{3Q-1} * * R8={ωn^2/ωp^2}R * */ double ωc = CutoffFrequencyHz * 2.0 * Math.PI; double ωp = ωc * Math.Sqrt(ps.D(0).real); double ωn = ωc * Math.Sqrt(ps.N(0).real); double Q = ωp / ps.D(1).real / ωc; /* Test p64 計算例18 * Q = 5; * ωp = 2.0 * Math.PI * 1000; * ωn = 2.0 * Math.PI * 2000; */ double rf = 1.0 / ωp / c; double r5 = r / (3.0 * Q - 1.0); double r8 = ωn * ωn * r / ωp / ωp; /* * Console.WriteLine("R={0} C={1} ωc={2} ωp={3} ωn={4} Q={5} Rf={6} R5={7} r8={8}", * r, c, ωc, ωp, ωn, Q, rf, r5, r8); */ textBoxParameters.Text += string.Format("Stage {0} is 2nd degree State variable lowpass notch filter. Fp={1}Hz Fn={2}Hz Q={3:G3}\n", nStage + 1, ValueString(ωp / 2 / Math.PI), ValueString(ωn / 2 / Math.PI), Q); // 抵抗R1 AddResistorH(mX, CIRCUIT_INPUT_LINE_H, ResistorValueString(r)); { // R1の右から出る横線。オペアンプA1の入力につながる。 var p = new List <Point>(); p.Add(new Point(mX + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + RESISTOR_LENGTH + 30, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + RESISTOR_LENGTH + 30, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + RESISTOR_LENGTH + 30 + 10, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); AddLineStrip(p, mBrush); } mX += RESISTOR_LENGTH + 20; { // R1の右から出て、R2につながる線。 var p = new List <Point>(); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 20, CIRCUIT_INPUT_LINE_H - 30)); AddLineStrip(p, mBrush); } // 抵抗R2 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H - 30, ResistorValueString(r)); { // R2の左から出て、R3につながる線。 var p = new List <Point>(); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H - 60)); p.Add(new Point(mX + 20, CIRCUIT_INPUT_LINE_H - 60)); AddLineStrip(p, mBrush); } // 抵抗R3 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H - 60, ResistorValueString(r)); { // オペアンプA1の左下から出て、R5につながる線。 var p = new List <Point>(); p.Add(new Point(mX + 20, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H + 50)); AddLineStrip(p, mBrush); } // 抵抗R5 AddResistorV(mX, CIRCUIT_INPUT_LINE_H + 50, ResistorValueString(r5)); // R5からGNDに接続する縦線。 AddLine(mX, CIRCUIT_INPUT_LINE_H + 50 + RESISTOR_LENGTH, mX, CIRCUIT_INPUT_LINE_H + 50 + RESISTOR_LENGTH + 20, mBrush); AddGnd(mX, CIRCUIT_INPUT_LINE_H + 50 + RESISTOR_LENGTH + 20); // R5の上からR4の左に接続する線。 AddLine(mX, CIRCUIT_INPUT_LINE_H + 40, mX + 20, CIRCUIT_INPUT_LINE_H + 40, mBrush); // 抵抗R4 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H + 40, ResistorValueString(r)); mX += 20; // オペアンプA1 AddOpamp(mX, CIRCUIT_INPUT_LINE_H, PlusPosition.Bottom); { // 抵抗R2からオペアンプA1の出力につながる線。 var p = new List <Point>(); p.Add(new Point(mX + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + OPAMP_WIDTH, CIRCUIT_INPUT_LINE_H)); AddLineStrip(p, mBrush); } mX += OPAMP_WIDTH + 10; { // オペアンプA1出力 → R8入力 var p = new List <Point>(); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H + 40 + 30)); p.Add(new Point(mX + 20, CIRCUIT_INPUT_LINE_H + 40 + 30)); AddLineStrip(p, mBrush); } // 抵抗R8 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H + 40 + 30, ResistorValueString(r8)); // R2の右からR6の左に接続する線。 AddLine(mX, CIRCUIT_INPUT_LINE_H - 30, mX + 20, CIRCUIT_INPUT_LINE_H - 30, mBrush); // 抵抗R6 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H - 30, ResistorValueString(rf)); // R6の右からC1の左に接続する線。 AddLine(mX + 20 + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H - 30, mX + 20 + RESISTOR_LENGTH + 40, CIRCUIT_INPUT_LINE_H - 30, mBrush); mX += 20 + RESISTOR_LENGTH + 20; // C1 AddCapacitorH(mX + 20, CIRCUIT_INPUT_LINE_H - 30, CapacitorValueString(c)); { // C1からオペアンプA2の出力につながる線。 var p = new List <Point>(); p.Add(new Point(mX + 20 + CAPACITOR_THICKNESS, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 10 + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 10 + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + 10 + OPAMP_WIDTH, CIRCUIT_INPUT_LINE_H)); AddLineStrip(p, mBrush); } { // R6からオペアンプA2の左上につながる線。 var p = new List <Point>(); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 10, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); AddLineStrip(p, mBrush); } { // オペアンプA2の左下からGNDにつながる線。 var p = new List <Point>(); p.Add(new Point(mX + 10, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX, CIRCUIT_INPUT_LINE_H + 20)); AddLineStrip(p, mBrush); } // オペアンプA2 AddOpamp(mX + 10, CIRCUIT_INPUT_LINE_H, PlusPosition.Bottom); AddGnd(mX, CIRCUIT_INPUT_LINE_H + 20); mX += 10 + OPAMP_WIDTH; { // R4の右からオペアンプA2の出力につながる線。 var p = new List <Point>(); p.Add(new Point(mX - OPAMP_WIDTH - 10 - 20 - RESISTOR_LENGTH - 20 - 10 - OPAMP_WIDTH + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H + 40)); p.Add(new Point(mX + 10, CIRCUIT_INPUT_LINE_H + 40)); p.Add(new Point(mX + 10, CIRCUIT_INPUT_LINE_H)); AddLineStrip(p, mBrush); } mX += 10; // オペアンプの出力からR7 AddLine(mX, CIRCUIT_INPUT_LINE_H - 30, mX + 20, CIRCUIT_INPUT_LINE_H - 30, mBrush); // 抵抗R7 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H - 30, ResistorValueString(rf)); // R7 → C2 AddLine(mX + 20 + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H - 30, mX + 20 + RESISTOR_LENGTH + 40, CIRCUIT_INPUT_LINE_H - 30, mBrush); // C2 AddCapacitorH(mX + 20 + RESISTOR_LENGTH + 40, CIRCUIT_INPUT_LINE_H - 30, CapacitorValueString(c)); { // R7 → オペアンプA3の左上 var p = new List <Point>(); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 30, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); AddLineStrip(p, mBrush); } { // オペアンプA3の左下 → GND var p = new List <Point>(); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 30, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H + 20)); AddLineStrip(p, mBrush); } mX += 20 + RESISTOR_LENGTH + 30; // オペアンプA3 AddOpamp(mX, CIRCUIT_INPUT_LINE_H, PlusPosition.Bottom); AddGnd(mX - 10, CIRCUIT_INPUT_LINE_H + 20); { // C2の出力 → オペアンプA3の出力 var p = new List <Point>(); p.Add(new Point(mX + 10 + CAPACITOR_THICKNESS, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + OPAMP_WIDTH, CIRCUIT_INPUT_LINE_H)); AddLineStrip(p, mBrush); } { // R3の出力 → オペアンプA3の出力 var p = new List <Point>(); p.Add(new Point(mX - 10 - 20 - RESISTOR_LENGTH - 20 - 10 - OPAMP_WIDTH - 10 - 20 - RESISTOR_LENGTH - 20 - 10 - OPAMP_WIDTH - 20 + 20 + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H - 60)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 60)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 30)); AddLineStrip(p, mBrush); } mX += OPAMP_WIDTH + 10; // オペアンプA3 → R9 AddLine(mX, CIRCUIT_INPUT_LINE_H, mX + 20, CIRCUIT_INPUT_LINE_H, mBrush); // 抵抗R9 AddResistorH(mX + 20, CIRCUIT_INPUT_LINE_H, ResistorValueString(r)); { // R9の出力 → R10入力 var p = new List <Point>(); p.Add(new Point(mX + 20 + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 20, CIRCUIT_INPUT_LINE_H - 30)); AddLineStrip(p, mBrush); } { // R9の出力 → オペアンプA4左上 var p = new List <Point>(); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 10, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 10, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 20, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); AddLineStrip(p, mBrush); } { // オペアンプA4左下 → GND var p = new List <Point>(); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 20, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 10, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 20 + RESISTOR_LENGTH + 20 + 10, CIRCUIT_INPUT_LINE_H + 20)); AddLineStrip(p, mBrush); } // 抵抗R10 AddResistorH(mX + 20 + RESISTOR_LENGTH + 20 + 20, CIRCUIT_INPUT_LINE_H - 30, ResistorValueString(r)); mX += 20 + RESISTOR_LENGTH + 40; // オペアンプA4 AddOpamp(mX, CIRCUIT_INPUT_LINE_H, PlusPosition.Bottom); AddGnd(mX - 10, CIRCUIT_INPUT_LINE_H + 20); { // R8の出力 → オペアンプA4左上入力 var p = new List <Point>(); p.Add(new Point(mX - 30, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX - 30, CIRCUIT_INPUT_LINE_H + 40 + 30)); p.Add(new Point(mX - 40 - RESISTOR_LENGTH - 20 - 10 - OPAMP_WIDTH - 10 - 20 - RESISTOR_LENGTH - 20 - 10 - OPAMP_WIDTH - 10 - 20, CIRCUIT_INPUT_LINE_H + 40 + 30)); AddLineStrip(p, mBrush); } { // R10出力 → オペアンプA4出力 var p = new List <Point>(); p.Add(new Point(mX + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + OPAMP_WIDTH, CIRCUIT_INPUT_LINE_H)); AddLineStrip(p, mBrush); } // オペアンプA4出力 → 出力 AddLine(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H, mX + OPAMP_WIDTH + 70, CIRCUIT_INPUT_LINE_H, mBrush); mX += OPAMP_WIDTH + 70; }
/// <summary> /// Sallen-Key Minimum Sensitivity 2nd degree Lowpass filter /// Analog Electronic Filters pp.470 /// </summary> private void DrawSallenKeyLowpassSecondOrderFilter(int nStage, SecondOrderComplexRationalPolynomial ps, double resistorValue) { /* k=1 * R1=R2=1 * とする。 * * C1=2Q/ω0 * * C2=1/2ω0Q * * ___ * ω0 = √d0 * Q = ω0/d1 */ double ω0 = Math.Sqrt(ps.D(0).real); double Q = ω0 / ps.D(1).real; double r1 = 1; double r2 = 1; double c1 = 2.0 * Q / ω0; double c2 = 1.0 / 2.0 / ω0 / Q; // 周波数スケーリング。キャパシタの値をωcで割る。 double ωc = CutoffFrequencyHz * 2.0 * Math.PI; c1 /= ωc; c2 /= ωc; // 最後に抵抗値を全て10 * 1000倍、キャパシターの容量を10*1000分の一する。 r1 *= resistorValue; r2 *= resistorValue; c1 /= resistorValue; c2 /= resistorValue; string message = ""; if (4.0 <= Q) { message = " : HighQ and unstable"; } textBoxParameters.Text += string.Format("Stage {0} is Sallen-Key LPF. ω0={1:G3} Q={2:G3}{3}\n", nStage + 1, ω0, Q, message); // 抵抗R1 AddResistorH(mX, CIRCUIT_INPUT_LINE_H, ResistorValueString(r1)); // R1の右から出る横線。R2の入力につながる。 AddLine(mX + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H, mX + RESISTOR_LENGTH + 40, CIRCUIT_INPUT_LINE_H, mBrush); mX += RESISTOR_LENGTH + 40; // 抵抗R2 AddResistorH(mX, CIRCUIT_INPUT_LINE_H, ResistorValueString(r2)); { // 抵抗R2の右から出る横線。オペアンプの+入力につながる。 var p = new List <Point>(); p.Add(new Point(mX + RESISTOR_LENGTH, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + RESISTOR_LENGTH + 20 + 40, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX + RESISTOR_LENGTH + 20 + 40, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + RESISTOR_LENGTH + 20 + 40 + 10, CIRCUIT_INPUT_LINE_H - OPAMP_INPUT_H_OFFS)); AddLineStrip(p, mBrush); } { // 抵抗R1-R2とキャパシタC1をつなげる縦線。 var p = new List <Point>(); p.Add(new Point(mX - 20, CIRCUIT_INPUT_LINE_H)); p.Add(new Point(mX - 20, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + RESISTOR_LENGTH + 20, CIRCUIT_INPUT_LINE_H - 30)); AddLineStrip(p, mBrush); } mX += RESISTOR_LENGTH + 20; // キャパシターC1 AddCapacitorH(mX, CIRCUIT_INPUT_LINE_H - 30, CapacitorValueString(c1)); { // キャパシターC1からオペアンプのー入力。 var p = new List <Point>(); p.Add(new Point(mX + CAPACITOR_THICKNESS, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 40 + 10 + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H - 30)); p.Add(new Point(mX + 40 + 10 + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H + 30)); p.Add(new Point(mX + 40, CIRCUIT_INPUT_LINE_H + 30)); p.Add(new Point(mX + 40, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); p.Add(new Point(mX + 40 + 10, CIRCUIT_INPUT_LINE_H + OPAMP_INPUT_H_OFFS)); AddLineStrip(p, mBrush); } // R2からC2に接続する縦線。 AddLine(mX, CIRCUIT_INPUT_LINE_H, mX, CIRCUIT_INPUT_LINE_H + 30, mBrush); // キャパシターC2 AddCapacitorV(mX, CIRCUIT_INPUT_LINE_H + 30, CapacitorValueString(c2)); // C2からGNDに接続する縦線。 AddLine(mX, CIRCUIT_INPUT_LINE_H + 30 + CAPACITOR_THICKNESS, mX, CIRCUIT_INPUT_LINE_H + 30 + CAPACITOR_THICKNESS + RESISTOR_LENGTH + 10, mBrush); AddGnd(mX, CIRCUIT_INPUT_LINE_H + 30 + CAPACITOR_THICKNESS + RESISTOR_LENGTH + 10); mX += 40 + 10; AddOpamp(mX, CIRCUIT_INPUT_LINE_H); // オペアンプの出力線。 AddLine(mX + OPAMP_WIDTH, CIRCUIT_INPUT_LINE_H, mX + OPAMP_WIDTH + 50, CIRCUIT_INPUT_LINE_H, mBrush); AddFilledCircle(mX + OPAMP_WIDTH + 10, CIRCUIT_INPUT_LINE_H, 5, mBrush); mX += OPAMP_WIDTH + 50; }