codexpast-exam-of-the-physics-2-paper-of-the-university-of-oxford2019-resit-rc-square-wave-response.py
past-exam-of-the-physics-2-paper-of-the-university-of-oxford/2019-resit-rc-square-wave-response.py
"""Plot exact settled RC responses. Python 3.14, NumPy, Matplotlib."""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams.update({'font.size': 12, 'figure.facecolor': 'white'})
A, tau = 10.0, 0.05
def response(t, frequency):
half_period = 0.5/frequency
local = np.remainder(t, 1/frequency)
peak = A*np.tanh(1/(4*frequency*tau))
return np.where(local < half_period,
A-(A+peak)*np.exp(-local/tau),
-A+(A+peak)*np.exp(-(local-half_period)/tau))
fig, axes = plt.subplots(3, 1, figsize=(10, 8.2), layout='constrained')
cycles = np.linspace(0, 2, 20001)
for ax, frequency, label in zip(axes, (1000, 10, 0.1), ('1 kHz', '10 Hz', '0.1 Hz')):
time = cycles/frequency
output = response(time, frequency)
if frequency != 1000:
input_voltage = np.where(np.remainder(cycles, 1) < 0.5, A, -A)
ax.plot(cycles, input_voltage, color='#888888', linestyle='--', linewidth=1.1, label='input')
ax.plot(cycles, output, color='#1f5f99', linewidth=2.3, label='capacitor')
peak = A*np.tanh(1/(4*frequency*tau))
ax.set_title(f'{label}: settled extrema ±{peak:.4g} V', loc='left')
ax.set_ylabel('Voltage (V)')
ax.set_xlabel('Time / input period')
ax.set_xlim(0, 2)
ax.grid(alpha=0.22)
ax.axhline(0, color='black', linewidth=0.6)
ax.set_ylim((-0.065, 0.065) if frequency == 1000 else (-11.5, 11.5))
if frequency == 10:
ax.legend(loc='upper right', ncols=2, fontsize=10)
if frequency == 0.1:
inset = ax.inset_axes([0.64, 0.28, 0.30, 0.43])
edge_t = np.linspace(0, 0.25, 500)
inset.plot(edge_t, response(edge_t, frequency), color='#1f5f99', linewidth=1.8)
inset.set_title('One rising edge', fontsize=9)
inset.set_xlabel('Time (s)', fontsize=9)
inset.tick_params(labelsize=8)
inset.set_ylim(-11, 11)
inset.grid(alpha=0.2)
fig.suptitle('RC low-pass response: R = 10 kΩ, C = 5 μF, input ±10 V', fontsize=15)
fig.savefig(Path.cwd() / Path(__file__).with_suffix('.png').name, dpi=120, facecolor='white')
plt.close(fig)