[Circuit x Python] How to solve circuit equations symbolically using sympy

Introduction

I am an analog circuit designer. Recently, I started studying Python as a hobby.

Numerical analysis circuit simulators using SPICE are often used in analog circuit design work. However, the numerical analysis simulator alone does not deepen the understanding of the circuit being designed. Sometimes it is necessary to simplify the circuit you are designing, formulate a circuit equation, and solve it. Solving circuit equations is a laborious task. It's okay to solve it for the time being, but I got results for the time, such as there was a calculation error and I could not get a useful result, the formula I got was complicated and I could not get insight and I did not have to solve it. It can be said that it is difficult to get rid of. So, this time, I made it possible to solve the circuit equation using Sympy. When creating the program, I was conscious of reducing the number of human input parts as much as possible.

For people like this

・ Circuit designers tired of solving circuit design ・ I have played with python and Jupyter-notebook ・ I have touched sympy a little

The assumed situation is as follows "I've done it until I draw a circuit diagram in my notebook and formulate the equations. There are so many equations that it will take time to solve them. I don't know if I can get meaningful results even if I solve them ... Alright, let sympy do it! "

environment

Python: 3.7.4、SymPy: 1.6.2

Circuit to analyze

As a simple example, let's calculate the transfer function of the circuit shown below. Circuit component constants are symbols rather than numbers. image.png

First, let's formulate the circuit equation by ourselves as shown in the figure below. When it comes to letting sympy solve circuit equations, you don't have to devise ways to reduce the number of equations, which saves your head energy. image.png

After confirming that the unknowns (here ZP, ZM, IT, VOUT) and the number of equations match, the circuit equation creation is complete.

From here on, let's run it on Jupyter-notebook.

All chords

Suddenly, the whole code is below.

All chords


#Enter the circuit equation
ce = """  
ZP = RP / (1 + s*CP*RP)
ZM = RM / (1 + s*CM*RM)
VIN = (s*LP + ZP + ZM)*IT
VOUT = ZM * IT
"""

#Enter an unknown
uk = "ZP, ZM, IT, VOUT"

#Enter the variable you want to find
wn = "VOUT"


#----------------------------------------------------
#Below, there is no place for the user to enter

#Initial setting
from sympy import *
from IPython.display import Math
from collections import Counter

#Extract the symbol from the circuit equation and declare it as Symbol
rep_char = ["+", "-", "*", "/", "s", "=", "\n", "(", ")"]
ce_rep = ce
for i in range(len(rep_char)):
    ce_rep = ce_rep.replace(rep_char[i], " ")
ce_sym = ce_rep.split()
ce_sym = list(Counter(ce_sym).keys())

for i in reversed(range(len(ce_sym))): #Clear the numbers in the list
     if ce_sym[i].isdecimal():
            del ce_sym[i]

s = Symbol("s", real=True)
for i in range(len(ce_sym)):
    exec(ce_sym[i] + " = Symbol(\"" + ce_sym[i] + "\", real=True)")


#Generate an array for TeX display
ce_tex = []
for i in range(len(ce_sym)):
    if len(ce_sym[i]) == 1:
        ce_tex.append(ce_sym[i][0])
    else:
        ce_tex.append(ce_sym[i][0] + "_{" + ce_sym[i][1:] + "}")


#Generate circuit equations and unknown symbol lists
start = 3
ind_eq = -1
ind_rt = 2

ce_sol = []

while True:
    ind_eq = ce.find("=", ind_eq+1)
    ind_rt = ce.find("\n", ind_rt+1)

    if ind_rt == -1:
        break

    exec("ce_sol.append(" + ce[start:ind_eq] + "-(" + ce[ind_eq+1: ind_rt] + "))")

    start=ind_rt + 1

exec("uk_sol = " + uk)
exec("wn_sol = " + wn)


#Solve and organize equations
if len(uk_sol) != len(ce_sol):
    print("Align the number of unknowns with the number of equations.")

