Observed since 20 Oct, 18:06 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
An educational module about linear AC electrical circuits
The aim of this project is to understand the rudiments of linear AC electrical circuits and their functioning.
Python : version 3
All operating systems
Libraries :
From Pypi repository :
https://pypi.org/project/ac-electricity
pip install ac-electricity
Circuit should only contain :
VL
<---------------------
L1
+------+ _ _ _
--->--| R1 |---/ \/ \/ \-----+-------+
IL +------+ | |
| |
^ IR v v IC
| | | ^
| +---+ | C1 |
| | | ----- |
Vin | |R2 | ----- | Vout
| | | | |
| +---+ | |
| | |
| |
-------------------------------+-------+
Datas :
Vin = 5 Vrms
Inductor : L1 = 100 mH ; R1 = 180 Ω
R2 = 2.2 kΩ ; C1 = 330 nF
What are the IL, IR, IC currents ?
What are the VL, Vout voltages ?
What is the frequency response Vout/Vin ?
>>> from acelectricity import *
>>> Vin = Voltage(5) # Vrms
>>> Zr1 = Impedance(r=180)
>>> Zl1 = Impedance(l=0.1)
>>> Zr2 = Impedance(r=2200)
>>> Zc1 = Impedance(c=330e-9)
>>> Zeq1 = 1/(1/Zr2 + 1/Zc1) # impedances in parallel
>>> # or Zeq1 = Zr2//Zc1
>>> Zeq1
Complex impedance (Ω) : 100.88-460.173j @ 1.0 kHz
>>> Zeq = Zr1 + Zl1 + Zeq1 # impedances in series
>>> Zeq(2000) # @ 2000 Hz
(206.11818300356995+1018.3560443060462j)
>>> IL = Vin/Zeq # Ohm's law
>>> IL.properties(2000)
Frequency (Hz) : 2000
Angular frequency (rad/s) : 12566.4
Complex current : 0.000954663-0.00471665j
Amplitude (Arms) : 0.00481229
Amplitude (A) : 0.00680561
Amplitude (dBA ref 1 Arms) : -46.3529621108357
Phase (degrees) : -78.5577
Phase (radians) : -1.37109
i(t) = 0.00680561×sin(12566.4×t -1.371091)
>>> Vout = IL*Zeq1 # Ohm's law
>>> VL = Vin-Vout # Kirchhoff’s voltage law
>>> IC = Vout/Zc1 # Ohm's law
>>> IR = IL-IC # Kirchhoff’s current law
>>> H = Vout/Vin # transfer function
>>> # draw Bode plot and save datas
>>> H.bode(title='Vout/Vin transfer function', filename='h.csv')
>>> IL.bode(magnitude_unit='default', yscale='linear', title='IL current')
>>> Zeq.bode(yscale='log', title='Zeq frequency response')
>>> Zeq.bode_imag(title='Zeq reactance frequency response')
>>> show()

Zoom and data cursors :




