├── LICENSE ├── README.md ├── circuits.mac └── images └── pi_attenuator.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ted Yapo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # maxima-circuits 2 | Maxima functions for circuit calculations 3 | 4 | See also the accompanying [Hackaday article](https://hackaday.com/2019/02/28/computer-algebra-for-electronic-design/). 5 | 6 | # Usage 7 | Load the functions using 8 | 9 | load("circuits.mac")$ 10 | 11 | You may also place this line in your startup script (typically ~/.maxima/maxima-init.mac or ~/.maxima/wxmaxima-init.mac) 12 | 13 | # par(...) 14 | Calculate reciprical of sum of reciprocals of supplied arguments, aka the harmonic sum. This calculates equivalents for parallel resistor or inductor values, or for series capacitors. 15 | 16 | Examples: 17 | 18 | (%i2) par(100, 75); 19 | (%o2) 42.85714285714285 20 | 21 | (%i3) par(r1, r2, r3); 22 | 1 23 | (%o3) ------------ 24 | 1 1 1 25 | -- + -- + -- 26 | r3 r2 r1 27 | # vdiv(r_top, r_bot) 28 | Calculate output of a voltage divider as a ratio of the input voltage. 29 | 30 | Examples: 31 | 32 | (%i4) 5*vdiv(75, 150); 33 | (%o4) 3.333333333333333 34 | 35 | (%i5) vdiv(r1, r2) = 3.3/5; 36 | r2 37 | (%o5) ------- = 0.6599999999999999 38 | r2 + r1 39 | 40 | # pref(x, E) 41 | Find preferred values from EIA standard "E series." The following values for E are allowed: 42 | 43 | E3 : 50% tolerance 44 | E6 : 20% tolerance 45 | E12 : 10% tolerance 46 | E24 : 5% tolerance 47 | E48 : 2% tolerance 48 | E96 : 1% tolerance 49 | E192 : <1% tolerance 50 | E48_24 : combined vales from E48 and E24 series 51 | E96_24 : combined vales from E96 and E24 series 52 | E192_24 : combined vales from E192 and E24 series 53 | 54 | Examples: 55 | 56 | (%i6) pref(50, E3); 57 | (%o6) 47.0 58 | (%i7) pref(50, E24); 59 | (%o7) 51.0 60 | (%i8) pref(50, E96); 61 | (%o8) 49.9 62 | 63 | # VrtodB(Vr) 64 | Convert voltage ratio to dB 65 | 66 | Example: 67 | 68 | (%i2) VrtodB(sqrt(2)); 69 | (%o2) 3.010299956639812 70 | 71 | # dBtoVr(dB) 72 | Convert dB to voltage ratio 73 | 74 | Example: 75 | 76 | (%i6) dBtoVr(6); 77 | (%o6) 1.995262314968879 78 | 79 | # Comprehensive Example 80 | Let's design a 6dB pi attenuator for a 50-ohm system. The circuit looks like this: 81 | 82 | ![pi attenuator schematic](images/pi_attenuator.png) 83 | 84 | First, we write an expression for the output impedance: 85 | 86 | (%i14) Zout: par(r2, r1+par(r2, 50)); 87 | 1 88 | (%o14) ------------------- 89 | 1 1 90 | -- + -------------- 91 | r2 1 92 | --------- + r1 93 | 1 94 | -- + 0.02 95 | r2 96 | 97 | next, an expression for the input to output voltage ratio (Vout/Vin): 98 | 99 | (%i15) Vout: vdiv(r1, par(r2, 50)); 100 | 1 101 | (%o15) ---------------------------- 102 | 1 1 103 | (--------- + r1) (-- + 0.02) 104 | 1 r2 105 | -- + 0.02 106 | r2 107 | 108 | Using these expressions, we create a system of two equations and solve for the resistor values: 109 | 110 | (%i3) soln: solve([Zout = 50, Vout = dBtoVr(-6)], [r1, r2]); 111 | (%o3) [[r1 = 37.35187703354015, r2 = 150.4760237537246], [r1 = 0, r2 = 0]] 112 | 113 | The first solution is the one we're interested in. Now, we choose resistors from the E12 (10%) series: 114 | 115 | (%i4) vals: pref(first(soln), E12); 116 | (%o4) [r1 = 39.0, r2 = 150.0] 117 | 118 | and evaluate the result: 119 | 120 | (%i5) ev([Zout, VrtodB(Vout)], vals); 121 | (%o5) [50.66225165562914, - 6.192603348517975] 122 | 123 | Let's see how much better 1% values are: 124 | 125 | (%i6) vals: pref(first(soln), E96); 126 | (%o6) [r1 = 37.4, r2 = 150.0] 127 | 128 | How does this look? 129 | 130 | (%i7) ev([Zout, VrtodB(Vout)], vals); 131 | (%o7) [49.95553579368609, - 6.009010999434952] 132 | 133 | Close enough. 134 | 135 | -------------------------------------------------------------------------------- /circuits.mac: -------------------------------------------------------------------------------- 1 | ratprint:false$ 2 | numer:true$ 3 | tr_warn_undefined_variable:false$ 4 | 5 | /* E-series preferred values */ 6 | Eseries_decade(x) := 10^(floor(log(x)/log(10)))$ 7 | Eseries_mant(x) := x / Eseries_decade(x)$ 8 | EX(x, E) := Eseries_decade(x) * 9 | block([d: abs(E - Eseries_mant(x))], 10 | E[first(sublist_indices(d, lambda([x1], x1=lmin(d))))])$ 11 | 12 | E3_base_values: [1.0, 2.2, 4.7, 10]$ 13 | E6_base_values: [1.0, 1.5, 2.2, 3.3, 4.7, 6.8, 10]$ 14 | E12_base_values: [1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 15 | 8.2, 10]$ 16 | E24_base_values: [1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 17 | 3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 18 | 8.2, 9.1, 10]$ 19 | E48_base_values: [1.00, 1.05, 1.10, 1.15, 1.21, 1.27, 1.33, 1.40, 1.47, 20 | 1.54, 1.62, 1.69, 1.78, 1.87, 1.96, 2.05, 2.15, 2.26, 21 | 2.37, 2.49, 2.61, 2.74, 2.87, 3.01, 3.16, 3.32, 3.48, 22 | 3.65, 3.83, 4.02, 4.22, 4.42, 4.64, 4.87, 5.11, 5.36, 23 | 5.62, 5.90, 6.19, 6.49, 6.81, 7.15, 7.50, 7.87, 8.25, 24 | 8.66, 9.09, 9.53, 10]$ 25 | E96_base_values: [1.00, 1.02, 1.05, 1.07, 1.10, 1.13, 1.15, 1.18, 1.21, 26 | 1.24, 1.27, 1.30, 1.33, 1.37, 1.40, 1.43, 1.47, 1.50, 27 | 1.54, 1.58, 1.62, 1.65, 1.69, 1.74, 1.78, 1.82, 1.87, 28 | 1.91, 1.96, 2.00, 2.05, 2.10, 2.15, 2.21, 2.26, 2.32, 29 | 2.37, 2.43, 2.49, 2.55, 2.61, 2.67, 2.74, 2.80, 2.87, 30 | 2.94, 3.01, 3.09, 3.16, 3.24, 3.32, 3.40, 3.48, 3.57, 31 | 3.65, 3.74, 3.83, 3.92, 4.02, 4.12, 4.22, 4.32, 4.42, 32 | 4.53, 4.64, 4.75, 4.87, 4.99, 5.11, 5.23, 5.36, 5.49, 33 | 5.62, 5.76, 5.90, 6.04, 6.19, 6.34, 6.49, 6.65, 6.81, 34 | 6.98, 7.15, 7.32, 7.50, 7.68, 7.87, 8.06, 8.25, 8.45, 35 | 8.66, 8.87, 9.09, 9.31, 9.53, 9.76, 10]$ 36 | E192_base_values: [1.00, 1.01, 1.02, 1.04, 1.05, 1.06, 1.07, 1.09, 1.10, 37 | 1.11, 1.13, 1.14, 1.15, 1.17, 1.18, 1.20, 1.21, 1.23, 38 | 1.24, 1.26, 1.27, 1.29, 1.30, 1.32, 1.33, 1.35, 1.37, 39 | 1.38, 1.40, 1.42, 1.43, 1.45, 1.47, 1.49, 1.50, 1.52, 40 | 1.54, 1.56, 1.58, 1.60, 1.62, 1.64, 1.65, 1.67, 1.69, 41 | 1.72, 1.74, 1.76, 1.78, 1.80, 1.82, 1.84, 1.87, 1.89, 42 | 1.91, 1.93, 1.96, 1.98, 2.00, 2.03, 2.05, 2.08, 2.10, 43 | 2.13, 2.15, 2.18, 2.21, 2.23, 2.26, 2.29, 2.32, 2.34, 44 | 2.37, 2.40, 2.43, 2.46, 2.49, 2.52, 2.55, 2.58, 2.61, 45 | 2.64, 2.67, 2.71, 2.74, 2.77, 2.80, 2.84, 2.87, 2.91, 46 | 2.94, 2.98, 3.01, 3.05, 3.09, 3.12, 3.16, 3.20, 3.24, 47 | 3.28, 3.32, 3.36, 3.40, 3.44, 3.48, 3.52, 3.57, 3.61, 48 | 3.65, 3.70, 3.74, 3.79, 3.83, 3.88, 3.92, 3.97, 4.02, 49 | 4.07, 4.12, 4.17, 4.22, 4.27, 4.32, 4.37, 4.42, 4.48, 50 | 4.53, 4.59, 4.64, 4.70, 4.75, 4.81, 4.87, 4.93, 4.99, 51 | 5.05, 5.11, 5.17, 5.23, 5.30, 5.36, 5.42, 5.49, 5.56, 52 | 5.62, 5.69, 5.76, 5.83, 5.90, 5.97, 6.04, 6.12, 6.19, 53 | 6.26, 6.34, 6.42, 6.49, 6.57, 6.65, 6.73, 6.81, 6.90, 54 | 6.98, 7.06, 7.15, 7.23, 7.32, 7.41, 7.50, 7.59, 7.68, 55 | 7.77, 7.87, 7.96, 8.06, 8.16, 8.25, 8.35, 8.45, 8.56, 56 | 8.66, 8.76, 8.87, 8.98, 9.09, 9.20, 9.31, 9.42, 9.53, 57 | 9.65, 9.76, 9.88, 10]$ 58 | 59 | E3(x) := EX(x, E3_base_values)$ 60 | E6(x) := EX(x, E6_base_values)$ 61 | E12(x) := EX(x, E12_base_values)$ 62 | E24(x) := EX(x, E24_base_values)$ 63 | E48(x) := EX(x, E48_base_values)$ 64 | E96(x) := EX(x, E96_base_values)$ 65 | E192(x) := EX(x, E192_base_values)$ 66 | 67 | /* combined series */ 68 | E48_24(x) := EX(x, unique(append(E24_base_values, E48_base_values)))$ 69 | E96_24(x) := EX(x, unique(append(E24_base_values, E96_base_values)))$ 70 | E192_24(x) := EX(x, unique(append(E24_base_values, E192_base_values)))$ 71 | 72 | /* select preferred values from selected series */ 73 | pref(x, E) := 74 | if atom(x) then 75 | if numberp(x) then 76 | apply(E, [x]) 77 | else 78 | x 79 | else 80 | map(lambda([x1], pref(x1, E)), x)$ 81 | 82 | /* parallel resistors and inductors, series capacitors */ 83 | par([x]) := 1/lsum(i, i, map(lambda([x1], 1/x1), x))$ 84 | 85 | /* voltage divider */ 86 | vdiv(r_top, r_bot) := r_bot/(r_top+r_bot)$ 87 | 88 | /* dB to voltage ratio */ 89 | dBtoVr(dB) := 10^(dB/20); 90 | 91 | /* voltage ratio to dB */ 92 | VrtodB(Vr) := 20*log(Vr)/log(10); 93 | -------------------------------------------------------------------------------- /images/pi_attenuator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedyapo/maxima-circuits/fc4d26e6b7132b836afc19d3e31dfae190ae52ce/images/pi_attenuator.png --------------------------------------------------------------------------------