else:
    sol = solve(ce_sol, uk_sol, dict=True)[0][wn_sol]

    #Organize the denominator numerator
    nu = collect(expand(numer(sol)), s)  #Numerator, molecule
    de = collect(expand(denom(sol)), s)  #denominator, denominator
    sol = nu / de

    #Displaying expressions
    sol_tex = latex(sol)
    for i in range(len(ce_sym)):
        sol_tex = sol_tex.replace(latex(ce_sym[i]), ce_tex[i])

    display(Math(sol_tex))

If you do this, you will get the following results:

\displaystyle \frac{C_{P} R_{M} R_{P} V_{IN} s + R_{M} V_{IN}}{C_{M} C_{P} L_{P} R_{M} R_{P} s^{3} + R_{M} + R_{P} + s^{2} \left(C_{M} L_{P} R_{M} + C_{P} L_{P} R_{P}\right) + s \left(C_{M} R_{M} R_{P} + C_{P} R_{M} R_{P} + L_{P}\right)}

Let's explain the flow of the program and its details.

STEP1: Enter the circuit equation and unknown

#Enter the circuit equation
ce = """  
ZP = RP / (1 + s*CP*RP)
ZM = RM / (1 + s*CM*RM)
VIN = (s*LP + ZP + ZM)*IT
VOUT = ZM * IT
"""

#Enter an unknown
uk = "ZP, ZM, IT, VOUT"

#Enter the variable you want to find
wn = "VOUT"

Enter the circuit equation, the unknown, and the variable you want to find. When entering circuit equations, start with a capital letter for parameters other than s. This is because it is inconvenient to use lowercase letters in the processing when displaying the calculation result in TeX.

STEP2: Import the module

python


from sympy import *
from IPython.display import Math
from collections import Counter

Import the module. No special commentary is needed.

STEP3: Extract the symbol from the circuit equation and declare it as Symbol

python


rep_char = ["+", "-", "*", "/", "s", "=", "\n", "(", ")"]
ce_rep = ce
for i in range(len(rep_char)):
    ce_rep = ce_rep.replace(rep_char[i], " ")
ce_sym = ce_rep.split()
ce_sym = list(Counter(ce_sym).keys())

for i in reversed(range(len(ce_sym))): #Clear the numbers in the list
     if ce_sym[i].isdecimal():
            del ce_sym[i]

Here, the following processing is performed __ (i) The circuit equation ce is input in STEP1 __ ZP = RP / (1 + sCPRP) ZM = RM / (1 + sCM+RM) VIN = (sLP + ZP + ZM)*IT VOUT = ZM * IT

__ (ii) Replace operators (+-* /), s, line feeds (\ n), etc. with spaces from the input circuit equation (ce in STEP1) __ ce_rep: ZP RP 1 CP RP ZM RM 1 CM RM VIN LP ZP ZM IT VOUT ZM IT

__ (iii) Extract the symbols that appear in the equation __ ce_sym: ['ZP', 'RP', '1', 'CP', 'ZM', 'RM', 'CM', 'VIN', 'LP', 'IT', 'VOUT']

__ (iii) Find the number from the list obtained above and delete it (in this case 1 is deleted) __ ce_sym: ['ZP', 'RP', 'CP', 'ZM', 'RM', 'CM', 'VIN', 'LP', 'IT', 'VOUT']

Now that we have a list of the symbols used in the circuit equations in the above process Declare it as a Sympy Symbol.

python


s = Symbol("s", real=True)
for i in range(len(ce_sym)):
    exec(ce_sym[i] + " = Symbol(\"" + ce_sym[i] + "\", real=True)")

Code running in __exec: __ ZP = Symbol("ZP", real=True) RP = Symbol("RP", real=True) CP = Symbol("CP", real=True) ZM = Symbol("ZM", real=True) RM = Symbol("RM", real=True) CM = Symbol("CM", real=True) VIN = Symbol("VIN", real=True) LP = Symbol("LP", real=True) IT = Symbol("IT", real=True) VOUT = Symbol("VOUT", real=True)

STEP4: Generate an array for TeX display

python


ce_tex = []
for i in range(len(ce_sym)):
    if len(ce_sym[i]) == 1:
        ce_tex.append(ce_sym[i][0])
    else:
        ce_tex.append(ce_sym[i][0] + "_{" + ce_sym[i][1:] + "}")

I want to display the output result in TeX, so I will create a list for this. Based on the list of ce_sym, the list ce_tex to be subscripted after the second character is generated [^ 1]. Example: VOUT → V_ {OUT}, $ V_ {OUT} $

ce_tex: ['Z_{P}', 'R_{P}', 'C_{P}', 'Z_{M}', 'R_{M}', 'C_{M}', 'V_{IN}', 'L_{P}', 'I_{T}', 'V_{OUT}']

__ (Reference) ce_sym: __ obtained in STEP3 ['ZP', 'RP', 'CP', 'ZM', 'RM', 'CM', 'VIN', 'LP', 'IT', 'VOUT']

[^ 1]: Note that if you use the symbol BW1, the Tex display will not be $ BW_1 $, but $ B_ {W1} $.

STEP5: Generate circuit equation and unknown symbol list

python


start = 3
ind_eq = -1
ind_rt = 2

ce_sol = []

while True:
    ind_eq = ce.find("=", ind_eq+1)
    ind_rt = ce.find("\n", ind_rt+1)

    if ind_rt == -1:
        break

    exec("ce_sol.append(" + ce[start:ind_eq] + "-(" + ce[ind_eq+1: ind_rt] + "))")

    start=ind_rt + 1

exec("uk_sol = " + uk)
exec("wn_sol = " + wn)

The equation and the unknown symbol list are generated by the following processing.

__ (i) The circuit equation ce is input in STEP1 __ ce: ZP = RP / (1 + sCPRP) ZM = RM / (1 + sCMRM) VIN = (s*LP + ZP + ZM)*IT VOUT = ZM * IT

__ (ii) Find the equal'=' and the line feed'\ n'from ce, and create a list with the right side moved to the left side __ ce_sol: -RP/(CPRPs + 1) + ZP, -RM/(CMRMs + 1) + ZM, -IT*(LPs + ZM + ZP) + VIN, -ITZM + VOUT

__ (iii) Execute the following code for the unknown (uk) and the variable (wn) you want to find __ uk_sol = ZP, ZM, IT, VOUT wn_sol = VOUT

STEP6: Solve and organize the equations

This is the part that finally solves the equation.

python


if len(uk_sol) != len(ce_sol):
    print("Align the number of unknowns with the number of equations.")

else:
    sol = solve(ce_sol, uk_sol, dict=True)[0][wn_sol]

    #Organize the denominator numerator
    nu = collect(expand(numer(sol)), s)  #Numerator, molecule
    de = collect(expand(denom(sol)), s)  #denominator, denominator
    sol = nu / de

If the number of unknowns and the number of equations are not the same, a solution cannot be obtained, so we check this first.

The equation is solved by the following code.

sol = solve(ce_sol, uk_sol, dict=True)[0][wn_sol]

If you execute solve (ce_sol, uk_sol, dict = True), you will get all the unknown solutions as below. By adding [0] [wn_sol], only the solution (VOUT this time) that you want to find is extracted.

Result of executing ___sol = solve (ce_sol, uk_sol, dict = True): __ ZP: RP/(CPRPs + 1) ZM: RM/(CMRMs + 1) IT: VIN * (CM * RM * s + 1) * (CP ~ omitted ~ VOUT: RM * VIN * (CP * RP * s + 1 ~ omitted ~

After finding the solution, the denominator and numerator are organized for s. The obtained solution is difficult to read as shown below. sol: $\displaystyle \frac{CP RM RP VIN s + RM VIN}{CM CP LP RM RP s^{3} + RM + RP + s^{2} \left(CM LP RM + CP LP RP\right) + s \left(CM RM RP + CP RM RP + LP\right)}$

    #Displaying expressions
    sol_tex = latex(sol)
    for i in range(len(ce_sym)):
        sol_tex = sol_tex.replace(latex(ce_sym[i]), ce_tex[i])
    
    display(Math(sol_tex))

Therefore, in order to make the display of the equation easier to see, it is converted to the TeX display. For example, if it is VOUT, replace it with V_ {OUT}.

The final result is as follows, and the readability has been improved by using TeX display. $\displaystyle \frac{C_{P} R_{M} R_{P} V_{IN} s + R_{M} V_{IN}}{C_{M} C_{P} L_{P} R_{M} R_{P} s^{3} + R_{M} + R_{P} + s^{2} \left(C_{M} L_{P} R_{M} + C_{P} L_{P} R_{P}\right) + s \left(C_{M} R_{M} R_{P} + C_{P} R_{M} R_{P} + L_{P}\right)}$

Variable name

The formula is replaced to display TeX, but it may behave unexpectedly depending on the symbol name. For example, using the symbol ac replaces \ fr ac in TeX code. For this reason, symbols should basically start with a capital letter.

in conclusion

That is all for the explanation. Since the user inputs only the circuit equation, the unknown, and the variable to be obtained, the circuit equation can be solved with the minimum effort required. The effort saved can be used to interpret the results obtained. For example, you could simplify the formula from the magnitude relation of the terms.

Humans set up the circuit equation this time, but I think that even setting up the circuit equation can be troublesome (no time). In this case, you can also automate the formulation of circuit equations by using a python package called Lcapy. All the user has to do is draw a schematic. I wrote a commentary article about this, so if you are interested, please have a look there as well.

[Circuit x Python] How to enable the linear circuit analysis package Lcapy [Circuit x Python] How to find the transfer function of a circuit using Lcapy [Circuit x Python] How to expand and calculate transfer function using Lcapy

Recommended Posts

[Circuit x Python] How to solve circuit equations symbolically using sympy
[Circuit x Python] How to expand and calculate transfer functions using Lcapy
[Python] Solve equations with sympy
[Circuit x Python] How to find the transfer function of a circuit using Lcapy
How to install python using anaconda
How to solve simultaneous linear equations
[Circuit x Python] How to enable the linear circuit analysis package Lcapy
How to erase Python 2.x on Mac.
[Blender x Python] How to use modifiers
Let's solve simultaneous linear equations with Python sympy!
[Algorithm x Python] How to use the list
[Blender x Python] How to make an animation
[Blender x Python] How to make vertex animation
Solve simultaneous equations in an instant using Python
How to install python
How to use SymPy
How to set up a Python environment using pyenv
[Blender x Python] How to create an original object
How to auto-submit Microsoft Forms using python (Mac version)
Solve simultaneous ordinary differential equations with Python and SymPy.
How to make a Python package using VS Code
How to exit when using Python in Terminal (Mac)
How to retrieve multiple arrays using slice in python.
[Introduction to Python] How to stop the loop using break?
How to execute a command using subprocess in Python
[Introduction to Python] How to write repetitive statements using for statements
[2020.8 latest] How to install Python
How to install Python [Windows]
[Introduction to Python] How to write conditional branches using if statements
python3: How to use bottle (2)
[Python] How to use list 1
How to update Python Tkinter to 8.6
How to transpose a 2D array using only python [Note]
Post to Twitter using Python
How to use Python argparse
Start to Selenium using python
Python: How to use pydub
[Python] How to use checkio
How to run Notepad ++ Python
How to change Python version
13th Offline Real-time How to Solve Writing Problems in Python
How to develop in Python
How to update FC2 blog etc. using XMLRPC with python
[python] How to judge scalar
[Python] How to use input ()
How to use Python lambda
[Python] How to use virtualenv
python3: How to use bottle (3)
python3: How to use bottle
Convert python 3.x code to python 2.x
How to use Python bytes
How to display formulas in latex when using sympy (> = 1.4) in Google Colaboratory
How to get followers and followers from python using the Mastodon API
The 17th Offline Real-time How to Solve Writing Problems in Python
How to write offline real time Solve E04 problems in Python
How to build a Python environment using Virtualenv on Ubuntu 18.04 LTS
How to update a Tableau packaged workbook data source using Python
How to write offline real time Solve F01 problems with Python
How to install Theano on Mac OS X 10.10 (using pyenv, anaconda)
How to write a Python class
[Python] How to FFT mp3 data