Analog and Digital Electronics Design

From Analysis to Synthesis

EE Design Tool

In this post, we'll present and analyze the code to create a design tool that will help us find values for use in implementing equivalent resistance, voltage dividers, and other types of simple resistor circuits. Due to the nature of the problems we're trying to solve, we'll implement a complete search of all possible combinations. For each trial, the error will be calculated and the trial with the minimum error will be presented as the solution. For some problems, there may be more than one solution; so extra constraints will be added to help choose the best solution.

Let's present a Python script that finds the best pair or standard resistors to use for a desired series equivalent resistance, parallel equivalent resistance, and ratio that can be used to implement a voltage divider.

                    

# Need a few math functions
import math

# Standard E24 mantissas, copied and pasted from Wikipedia
R24Standards = [1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 
                3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1]

# Expand to a set of resistances from 10 ohms to 9.1 megaohms 
# using a list comprehension
# round and truncate the result to eliminated fractions caused by **
R24Values = [int(y*10**x + 0.5) for x in range(1,7) for y in R24Standards] 

# A few functions to help get things done

# Percent Error - minimum error is desired
def percentError(Target, Estimate):
    return 100.0 * (Target - Estimate) / Target

# Brute-Force Search
# use every value with every value
# Target: desired equivalent resistance or ratio
# SourceList: list of standard resistors
# designfunction: function to satisfied, 
#   e.g., series combination, parallel combination, ratio
# LowLimit: ignore list values less than this
# HighLimit: ignore list values greater than this
def bfSearch(Target, SourceList1, SourceList2, designFunction, LowLimit=1.0, HighLimit=10E7):
    Error = 1E7;
    for a in SourceList1:
        if not(LowLimit <= a <= HighLimit): continue
        for b in SourceList2:
            if not(LowLimit <= b <= HighLimit): continue
            else:
                NewValue = designFunction(a, b)
                NewError = percentError(Target, NewValue)
                if math.fabs(NewError) <= math.fabs(Error): 
                    Error = NewError
                    Best = (a, b)
    return (Best, Error)

# some design functions
series = lambda x, y: x + y
parallel = lambda x, y: x * y / (x + y)
ratio = lambda x, y: x/y

# displaying resistor values in engineering notation
def resistorEngineering(resistor):
    exponent = math.log10(resistor)
    if exponent < 3.0: # less than 1000
        return str(resistor) + ' \u03A9'
    elif exponent < 6.0: # kilo
        return str(resistor / 1E3) + ' k\u03A9'
    elif exponent < 9.0: # mega
        return str(resistor / 1E6) + ' M\u03A9'
    else: # giga
        return str(resistor / 1E9) + ' G\u03A9'

# Examples

# Series Equivalent
DesiredResistance = 25000; # 25 kΩ
Result = bfSearch(DesiredResistance, R24Values, R24Values, series)
print('Series equivalent of ', resistorEngineering(DesiredResistance))
print ('R1 = ', resistorEngineering(Result[0][0]), ', R2 = ', 
        resistorEngineering(Result[0][1]), ', Error = ', Result[1], '%')

# Parallel Equivalent
DesiredResistance = 1430; # 1.43 kΩ
Result = bfSearch(DesiredResistance, R24Values, R24Values, parallel)
print('Parallel equivalent of ', resistorEngineering(DesiredResistance))
print ('R1 = ', resistorEngineering(Result[0][0]), ', R2 = ', 
        resistorEngineering(Result[0][1]), ', Error = ', Result[1], '%')

# Voltage Divider
Vs = 12 # input voltage = 12 V
V2 = 5 # output voltage = 5 V
Ratio = Vs/V2 - 1 # ratio of R1 to R2
Result = bfSearch(Ratio, R24Values, R24Values, ratio, LowLimit=1000, HighLimit=100E3)
print('Voltage divider resistances for ', Vs, 'V in and ',V2, 'V out.')
print ('R1 = ', resistorEngineering(Result[0][0]), ', R2 = ', 
        resistorEngineering(Result[0][1]), ', Error = ', Result[1], '%')                    
                    
                    

The example code uses E24 (5%) standard resistor values. You can certainly use other lists of standard values such as E96 (1%). The code is also easily altered to handle capacitors and design simple first-order passive filters or even simple op amp gain circuits. For instance, to design a simple first-order passive filter, take the equation for the cut-off frequency: \(f_{c} = \Large{\frac{1}{2\pi RC}}\). Write the appropriate design function:


cutoffFrequency = lamba x, y: 1.0 / (2 * math.pi * x * y)
                        
generate a list of standard capacitors, and fix the limits for capacitance values.

Until the next post,

Dr. Dave

15 Oct 2023