>>> Yr2 = 1/Zr2
>>> Yc1 = 1/Zc1
>>> Yc1
Complex admittance (S) : 0+0.00207345j @ 1.0 kHz
>>> 1/Yc1
Complex impedance (Ω) : 0-482.288j @ 1.0 kHz
>>> 1/(Yr2+Yc1)
Complex impedance (Ω) : 100.88-460.173j @ 1.0 kHz
>>> Zr2*(Zc1/(Zr2+Zc1))
Complex impedance (Ω) : 100.88-460.173j @ 1.0 kHz
>>> law = Law()
>>> # voltage divider
>>> Vout = law.VoltageDivider(vtotal=Vin, z=Zr2//Zc1, z2=Zr1+Zl1)
>>> Vout
Complex voltage (Vrms) : -2.28808-6.8219j @ 1.0 kHz
>>> Vin*(Zeq1/Zeq)
Complex voltage (Vrms) : -2.28808-6.8219j @ 1.0 kHz
>>> # Millman's theorem
>>> gnd = Voltage(0)
>>> Vout = law.Millman(v_z=[(Vin, Zr1+Zl1), (gnd, Zr2), (gnd, Zc1)])
>>> Vout
Complex voltage (Vrms) : -2.28808-6.8219j @ 1.0 kHz
>>> (Vin/(Zr1+Zl1))/(1/(Zr1+Zl1) +1/Zr2 +1/Zc1)
Complex voltage (Vrms) : -2.28808-6.8219j @ 1.0 kHz
>>> Vout/Vin
Ratio : -0.457615-1.36438j @ 1.0 kHz
>>> # current divider
>>> IC = law.CurrentDivider(itotal=IL, z=Zc1, z2=Zr2)
>>> IC
Complex current (Arms) : 0.0141449-0.00474421j @ 1.0 kHz
>>> IL*Zr2/(Zr2 +Zc1)
Complex current (Arms) : 0.0141449-0.00474421j @ 1.0 kHz
>>> S = IL*Vin # input source complex power
>>> S.properties(1000)
Frequency (Hz) : 1000
Angular frequency (rad/s) : 6283.19
Complex power : 0.0655242+0.0392254j
Active power P (W) : +0.0655242
Reactive power Q (var) : +0.0392254
Apparent power S (VA) : 0.0763678
Phase (degrees) : +30.9064
Phase (radians) : +0.539419
Power factor PF : 0.8580073402000852
Active power (dBW ref 1 W) : -11.835985322667693
>>> Sr1 = law.Joule(z=Zr1, i=IL)
>>> Sr1
Complex power (W): 0.0419907+0j @ 1.0 kHz
>>> Zr1*IL*IL
Complex power (W): 0.0419907+0j @ 1.0 kHz
>>> Sr2 = law.Joule(z=Zr2, v=Vout)
>>> Sr2
Complex power (W): 0.0235334 @ 1.0 kHz
>>> Sl1 = Zl1*IL*IL
Complex power (W): 0+0.146575j @ 1.0 kHz
>>> Sc1 = Zc1*IC*IC
Complex power (W): 0-0.10735j @ 1.0 kHz
>>> Sr1 +Sr2 +Sc1 +Sl1
Complex power (W): 0.0655242+0.0392254j @ 1.0 kHz
>>> Vin.RMS = 10
>>> Vin.phase = 45
>>> Zr1.r = 100
>>> Zl1.l = 0.22
>>> Zr2.r = 1000
>>> Zc1.c = 100e-9
>>> H.bode(title='Vout/Vin transfer function', filename='h2.csv')
>>> IL.bode(magnitude_unit='default', yscale='linear', title='IL current')
>>> show()


>>> for Zr2.r in [10, 100, 1e3, 1e4]:
H.bode(title="Vout/Vin with R2={} Ω".format(Zr2.r))
>>> show()
>>> fig, ax1, ax2, mag, ph = H.bode(title='Vout/Vin transfer function')
>>> fig.subplots_adjust(left=0.15, bottom=0.35, right=0.85, top=0.9)
>>> ax_r1 = plt.axes([0.15, 0.20, 0.4, 0.03])
>>> ax_l1 = plt.axes([0.15, 0.15, 0.4, 0.03])
>>> ax_r2 = plt.axes([0.15, 0.10, 0.4, 0.03])
>>> ax_c1 = plt.axes([0.15, 0.05, 0.4, 0.03])
>>> slider_r1 = Slider(ax_r1, 'r1 (Ω)', 10, 300,
valinit=Zr1.r, valstep=1)
>>> slider_l1 = Slider(ax_l1, 'l1 (H)', 0.01, 1,
valinit=Zl1.l, valstep=0.01)
>>> slider_r2 = Slider(ax_r2, 'r2 (Ω)', 1e3, 1e4,
valinit=Zr2.r, valstep=10)
>>> slider_c1 = Slider(ax_c1, 'c1 (nF)', 100, 1000,
valinit=Zc1.c*1e9, valstep=1)
>>> def update(val):
Zr1.r = slider_r1.val
Zl1.l = slider_l1.val
Zr2.r = slider_r2.val
Zc1.c = slider_c1.val*1e-9
xvalues = mag.get_xdata()
# H.db() method, according to H.bode() parameters :
# magnitude_unit='db' (default)
# help(H) for more information
magnitudes = [H.db(x) for x in xvalues]
# H.phase_deg() method, according to H.bode() parameters :
# phase_unit='degrees' (default)
phases = [H.phase_deg(x) for x in xvalues]
mag.set_ydata(magnitudes)
ph.set_ydata(phases)
>>> slider_r1.on_changed(update)
>>> slider_l1.on_changed(update)
>>> slider_r2.on_changed(update)
>>> slider_c1.on_changed(update)
>>> ax_button = plt.axes([0.7, 0.10, 0.15, 0.06])
>>> button = Button(ax_button, 'Autoscale')
>>> def autoscale(event):
ax1.relim()
ax1.autoscale_view()
ax2.relim()
ax2.autoscale_view()
>>> button.on_clicked(autoscale)
>>> show()

>>> from acelectricity import *
>>> # static gain, damping value, normal angular frequency
>>> a, z, wn = 10, 0.1, 1000*2*math.pi
>>> H = Ratio(fw=lambda w: a*(2*z*1j*w/wn)/(1+2*z*1j*w/wn-(w/wn)**2))
>>> H.bode(filename='H.csv')
>>> a, z, wn = 100, 0.5, 10000
>>> H.bode(filename='H2.csv')
>>> show()
or :
>>> a, z, wn = 10, 0.1, 1000*2*math.pi
>>> H = Ratio.transfer_function(numerator=[0, a*(2*z*1j/wn)],
denominator=[1, 2*z*1j/wn, -1/wn**2])
>>> H.bode(filename='H3.csv')
>>> a, z, wn = 100, 0.5, 10000
>>> # new instance
>>> H = Ratio.transfer_function(numerator=[0, a*(2*z*1j/wn)],
denominator=[1, 2*z*1j/wn, -1/wn**2])
>>> H.bode(filename='H4.csv')
>>> show()
>>> from acelectricity import *
>>> # first order low-pass filter
>>> wn = 10000
>>> Hlp = Ratio(fw=lambda w: 1/(1+1j*w/wn))
>>> # first order high-pass filter
>>> Hhp = Ratio(fw=lambda w: 1/(1+1j*wn/w))
>>> Hs = Hlp*Hhp # cascaded series filters
>>> Hs.bode()
>>> Hp = Hlp+Hhp # parallel filters
>>> Hp.bode()
>>> show()
+ +------+
-->---(X)---| G(w) |----+--->--
- | +------+ |
| |
| +------+ |
+----| H(w) |-<--+
+------+
>>> from acelectricity import *
>>> # feedforward transfer function
>>> # first order low-pass filter
>>> wn = 10000
>>> G = Ratio.transfer_function([1], [1, 1j/wn])
>>> # feedback transfer function
>>> H = Ratio.transfer_function([10]) # constant
>>> # open-loop transfer function
>>> Hopenloop = G*H
>>> Hopenloop.bode()
>>> # closed-loop transfer function
>>> Hcloseloop = G/(1+Hopenloop)
>>> Hcloseloop.bode()
>>> show()
y(n) = 0.1x(n) +1.6y(n-1) -0.7y(n-2)
>>> from acelectricity import *
>>> fs = 100000 # sampling rate (Hz)
>>> H = Ratio.digital_filter(fs=fs, b=[0.1], a=[1, -1.6, 0.7])
>>> H.bode(xmin=0, xmax=fs/2, xscale='linear',
title='IIR digital filter')
>>> show()

y(n) = (x(n)+x(n-1)+...+x(n-7))/8
>>> from acelectricity import *
>>> fs = 10000 # sampling rate (Hz)
>>> H = Ratio.digital_filter(fs=fs, b=[1/8]*8)
>>> H.bode(xmin=0, xmax=fs/2, xscale='linear',
magnitude_unit='default', title='FIR digital filter')
>>> show()

>>> from acelectricity import *
>>> Yc = Admittance(c=220e-6)
>>> Yc
Complex admittance (S) : 0+1.3823j @ 1.0 kHz
>>> ElectricalQuantity.DEFAULT_FREQUENCY = 50
>>> Yc
Complex admittance (S) : 0+0.069115j @ 50 Hz
>>> 1/Yc
Complex impedance (Ω) : 0-14.4686j @ 50 Hz
>>> from acelectricity import *
>>> def lp(w):
wn = 10000
return 1 if w < wn else 0.001
>>> def hp(w):
wn = 1000
return 10 if w > wn else 0.001
>>> def bp(w):
wn1, wn2 = 1000, 10000
return 1 if wn2 > w > wn1 else 0.001
>>> def notch(w):
wn1, wn2 = 4000, 5000
return 0.001 if wn2 > w > wn1 else 1
>>> def allpass(w):
wn = 10000
return 1j if w > wn else -1j
>>> Hlp = Ratio(fw=lp)
>>> Hhp = Ratio(fw=hp)
>>> Hbp = Ratio(fw=bp)
>>> Hnotch = Ratio(fw=notch)
>>> Hallpass = Ratio(fw=allpass)
>>> Hallpass.bode(title='Ideal all-pass filter')
>>> (Hhp+Hlp).bode(title='Ideal filter Bode plot')
>>> show()


Note : remember that ideal filters are not realizable (not causal).
>>> def lp1(w):
# first order low-pass filter 1/(1+1j*w/wn)
# asymptotic approximation
wn = 1000
return 1 if w < wn else 1/(1j*w/wn)
>>> def lp2(w):
wn = 30000
return 1 if w < wn else 1/(1j*w/wn)
>>> Hlp1 = Ratio(fw=lp1);Hlp2 = Ratio(fw=lp2)
>>> (Hlp1*Hlp2).bode(title='Asymptotic Bode plot')
>>> show()

This module manages basic arithmetic operations + - * / as well as // which designates two impedances in parallel.
The dimensional homogeneity is checked :
>>> V3 = V1 - V2 + I3 # V+A -> Error
TypeError : Voltage expected
>>> I1 = Current(2)
>>> I = I1 + 0.5 # A+number -> Error
TypeError : Current expected
>>> I2 = Current(0.5, phase=30)
>>> I = I1 + I2
>>> I
Complex current (Arms) : 2.43301+0.25j @ 1.0 kHz
>>> I = 5*I2 - V1/Z1 + I3
The result of any operation must give a quantity whose unit is one of : V, A, Ω, S, W (or ratio).
Otherwise, you will get an error :
>>> Z1/V1 # Ω/V -> 1/A -> Error
TypeError
>>> U2*(Z3/(Z2+Z3)) # V*(Ω/Ω) -> V*() -> V
>>> U2*Z3/(Z2+Z3) # V*Ω -> Error
TypeError
>>> S = V1*(V1/Z1) # V*(V/Ω) -> V*A -> W
>>> S = V1*V1/Z1 # V*V -> Error
TypeError
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.4.7 | 26 Oct 2024 | 1 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 18:06 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:c6c1c39385262505b44faaa40b53fb9592c60d7a60b3af3f38b1dcd440d79682