LTI System Analysis

In this example the state-space, transfer function, zero-pole-gain, and magnitude response for an LTI system are derived and visualized.

Signal-flow graph

6th-order elliptic low-pass filter

from b_asic.sfg_generators.digital_filters import direct_form_2_iir

b = [
    0.00688044, 0.00271194, 0.01334486, 0.00694836,
    0.01334486,0.00271194, 0.00688044
]
a = [
    1, -3.82875342, 7.15331101, -7.94817034,
    5.49500754, -2.23261844,  0.42049185
]

sfg = direct_form_2_iir(b, a)
sfg
%3 in0 in0 add0 add0 in0:e->add0 0 add0.0 add0->add0.0 out0 out0 add2 add2 add2->out0:w add1 add1 add1->add0 1 t0 t0 add0.0->t0 cmul0 cmul0 add0.0->cmul0 t0.0 t0->t0.0 cmul0->add2 0 add3 add3 add3->add2 1 add4 add4 add4->add3 0 cmul1 cmul1 cmul1->add3 1 t0.0->cmul1 t1 t1 t0.0->t1 cmul12 cmul12 t0.0->cmul12 add5 add5 add5->add4 0 cmul2 cmul2 cmul2->add4 1 t1.0 t1.0->cmul2 t2 t2 t1.0->t2 cmul3 cmul3 t1.0->cmul3 t1->t1.0 t2.0 t2->t2.0 add6 add6 cmul3->add6 1 add6->add1 0 add7 add7 add7->add6 0 add8 add8 add8->add7 0 cmul4 cmul4 cmul4->add7 1 t2.0->cmul4 t3 t3 t2.0->t3 cmul11 cmul11 t2.0->cmul11 add9 add9 add9->add8 0 cmul5 cmul5 cmul5->add8 1 t3.0 t3.0->cmul5 t4 t4 t3.0->t4 cmul6 cmul6 t3.0->cmul6 t3->t3.0 t4.0 t4->t4.0 add10 add10 cmul6->add10 1 add10->add5 0 add11 add11 add11->add10 0 cmul7 cmul7 cmul7->add11 0 cmul8 cmul8 cmul8->add11 1 t4.0->cmul8 t5 t5 t4.0->t5 cmul10 cmul10 t4.0->cmul10 t5.0 t5.0->cmul7 cmul9 cmul9 t5.0->cmul9 t5->t5.0 cmul9->add9 0 cmul10->add9 1 cmul11->add5 1 cmul12->add1 1


State-space representation

ss = sfg.to_ss()
print(ss)
StateSpace (6 states, 1 inputs, 1 outputs)
  A = [[ 3.82875342, -7.15331101,  7.94817034, -5.49500754,  2.23261844,
  -0.42049185],
 [ 1.        ,  0.        ,  0.        ,  0.        ,  0.        ,
   0.        ],
 [ 0.        ,  1.        ,  0.        ,  0.        ,  0.        ,
   0.        ],
 [ 0.        ,  0.        ,  1.        ,  0.        ,  0.        ,
   0.        ],
 [ 0.        ,  0.        ,  0.        ,  1.        ,  0.        ,
   0.        ],
 [ 0.        ,  0.        ,  0.        ,  0.        ,  1.        ,
   0.        ]],
  B = [[1.],
 [0.],
 [0.],
 [0.],
 [0.],
 [0.]],
  C = [[ 0.02905545, -0.03587307,  0.06163527, -0.02446321,  0.01807334,
   0.00398727]],
  D = [[0.00688044]]

Transfer function

tf = sfg.to_tf()
print(tf)
TransferFunction (1 inputs, 1 outputs)
  Denominator: [ 1.         -3.82875342  7.15331101 -7.94817034  5.49500754 -2.23261844
  0.42049185]
  in0 Numerator: [0.00688044 0.00271194 0.01334486 0.00694836 0.01334486 0.00271194
 0.00688044]

Zero-pole-gain

zpk = sfg.to_zpk()
zeros, poles, gain = zpk["in0"]
print("Zeros:", zeros)
print("Poles:", poles)
print("Gain:", gain)
Zeros: [-0.66130483+0.75011727j -0.66130483-0.75011727j  0.34164245+0.93983j
  0.34164245-0.93983j     0.12258632+0.99245786j  0.12258632-0.99245786j]
Poles: [0.57014161+0.78145237j 0.57014161-0.78145237j 0.62440867+0.61818949j
 0.62440867-0.61818949j 0.71982644+0.25279698j 0.71982644-0.25279698j]
Gain: 0.006880439999999988

Pole-zero plot

import numpy as np
import matplotlib.pyplot as plt

theta = np.linspace(0, 2 * np.pi, 1024)

fig, ax = plt.subplots()
ax.plot(np.cos(theta), np.sin(theta), "k--")
ax.scatter(zeros.real, zeros.imag, marker="o")
ax.scatter(poles.real, poles.imag, marker="x")
ax.axhline(0, color="black")
ax.axvline(0, color="black")
ax.set_aspect("equal")
ax.set_xlabel("Real")
ax.set_ylabel("Imaginary")
plt.tight_layout()
plt.show()
lti system analysis

Magnitude response

from b_asic.signal_generator import Impulse
from b_asic.simulation import Simulation

sim = Simulation(sfg, [Impulse()])
sim.run_for(1024)

h = np.array(sim.results["out0"])

H = np.fft.rfft(h)
freqs = np.fft.rfftfreq(len(h))

fig, ax = plt.subplots()
ax.plot(freqs, 20 * np.log10(np.abs(H)))
ax.set_xlabel("Normalized frequency")
ax.set_ylabel("Magnitude, dB")
ax.grid(True)
plt.tight_layout()
plt.show()
lti system analysis

Total running time of the script: (0 minutes 0.384 seconds)

Gallery generated by Sphinx-Gallery