Calculating impedance of a RLC circuit

Updated TrustyTony 0 Tallied Votes 3K Views Share

circuit Here is a version in Python of program from classic Lisp book (see http://www.daniweb.com/software-development/legacy-languages/code/446235/simple-scheme-functions-for-finding-impedance-for-norvigs-implementation for the details) for calculating impedance of a circuit. (Example circuit with 1MOhm like in the book's code not like in diagram)

from math import pi, degrees
from cmath import phase

def impedance(circuit, omega):
    def r(x):
        return x
    def l(x):
        return complex(0.0, omega * x)
    def c(x):
        return complex(0.0, -1.0 / (omega * x))
    return eval(circuit)

def series(*things):
    return sum(things)

def parallel(*things):
    return 1. / (sum(1. / value for value in things))

if __name__ == '__main__':
    # definition in pairs from LISP implementation
    ##circuit_a = 'series(r(1), parallel(series(r(100.0),l(0.2)), parallel(c(1e-06),r(1000000.0))))'

    # This implementation knows to deal with more than two components in serial/parallel
    circuit_a = 'series(r(1), parallel(series(r(100.0),l(0.2)), c(1e-06),r(1000000.0)))'
    print(circuit_a)

    for omega in 2179.44, 2207.99:
        p = impedance(circuit_a, omega)
        print('omega = %.2f' % omega)
        print(u'rectangular: %.2f + %.2fj' % (p.real, p.imag))
        print(u'polar, angle in degrees: %.2f Ω, φ = %.2f °' % (abs(p), degrees(phase(p))))
        print('-'*60)

Dani AI

Generated

Nice port, . If you want to stress-test the idea across frequency (and avoid edge cases at f=0), here is a small, vectorized helper that keeps the functional style but evaluates over a sweep. It also handles open/short behavior cleanly for ideal L and C.

import numpy as np

def series(*Z):
    Z = np.array(Z, dtype=complex)
    return np.sum(Z, axis=0)

def parallel(*Z):
    Z = np.array(Z, dtype=complex)
    Y = np.where(np.isinf(Z), 0, 1/Z)    # open branch -> no admittance
    Ysum = np.sum(Y, axis=0)
    return np.where(Ysum == 0, np.inf, 1/Ysum)  # no path -> open circuit

def Z_R(R): return R + 0j
def Z_L(L, w): return 1j*w*L
def Z_C(C, w):
    w = np.asarray(w)
    Z = -1j/(w*C)
    Z[w == 0] = np.inf
    return Z

# Example: R in series with parallel L and C (1 Mohm like Norvig's example)
R, L, C = 1e6, 1e-3, 1e-9
f = np.logspace(1, 6, 500)               # 10 Hz .. 1 MHz
w = 2*np.pi*f
Z = series(Z_R(R), parallel(Z_L(L, w), Z_C(C, w)))

f0 = 1/(2*np.pi*np.sqrt(L*C))            # parallel LC antiresonance
print("Resonant f0 ~= %.3f kHz" % (f0/1e3))
print("|Z| at f0 ~= %.3e ohm" % np.abs(Z[np.argmin(np.abs(f - f0))]))

Tips:

  • Use SI units: R in ohm, L in henry, C in farad; w = 2*pi*f is in rad/s.
  • At f=0, Z_C -> inf and Z_L -> 0; at very high f, the roles flip. The guards above prevent divide-by-zero warnings.
  • If you are keeping the recursive circuit description from the Lisp/Scheme version, you can plug those node evaluators into series() and parallel() and get magnitude/phase or Bode plots with NumPy in a few lines.
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.