Op-amp filter

For the op-amp filter shown in the figure, find $R_2$ and $C$ so as to get a cut-off frequency of $200\,$Hz and high-frequency gain of $14\,$dB.

In [1]:
from IPython.display import Image
Image(filename =r'EC_filter_1_fig_1.png', width=280)
Out[1]:
No description has been provided for this image
In [2]:
# run this cell to view the circuit file.
%pycat EC_filter_1_orig.in

We now replace strings such as \$R2 with the values of our choice by running the python script given below. It takes an existing circuit file EC_filter_1_orig.in and produces a new circuit file EC_filter_1.in, after replacing \$R2, etc. with the values of our choice.

In [3]:
import gseim_calc as calc
s_R1 = '1k'
s_R2 = '8k' # to be changed by user
s_C = '1.8e-6' # to be changed by user
s_NPD = '100'

f_start = 10.0
f_stop = 1.0e4

s_FSTART = ("%11.4E"%(f_start)).strip()
s_FSTOP  = ("%11.4E"%(f_stop)).strip()

l = [
  ('$R1', s_R1),
  ('$R2', s_R2),
  ('$C', s_C),
  ('$NPD', s_NPD),
  ('$FSTART', s_FSTART),
  ('$FSTOP', s_FSTOP),
]
calc.replace_strings_1("EC_filter_1_orig.in", "EC_filter_1.in", l)
print('EC_filter_1.in is ready for execution')
EC_filter_1.in is ready for execution
Execute the following cell to run NGSPICE on EC_filter_1.in.
In [4]:
import ngspice_calc as ngcalc
ngcalc.run_ngspice('EC_filter_1.in')
Circuit: op-amp filter frequency response

Doing analysis at TEMP = 27.000000 and TNOM = 27.000000

No. of Data Columns : 3  

No. of Data Rows : 301

Total analysis time (seconds) = 0.001

Total elapsed time (seconds) = 0.002 

Total DRAM available = 7739.719 MB.
DRAM currently available = 2538.383 MB.
Total ngspice program size =   19.594 MB.
Resident set size =    9.469 MB.
Shared ngspice pages =    7.824 MB.
Text (code) pages =    5.789 MB.
Stack = 0 bytes.
Library pages =    1.844 MB.


Out[4]:
'EC_filter_1.raw'
In [5]:
# get output file information from the circuit file
s = ngcalc.slv('EC_filter_1.in')

for i in range(s.num_plots()):
    print(f"  plot {i}: {s.plotname(i)} | type: {s.analysis_type(i)} | vars: {s.variables(i)}")
  plot 0: AC Analysis | type: tran | vars: ['frequency', 'v(a)', 'v(d)']
In [6]:
freq  = s.get_array('frequency')
v_in  = s.get_array('v(a)')
v_out = s.get_array('v(d)')

H = v_out/v_in

gain_db = ngcalc.to_db(H)
phase1  = ngcalc.to_degree(H)
phase = [x if x < 0 else (x-360.0) for x in phase1]

print(f'Frequency points : {len(freq)}')
print(f'Freq range       : {freq[0]:.2f} Hz  to  {freq[-1]:.2e} Hz')

flag_flat = False

print(f'gain_db[-1]: {gain_db[-1]:.2f} dB')
print(f'gain_db[-2]: {gain_db[-2]:.2f} dB')

if abs(gain_db[-1]-gain_db[-2]) < 0.02:
    flag_flat = True
    gain_3db = gain_db[-1] - 3.0
    print(f'gain_max: {gain_db[-1]:.2f} dB')
    f_c = ngcalc.interp_at(gain_db, freq, gain_3db)
    print(f'f_c: {f_c:.2e}')
    print(f'gain_3db: {gain_3db:.2f}')
else:
    print('fc is outside the simulation frequency range')
Frequency points : 301
Freq range       : 10.00 Hz  to  1.00e+04 Hz
gain_db[-1]: 18.06 dB
gain_db[-2]: 18.06 dB
gain_max: 18.06 dB
f_c: 8.86e+01
gain_3db: 15.06
In [7]:
import matplotlib.pyplot as plt

color1 = 'blue'
color2 = 'green'
color3 = 'red'

fig, ax = plt.subplots(2, sharex=True, figsize=(6, 5))
plt.subplots_adjust(hspace=0.08)
plt.xlim(f_start, f_stop)

# ── Gain plot ────────────────────────────────────────────────
ax[0].semilogx(freq, gain_db, color=color1, linewidth=1.0, label='gain')
if flag_flat:
    ax[0].axvline(x=f_c, color=color2, linestyle='--', linewidth=0.8, dashes=(5,5), label='fc')
    ax[0].axhline(y=gain_3db,  color=color3, linestyle='--',  linewidth=0.8, dashes=(5,5), label='3 dB')
    ax[0].legend(fontsize=9)
ax[0].set_ylabel('Gain (dB)', fontsize=11)
ax[0].grid(color='#CCCCCC', linestyle='solid', linewidth=0.5, which='both')
ax[0].tick_params(labelbottom=False)

# ── Phase plot ───────────────────────────────────────────────
ax[1].semilogx(freq, phase,        color=color1, linewidth=1.0, label='NGSPICE')
ax[1].set_ylabel('Phase (deg)', fontsize=11)
ax[1].set_xlabel('Frequency (Hz)', fontsize=11)
ax[1].grid(color='#CCCCCC', linestyle='solid', linewidth=0.5, which='both')

fig.suptitle('Filter Frequency Response', fontsize=12)
plt.tight_layout()
plt.show()
No description has been provided for this image

This notebook was contributed by Prof. M. B. Patil, IIT Bombay. He may be contacted at mbpatil@ee.iitb.ac.in.

In [ ]: