Path: blob/main/latex-templates/templates/electrical-engineering/rc_circuit.tex
51 views
unlisted
\documentclass[a4paper, 11pt]{article}1\usepackage[utf8]{inputenc}2\usepackage[T1]{fontenc}3\usepackage{amsmath, amssymb, amsthm}4\usepackage{graphicx}5\usepackage{siunitx}6\usepackage{booktabs}7\usepackage{float}8\usepackage{geometry}9\geometry{margin=1in}10\usepackage[makestderr]{pythontex}1112% Theorem environments13\newtheorem{theorem}{Theorem}[section]14\newtheorem{definition}[theorem]{Definition}15\newtheorem{example}[theorem]{Example}1617\title{RC Circuit Analysis: Transient Response, Frequency Domain,\\and Filter Design Laboratory Report}18\author{Electrical Engineering Laboratory}19\date{\today}2021\begin{document}22\maketitle2324\begin{abstract}25This laboratory report presents a comprehensive analysis of RC circuits, covering transient response characteristics, Laplace transform methods, frequency domain analysis, and filter design applications. Through computational analysis with Python, we demonstrate charging and discharging dynamics, time constant determination, Bode plot interpretation, and the design of low-pass, high-pass, and band-pass filter configurations. All numerical results are dynamically computed, ensuring reproducibility.26\end{abstract}2728\section{Introduction}2930RC circuits form the foundation of analog signal processing and filtering. The combination of resistance (R) and capacitance (C) creates a frequency-dependent impedance that enables selective signal attenuation and phase shifting.3132\begin{definition}[Time Constant]33The time constant $\tau$ of an RC circuit is the time required for the voltage to reach approximately 63.2\% of its final value during charging or decay to 36.8\% during discharging:34\begin{equation}35\tau = RC36\end{equation}37\end{definition}3839\section{Laplace Domain Analysis}4041\begin{pycode}42import numpy as np43import matplotlib.pyplot as plt44from scipy import signal45from scipy.integrate import odeint4647plt.rc('text', usetex=True)48plt.rc('font', family='serif', size=9)49np.random.seed(42)5051# Circuit parameters52R = 1000 # Resistance (Ohm)53C = 1e-6 # Capacitance (F)54tau = R * C # Time constant (s)55V0 = 5.0 # Source voltage (V)5657# Derived parameters58f_cutoff = 1 / (2 * np.pi * R * C) # Cutoff frequency (Hz)59omega_cutoff = 2 * np.pi * f_cutoff # Angular cutoff frequency (rad/s)6061# Time vector for transient analysis62t = np.linspace(0, 5*tau, 1000)63\end{pycode}6465The transfer function of an RC low-pass filter in the Laplace domain is:66\begin{equation}67H(s) = \frac{V_{out}(s)}{V_{in}(s)} = \frac{1}{1 + sRC} = \frac{1}{1 + s\tau}68\end{equation}6970\begin{theorem}[Voltage Equations via Laplace Transform]71For a step input of magnitude $V_0$, the capacitor voltage during charging is:72\begin{equation}73v_C(t) = V_0\left(1 - e^{-t/\tau}\right)u(t)74\end{equation}75where $u(t)$ is the unit step function.76\end{theorem}7778\noindent\textbf{Circuit Parameters:}79\begin{itemize}80\item Resistance: $R = \py{R}$ $\Omega$81\item Capacitance: $C = \py{C*1e6:.1f}$ $\mu$F82\item Time Constant: $\tau = \py{f"{tau*1000:.3f}"}$ ms83\item Cutoff Frequency: $f_c = \py{f"{f_cutoff:.1f}"}$ Hz84\end{itemize}8586\section{Transient Response Analysis}8788\subsection{Charging and Discharging Dynamics}8990\begin{pycode}91# Transient responses92v_charge = V0 * (1 - np.exp(-t/tau))93v_discharge = V0 * np.exp(-t/tau)9495# Current during charging96i_charge = (V0/R) * np.exp(-t/tau)97i_discharge = -(V0/R) * np.exp(-t/tau)9899# Power calculations100p_charge = v_charge * i_charge101p_resistor = i_charge**2 * R102103# Energy stored in capacitor104energy_cap = 0.5 * C * v_charge**2105energy_max = 0.5 * C * V0**2106107# Key time points108t_1tau = tau109t_3tau = 3 * tau110t_5tau = 5 * tau111112v_at_1tau = V0 * (1 - np.exp(-1)) # ~63.2%113v_at_3tau = V0 * (1 - np.exp(-3)) # ~95.0%114v_at_5tau = V0 * (1 - np.exp(-5)) # ~99.3%115116fig, axes = plt.subplots(2, 2, figsize=(10, 8))117118# Voltage responses119axes[0, 0].plot(t*1000, v_charge, 'b-', linewidth=1.5, label='Charging')120axes[0, 0].plot(t*1000, v_discharge, 'r--', linewidth=1.5, label='Discharging')121axes[0, 0].axhline(y=V0*0.632, color='gray', linestyle=':', alpha=0.7)122axes[0, 0].axvline(x=tau*1000, color='g', linestyle=':', alpha=0.7, label=r'$\tau$')123axes[0, 0].axvline(x=3*tau*1000, color='orange', linestyle=':', alpha=0.5, label=r'$3\tau$')124axes[0, 0].axvline(x=5*tau*1000, color='purple', linestyle=':', alpha=0.5, label=r'$5\tau$')125axes[0, 0].plot([tau*1000], [v_at_1tau], 'go', markersize=6)126axes[0, 0].set_xlabel('Time (ms)')127axes[0, 0].set_ylabel('Voltage (V)')128axes[0, 0].set_title('Capacitor Voltage')129axes[0, 0].legend(loc='center right', fontsize=7)130axes[0, 0].grid(True, alpha=0.3)131132# Current responses133axes[0, 1].plot(t*1000, i_charge*1000, 'b-', linewidth=1.5, label='Charging')134axes[0, 1].plot(t*1000, i_discharge*1000, 'r--', linewidth=1.5, label='Discharging')135axes[0, 1].axhline(y=0, color='gray', linestyle='-', alpha=0.3)136axes[0, 1].axvline(x=tau*1000, color='g', linestyle=':', alpha=0.7)137axes[0, 1].set_xlabel('Time (ms)')138axes[0, 1].set_ylabel('Current (mA)')139axes[0, 1].set_title('Circuit Current')140axes[0, 1].legend(loc='upper right', fontsize=8)141axes[0, 1].grid(True, alpha=0.3)142143# Power dissipation144axes[1, 0].plot(t*1000, p_resistor*1000, 'r-', linewidth=1.5, label='Resistor')145axes[1, 0].plot(t*1000, p_charge*1000, 'b--', linewidth=1.5, label='Capacitor Input')146axes[1, 0].axvline(x=tau*1000, color='g', linestyle=':', alpha=0.7)147axes[1, 0].set_xlabel('Time (ms)')148axes[1, 0].set_ylabel('Power (mW)')149axes[1, 0].set_title('Power Distribution')150axes[1, 0].legend(loc='upper right', fontsize=8)151axes[1, 0].grid(True, alpha=0.3)152153# Energy storage154axes[1, 1].plot(t*1000, energy_cap*1e6, 'b-', linewidth=1.5)155axes[1, 1].axhline(y=energy_max*1e6, color='r', linestyle='--', alpha=0.7, label='Max Energy')156axes[1, 1].axvline(x=tau*1000, color='g', linestyle=':', alpha=0.7)157axes[1, 1].set_xlabel('Time (ms)')158axes[1, 1].set_ylabel(r'Energy ($\mu$J)')159axes[1, 1].set_title('Capacitor Energy Storage')160axes[1, 1].legend(loc='lower right', fontsize=8)161axes[1, 1].grid(True, alpha=0.3)162163plt.tight_layout()164plt.savefig('rc_circuit_plot1.pdf', bbox_inches='tight', dpi=150)165plt.close()166\end{pycode}167168\begin{figure}[H]169\centering170\includegraphics[width=0.95\textwidth]{rc_circuit_plot1.pdf}171\caption{Transient response characteristics: voltage, current, power, and energy.}172\end{figure}173174\begin{table}[H]175\centering176\caption{Charging Voltage at Key Time Constants}177\begin{tabular}{ccc}178\toprule179\textbf{Time} & \textbf{Voltage (V)} & \textbf{Percentage of $V_0$} \\180\midrule181$\tau$ & \py{f"{v_at_1tau:.3f}"} & 63.2\% \\182$3\tau$ & \py{f"{v_at_3tau:.3f}"} & 95.0\% \\183$5\tau$ & \py{f"{v_at_5tau:.3f}"} & 99.3\% \\184\bottomrule185\end{tabular}186\end{table}187188\subsection{Pulse Response and Duty Cycle Effects}189190\begin{pycode}191# Pulse response with different duty cycles192t_pulse = np.linspace(0, 10*tau, 2000)193dt = t_pulse[1] - t_pulse[0]194195# Generate pulse trains196def generate_pulse_response(t, tau, period_factor, duty_cycle):197period = period_factor * tau198v_out = np.zeros_like(t)199v_cap = 0 # Initial capacitor voltage200201for i in range(len(t)):202t_in_cycle = t[i] % period203if t_in_cycle < period * duty_cycle:204v_in = V0205else:206v_in = 0207208# RC circuit differential equation209dv = (v_in - v_cap) / tau210v_cap = v_cap + dv * dt211v_out[i] = v_cap212213return v_out214215# Different cases216v_slow_50 = generate_pulse_response(t_pulse, tau, 10, 0.5) # Period = 10*tau217v_fast_50 = generate_pulse_response(t_pulse, tau, 2, 0.5) # Period = 2*tau218v_fast_20 = generate_pulse_response(t_pulse, tau, 2, 0.2) # 20% duty cycle219220# Square wave input for comparison221def square_wave(t, period, duty):222return V0 * ((t % period) < (period * duty)).astype(float)223224fig, axes = plt.subplots(2, 2, figsize=(10, 8))225226# Slow pulse (period = 10*tau)227period_slow = 10 * tau228axes[0, 0].plot(t_pulse*1000, square_wave(t_pulse, period_slow, 0.5), 'gray', alpha=0.5, label='Input')229axes[0, 0].plot(t_pulse*1000, v_slow_50, 'b-', linewidth=1.5, label='Output')230axes[0, 0].set_xlabel('Time (ms)')231axes[0, 0].set_ylabel('Voltage (V)')232axes[0, 0].set_title(f'Slow Pulse: Period = 10$\\tau$, 50\\% Duty')233axes[0, 0].legend(loc='upper right', fontsize=8)234axes[0, 0].grid(True, alpha=0.3)235236# Fast pulse (period = 2*tau)237period_fast = 2 * tau238axes[0, 1].plot(t_pulse*1000, square_wave(t_pulse, period_fast, 0.5), 'gray', alpha=0.5, label='Input')239axes[0, 1].plot(t_pulse*1000, v_fast_50, 'r-', linewidth=1.5, label='Output')240axes[0, 1].set_xlabel('Time (ms)')241axes[0, 1].set_ylabel('Voltage (V)')242axes[0, 1].set_title(f'Fast Pulse: Period = 2$\\tau$, 50\\% Duty')243axes[0, 1].legend(loc='upper right', fontsize=8)244axes[0, 1].grid(True, alpha=0.3)245246# Low duty cycle247axes[1, 0].plot(t_pulse*1000, square_wave(t_pulse, period_fast, 0.2), 'gray', alpha=0.5, label='Input')248axes[1, 0].plot(t_pulse*1000, v_fast_20, 'g-', linewidth=1.5, label='Output')249axes[1, 0].set_xlabel('Time (ms)')250axes[1, 0].set_ylabel('Voltage (V)')251axes[1, 0].set_title(f'Low Duty Cycle: 20\\%')252axes[1, 0].legend(loc='upper right', fontsize=8)253axes[1, 0].grid(True, alpha=0.3)254255# DC component extraction (averaging)256dc_values = []257duty_cycles = np.linspace(0.1, 0.9, 9)258for dc in duty_cycles:259v_resp = generate_pulse_response(t_pulse, tau, 2, dc)260dc_values.append(np.mean(v_resp[-500:])) # Steady-state average261262axes[1, 1].plot(duty_cycles*100, dc_values, 'bo-', linewidth=1.5, markersize=6)263axes[1, 1].plot(duty_cycles*100, duty_cycles*V0, 'r--', alpha=0.7, label='Ideal: $D \\cdot V_0$')264axes[1, 1].set_xlabel('Duty Cycle (\\%)')265axes[1, 1].set_ylabel('DC Output (V)')266axes[1, 1].set_title('DC Component vs Duty Cycle')267axes[1, 1].legend(loc='upper left', fontsize=8)268axes[1, 1].grid(True, alpha=0.3)269270plt.tight_layout()271plt.savefig('rc_circuit_plot2.pdf', bbox_inches='tight', dpi=150)272plt.close()273\end{pycode}274275\begin{figure}[H]276\centering277\includegraphics[width=0.95\textwidth]{rc_circuit_plot2.pdf}278\caption{Pulse response showing the effect of pulse period and duty cycle on output waveform.}279\end{figure}280281\section{Frequency Response Analysis}282283\subsection{Bode Plot Characterization}284285\begin{pycode}286# Frequency response analysis287f = np.logspace(1, 7, 1000) # 10 Hz to 10 MHz288omega = 2 * np.pi * f289290# Transfer function magnitude and phase291H = 1 / (1 + 1j * omega * R * C)292H_mag = np.abs(H)293H_phase = np.angle(H, deg=True)294H_mag_dB = 20 * np.log10(H_mag)295296# Key points297idx_fc = np.argmin(np.abs(f - f_cutoff))298mag_at_fc = H_mag_dB[idx_fc]299phase_at_fc = H_phase[idx_fc]300301# Roll-off calculation302f_decade_above = 10 * f_cutoff303idx_decade = np.argmin(np.abs(f - f_decade_above))304rolloff = H_mag_dB[idx_fc] - H_mag_dB[idx_decade]305306# Phase delay307phase_delay = -H_phase / (360 * f) # in seconds308group_delay = -np.gradient(np.unwrap(np.angle(H))) / np.gradient(omega)309310fig, axes = plt.subplots(2, 2, figsize=(10, 8))311312# Magnitude response313axes[0, 0].semilogx(f, H_mag_dB, 'b-', linewidth=1.5)314axes[0, 0].axhline(y=-3, color='r', linestyle='--', alpha=0.7, label='-3 dB')315axes[0, 0].axhline(y=-20, color='gray', linestyle=':', alpha=0.5)316axes[0, 0].axvline(x=f_cutoff, color='g', linestyle='--', alpha=0.7, label='$f_c$')317axes[0, 0].plot(f_cutoff, mag_at_fc, 'go', markersize=6)318axes[0, 0].set_xlabel('Frequency (Hz)')319axes[0, 0].set_ylabel('Magnitude (dB)')320axes[0, 0].set_title('Bode Plot - Magnitude')321axes[0, 0].legend(loc='lower left', fontsize=8)322axes[0, 0].grid(True, which='both', alpha=0.3)323axes[0, 0].set_ylim([-60, 5])324325# Phase response326axes[0, 1].semilogx(f, H_phase, 'b-', linewidth=1.5)327axes[0, 1].axhline(y=-45, color='r', linestyle='--', alpha=0.7, label='-45°')328axes[0, 1].axhline(y=-90, color='gray', linestyle=':', alpha=0.5)329axes[0, 1].axvline(x=f_cutoff, color='g', linestyle='--', alpha=0.7)330axes[0, 1].plot(f_cutoff, phase_at_fc, 'go', markersize=6)331axes[0, 1].set_xlabel('Frequency (Hz)')332axes[0, 1].set_ylabel('Phase (degrees)')333axes[0, 1].set_title('Bode Plot - Phase')334axes[0, 1].legend(loc='upper right', fontsize=8)335axes[0, 1].grid(True, which='both', alpha=0.3)336337# Nyquist plot338axes[1, 0].plot(np.real(H), np.imag(H), 'b-', linewidth=1.5)339axes[1, 0].plot(1, 0, 'go', markersize=8, label='DC (0 Hz)')340axes[1, 0].plot(0.5, -0.5, 'ro', markersize=8, label='$f_c$')341axes[1, 0].plot(0, 0, 'ko', markersize=8, label=r'$\infty$')342axes[1, 0].set_xlabel('Real')343axes[1, 0].set_ylabel('Imaginary')344axes[1, 0].set_title('Nyquist Plot')345axes[1, 0].legend(loc='lower left', fontsize=8)346axes[1, 0].grid(True, alpha=0.3)347axes[1, 0].axis('equal')348axes[1, 0].set_xlim([-0.1, 1.1])349350# Group delay351axes[1, 1].semilogx(f, group_delay*1e6, 'b-', linewidth=1.5)352axes[1, 1].axhline(y=tau*1e6, color='r', linestyle='--', alpha=0.7, label=r'$\tau$')353axes[1, 1].axvline(x=f_cutoff, color='g', linestyle='--', alpha=0.7)354axes[1, 1].set_xlabel('Frequency (Hz)')355axes[1, 1].set_ylabel(r'Group Delay ($\mu$s)')356axes[1, 1].set_title('Group Delay')357axes[1, 1].legend(loc='upper right', fontsize=8)358axes[1, 1].grid(True, which='both', alpha=0.3)359360plt.tight_layout()361plt.savefig('rc_circuit_plot3.pdf', bbox_inches='tight', dpi=150)362plt.close()363\end{pycode}364365\begin{figure}[H]366\centering367\includegraphics[width=0.95\textwidth]{rc_circuit_plot3.pdf}368\caption{Frequency response characteristics: Bode plots, Nyquist diagram, and group delay.}369\end{figure}370371\begin{table}[H]372\centering373\caption{Frequency Response Characteristics}374\begin{tabular}{lcc}375\toprule376\textbf{Parameter} & \textbf{Value} & \textbf{Unit} \\377\midrule378Cutoff Frequency & \py{f"{f_cutoff:.1f}"} & Hz \\379Magnitude at $f_c$ & \py{f"{mag_at_fc:.1f}"} & dB \\380Phase at $f_c$ & \py{f"{phase_at_fc:.1f}"} & degrees \\381Roll-off per Decade & \py{f"{rolloff:.1f}"} & dB \\382DC Group Delay & \py{f"{tau*1e6:.1f}"} & $\mu$s \\383\bottomrule384\end{tabular}385\end{table}386387\section{Filter Design Applications}388389\subsection{Low-Pass and High-Pass Configurations}390391\begin{pycode}392# Compare low-pass and high-pass configurations393# Low-pass: H_LP = 1/(1 + jwRC)394# High-pass: H_HP = jwRC/(1 + jwRC)395396H_lp = 1 / (1 + 1j * omega * R * C)397H_hp = (1j * omega * R * C) / (1 + 1j * omega * R * C)398399H_lp_dB = 20 * np.log10(np.abs(H_lp))400H_hp_dB = 20 * np.log10(np.abs(H_hp))401402phase_lp = np.angle(H_lp, deg=True)403phase_hp = np.angle(H_hp, deg=True)404405# Second-order filters (two RC stages cascaded)406H_lp2 = H_lp**2407H_hp2 = H_hp**2408409H_lp2_dB = 20 * np.log10(np.abs(H_lp2))410H_hp2_dB = 20 * np.log10(np.abs(H_hp2))411412fig, axes = plt.subplots(2, 2, figsize=(10, 8))413414# First-order magnitude comparison415axes[0, 0].semilogx(f, H_lp_dB, 'b-', linewidth=1.5, label='Low-Pass')416axes[0, 0].semilogx(f, H_hp_dB, 'r-', linewidth=1.5, label='High-Pass')417axes[0, 0].axhline(y=-3, color='gray', linestyle='--', alpha=0.7)418axes[0, 0].axvline(x=f_cutoff, color='g', linestyle=':', alpha=0.7)419axes[0, 0].set_xlabel('Frequency (Hz)')420axes[0, 0].set_ylabel('Magnitude (dB)')421axes[0, 0].set_title('First-Order Filter Comparison')422axes[0, 0].legend(loc='center left', fontsize=8)423axes[0, 0].grid(True, which='both', alpha=0.3)424axes[0, 0].set_ylim([-40, 5])425426# Phase comparison427axes[0, 1].semilogx(f, phase_lp, 'b-', linewidth=1.5, label='Low-Pass')428axes[0, 1].semilogx(f, phase_hp, 'r-', linewidth=1.5, label='High-Pass')429axes[0, 1].axhline(y=-45, color='gray', linestyle='--', alpha=0.7)430axes[0, 1].axhline(y=45, color='gray', linestyle='--', alpha=0.7)431axes[0, 1].axvline(x=f_cutoff, color='g', linestyle=':', alpha=0.7)432axes[0, 1].set_xlabel('Frequency (Hz)')433axes[0, 1].set_ylabel('Phase (degrees)')434axes[0, 1].set_title('Phase Response Comparison')435axes[0, 1].legend(loc='center right', fontsize=8)436axes[0, 1].grid(True, which='both', alpha=0.3)437438# Second-order comparison439axes[1, 0].semilogx(f, H_lp_dB, 'b--', linewidth=1, alpha=0.7, label='1st Order LP')440axes[1, 0].semilogx(f, H_lp2_dB, 'b-', linewidth=1.5, label='2nd Order LP')441axes[1, 0].semilogx(f, H_hp_dB, 'r--', linewidth=1, alpha=0.7, label='1st Order HP')442axes[1, 0].semilogx(f, H_hp2_dB, 'r-', linewidth=1.5, label='2nd Order HP')443axes[1, 0].axhline(y=-3, color='gray', linestyle='--', alpha=0.5)444axes[1, 0].axvline(x=f_cutoff, color='g', linestyle=':', alpha=0.7)445axes[1, 0].set_xlabel('Frequency (Hz)')446axes[1, 0].set_ylabel('Magnitude (dB)')447axes[1, 0].set_title('Order Comparison')448axes[1, 0].legend(loc='lower left', fontsize=7)449axes[1, 0].grid(True, which='both', alpha=0.3)450axes[1, 0].set_ylim([-60, 5])451452# Selectivity (Q-factor) for different filter orders453orders = [1, 2, 3, 4]454colors = ['b', 'r', 'g', 'orange']455for n, color in zip(orders, colors):456H_n = H_lp**n457axes[1, 1].semilogx(f, 20*np.log10(np.abs(H_n)), color=color,458linewidth=1.5, label=f'n={n}')459460axes[1, 1].axhline(y=-3, color='gray', linestyle='--', alpha=0.5)461axes[1, 1].axvline(x=f_cutoff, color='k', linestyle=':', alpha=0.7)462axes[1, 1].set_xlabel('Frequency (Hz)')463axes[1, 1].set_ylabel('Magnitude (dB)')464axes[1, 1].set_title('Low-Pass Filter Order Effects')465axes[1, 1].legend(loc='lower left', fontsize=8)466axes[1, 1].grid(True, which='both', alpha=0.3)467axes[1, 1].set_ylim([-80, 5])468469plt.tight_layout()470plt.savefig('rc_circuit_plot4.pdf', bbox_inches='tight', dpi=150)471plt.close()472\end{pycode}473474\begin{figure}[H]475\centering476\includegraphics[width=0.95\textwidth]{rc_circuit_plot4.pdf}477\caption{Filter configurations: low-pass and high-pass comparison with order effects.}478\end{figure}479480\subsection{Band-Pass Filter Design}481482\begin{pycode}483# Band-pass filter: cascaded HP and LP484# Different cutoff frequencies for HP and LP485R_hp = 10000 # Higher R for lower cutoff486R_lp = 1000 # Lower R for higher cutoff487C_common = 100e-9 # 100 nF488489f_low = 1 / (2 * np.pi * R_hp * C_common) # Lower cutoff490f_high = 1 / (2 * np.pi * R_lp * C_common) # Upper cutoff491f_center = np.sqrt(f_low * f_high)492bandwidth = f_high - f_low493Q_factor = f_center / bandwidth494495# Transfer functions496H_hp_bp = (1j * omega * R_hp * C_common) / (1 + 1j * omega * R_hp * C_common)497H_lp_bp = 1 / (1 + 1j * omega * R_lp * C_common)498H_bp = H_hp_bp * H_lp_bp499500H_bp_dB = 20 * np.log10(np.abs(H_bp))501phase_bp = np.angle(H_bp, deg=True)502503# Find -3dB bandwidth504max_gain = np.max(H_bp_dB)505idx_3db_low = np.where(H_bp_dB[:np.argmax(H_bp_dB)] < max_gain - 3)[0][-1]506idx_3db_high = np.argmax(H_bp_dB) + np.where(H_bp_dB[np.argmax(H_bp_dB):] < max_gain - 3)[0][0]507f_3db_low = f[idx_3db_low]508f_3db_high = f[idx_3db_high]509measured_bw = f_3db_high - f_3db_low510511fig, axes = plt.subplots(2, 2, figsize=(10, 8))512513# Band-pass magnitude514axes[0, 0].semilogx(f, H_bp_dB, 'b-', linewidth=1.5)515axes[0, 0].axhline(y=max_gain-3, color='r', linestyle='--', alpha=0.7, label='-3 dB')516axes[0, 0].axvline(x=f_low, color='g', linestyle=':', alpha=0.7, label='$f_L$')517axes[0, 0].axvline(x=f_high, color='orange', linestyle=':', alpha=0.7, label='$f_H$')518axes[0, 0].axvline(x=f_center, color='purple', linestyle='--', alpha=0.7, label='$f_0$')519axes[0, 0].set_xlabel('Frequency (Hz)')520axes[0, 0].set_ylabel('Magnitude (dB)')521axes[0, 0].set_title('Band-Pass Filter Response')522axes[0, 0].legend(loc='lower right', fontsize=7)523axes[0, 0].grid(True, which='both', alpha=0.3)524axes[0, 0].set_ylim([-40, 5])525526# Band-pass phase527axes[0, 1].semilogx(f, phase_bp, 'b-', linewidth=1.5)528axes[0, 1].axhline(y=0, color='gray', linestyle='--', alpha=0.5)529axes[0, 1].axvline(x=f_center, color='purple', linestyle='--', alpha=0.7)530axes[0, 1].set_xlabel('Frequency (Hz)')531axes[0, 1].set_ylabel('Phase (degrees)')532axes[0, 1].set_title('Band-Pass Phase Response')533axes[0, 1].grid(True, which='both', alpha=0.3)534535# Component contributions536axes[1, 0].semilogx(f, 20*np.log10(np.abs(H_hp_bp)), 'r--', linewidth=1, label='HP Section')537axes[1, 0].semilogx(f, 20*np.log10(np.abs(H_lp_bp)), 'b--', linewidth=1, label='LP Section')538axes[1, 0].semilogx(f, H_bp_dB, 'g-', linewidth=1.5, label='Combined')539axes[1, 0].axvline(x=f_low, color='r', linestyle=':', alpha=0.5)540axes[1, 0].axvline(x=f_high, color='b', linestyle=':', alpha=0.5)541axes[1, 0].set_xlabel('Frequency (Hz)')542axes[1, 0].set_ylabel('Magnitude (dB)')543axes[1, 0].set_title('Filter Section Contributions')544axes[1, 0].legend(loc='lower left', fontsize=8)545axes[1, 0].grid(True, which='both', alpha=0.3)546axes[1, 0].set_ylim([-40, 5])547548# Impulse response of band-pass549num_bp = [R_hp * C_common, 0]550den_bp = np.convolve([R_hp * C_common, 1], [R_lp * C_common, 1])551bp_sys = signal.TransferFunction(num_bp, den_bp)552t_imp = np.linspace(0, 0.01, 1000)553t_i, y_imp = signal.impulse(bp_sys, T=t_imp)554555axes[1, 1].plot(t_i*1000, y_imp, 'b-', linewidth=1.5)556axes[1, 1].set_xlabel('Time (ms)')557axes[1, 1].set_ylabel('Amplitude')558axes[1, 1].set_title('Band-Pass Impulse Response')559axes[1, 1].grid(True, alpha=0.3)560561plt.tight_layout()562plt.savefig('rc_circuit_plot5.pdf', bbox_inches='tight', dpi=150)563plt.close()564\end{pycode}565566\begin{figure}[H]567\centering568\includegraphics[width=0.95\textwidth]{rc_circuit_plot5.pdf}569\caption{Band-pass filter design and frequency response analysis.}570\end{figure}571572\begin{table}[H]573\centering574\caption{Band-Pass Filter Parameters}575\begin{tabular}{lcc}576\toprule577\textbf{Parameter} & \textbf{Value} & \textbf{Unit} \\578\midrule579Lower Cutoff $f_L$ & \py{f"{f_low:.1f}"} & Hz \\580Upper Cutoff $f_H$ & \py{f"{f_high:.1f}"} & Hz \\581Center Frequency $f_0$ & \py{f"{f_center:.1f}"} & Hz \\582Bandwidth & \py{f"{bandwidth:.1f}"} & Hz \\583Quality Factor Q & \py{f"{Q_factor:.2f}"} & -- \\584\bottomrule585\end{tabular}586\end{table}587588\section{Signal Processing Applications}589590\subsection{Noise Filtering and Signal Conditioning}591592\begin{pycode}593# Signal processing demonstration594np.random.seed(42)595t_sig = np.linspace(0, 0.01, 2000)596dt_sig = t_sig[1] - t_sig[0]597fs = 1 / dt_sig598599# Create signal with noise600f_signal = 100 # 100 Hz signal601signal_clean = np.sin(2 * np.pi * f_signal * t_sig)602noise = 0.5 * np.random.randn(len(t_sig))603noise += 0.3 * np.sin(2 * np.pi * 5000 * t_sig) # High-frequency interference604signal_noisy = signal_clean + noise605606# Apply RC low-pass filter using convolution607# Impulse response of RC filter: h(t) = (1/tau) * exp(-t/tau)608tau_filter = 1 / (2 * np.pi * 500) # fc = 500 Hz609t_ir = np.arange(0, 5*tau_filter, dt_sig)610h_ir = (1/tau_filter) * np.exp(-t_ir/tau_filter) * dt_sig611612signal_filtered = np.convolve(signal_noisy, h_ir, mode='same')613614# FFT analysis615n_fft = len(t_sig)616freqs_fft = np.fft.fftfreq(n_fft, dt_sig)[:n_fft//2]617fft_noisy = np.abs(np.fft.fft(signal_noisy))[:n_fft//2] * 2/n_fft618fft_filtered = np.abs(np.fft.fft(signal_filtered))[:n_fft//2] * 2/n_fft619fft_clean = np.abs(np.fft.fft(signal_clean))[:n_fft//2] * 2/n_fft620621# SNR calculation622noise_power_before = np.var(signal_noisy - signal_clean)623noise_power_after = np.var(signal_filtered - signal_clean)624snr_before = 10 * np.log10(np.var(signal_clean) / noise_power_before)625snr_after = 10 * np.log10(np.var(signal_clean) / noise_power_after)626627fig, axes = plt.subplots(2, 2, figsize=(10, 8))628629# Time domain signals630axes[0, 0].plot(t_sig*1000, signal_noisy, 'gray', alpha=0.5, linewidth=0.5, label='Noisy')631axes[0, 0].plot(t_sig*1000, signal_filtered, 'b-', linewidth=1.5, label='Filtered')632axes[0, 0].plot(t_sig*1000, signal_clean, 'r--', linewidth=1, label='Original')633axes[0, 0].set_xlabel('Time (ms)')634axes[0, 0].set_ylabel('Amplitude')635axes[0, 0].set_title('Time Domain Filtering')636axes[0, 0].legend(loc='upper right', fontsize=8)637axes[0, 0].grid(True, alpha=0.3)638axes[0, 0].set_xlim([0, 5])639640# Frequency spectrum641axes[0, 1].semilogy(freqs_fft, fft_noisy, 'gray', alpha=0.5, linewidth=0.5, label='Noisy')642axes[0, 1].semilogy(freqs_fft, fft_filtered, 'b-', linewidth=1.5, label='Filtered')643axes[0, 1].axvline(x=500, color='r', linestyle='--', alpha=0.7, label='$f_c$')644axes[0, 1].set_xlabel('Frequency (Hz)')645axes[0, 1].set_ylabel('Magnitude')646axes[0, 1].set_title('Frequency Spectrum')647axes[0, 1].legend(loc='upper right', fontsize=8)648axes[0, 1].grid(True, which='both', alpha=0.3)649axes[0, 1].set_xlim([0, 10000])650651# Filter impulse response652axes[1, 0].plot(t_ir*1000, h_ir/dt_sig, 'b-', linewidth=1.5)653axes[1, 0].axvline(x=tau_filter*1000, color='r', linestyle='--', alpha=0.7, label=r'$\tau$')654axes[1, 0].set_xlabel('Time (ms)')655axes[1, 0].set_ylabel('Amplitude')656axes[1, 0].set_title('Filter Impulse Response')657axes[1, 0].legend(loc='upper right', fontsize=8)658axes[1, 0].grid(True, alpha=0.3)659660# SNR comparison661bars = axes[1, 1].bar(['Before', 'After'], [snr_before, snr_after],662color=['gray', 'blue'], alpha=0.7)663axes[1, 1].set_ylabel('SNR (dB)')664axes[1, 1].set_title('Signal-to-Noise Ratio Improvement')665axes[1, 1].grid(True, alpha=0.3, axis='y')666667# Add value labels on bars668for bar, val in zip(bars, [snr_before, snr_after]):669axes[1, 1].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,670f'{val:.1f} dB', ha='center', fontsize=9)671672plt.tight_layout()673plt.savefig('rc_circuit_plot6.pdf', bbox_inches='tight', dpi=150)674plt.close()675676snr_improvement = snr_after - snr_before677\end{pycode}678679\begin{figure}[H]680\centering681\includegraphics[width=0.95\textwidth]{rc_circuit_plot6.pdf}682\caption{Signal processing application: noise filtering with RC low-pass filter.}683\end{figure}684685\noindent\textbf{Signal Processing Results:}686\begin{itemize}687\item SNR Before Filtering: \py{f"{snr_before:.1f}"} dB688\item SNR After Filtering: \py{f"{snr_after:.1f}"} dB689\item SNR Improvement: \py{f"{snr_improvement:.1f}"} dB690\end{itemize}691692\section{Component Sensitivity Analysis}693694\begin{pycode}695# Sensitivity analysis: effect of component variations696R_nom = 1000697C_nom = 1e-6698699# Tolerance ranges700tolerances = [1, 5, 10, 20] # percent701702# Monte Carlo simulation for cutoff frequency variation703n_samples = 1000704f_c_samples = []705tolerance_labels = []706707for tol in tolerances:708R_samples = R_nom * (1 + (np.random.rand(n_samples) - 0.5) * 2 * tol/100)709C_samples = C_nom * (1 + (np.random.rand(n_samples) - 0.5) * 2 * tol/100)710f_c_samples.append(1 / (2 * np.pi * R_samples * C_samples))711tolerance_labels.append(f'{tol}%')712713# Nominal cutoff714f_c_nom = 1 / (2 * np.pi * R_nom * C_nom)715716fig, axes = plt.subplots(2, 2, figsize=(10, 8))717718# Histogram of cutoff frequencies719for i, (fc, label) in enumerate(zip(f_c_samples, tolerance_labels)):720axes[0, 0].hist(fc, bins=30, alpha=0.5, label=label)721722axes[0, 0].axvline(x=f_c_nom, color='r', linestyle='--', linewidth=2, label='Nominal')723axes[0, 0].set_xlabel('Cutoff Frequency (Hz)')724axes[0, 0].set_ylabel('Count')725axes[0, 0].set_title('Cutoff Frequency Distribution')726axes[0, 0].legend(loc='upper right', fontsize=8)727728# Standard deviation vs tolerance729stds = [np.std(fc) for fc in f_c_samples]730axes[0, 1].plot(tolerances, stds, 'bo-', linewidth=1.5, markersize=8)731axes[0, 1].set_xlabel('Component Tolerance (%)')732axes[0, 1].set_ylabel('Std Dev of $f_c$ (Hz)')733axes[0, 1].set_title('Cutoff Frequency Variability')734axes[0, 1].grid(True, alpha=0.3)735736# Frequency response with tolerance bands (5%)737R_min, R_max = R_nom * 0.95, R_nom * 1.05738C_min, C_max = C_nom * 0.95, C_nom * 1.05739740# Worst cases741H_nom = 1 / (1 + 1j * omega * R_nom * C_nom)742H_low_fc = 1 / (1 + 1j * omega * R_max * C_max) # Lowest cutoff743H_high_fc = 1 / (1 + 1j * omega * R_min * C_min) # Highest cutoff744745axes[1, 0].semilogx(f, 20*np.log10(np.abs(H_nom)), 'b-', linewidth=1.5, label='Nominal')746axes[1, 0].fill_between(f, 20*np.log10(np.abs(H_low_fc)),74720*np.log10(np.abs(H_high_fc)),748alpha=0.3, color='blue', label='5% Tolerance')749axes[1, 0].axhline(y=-3, color='r', linestyle='--', alpha=0.7)750axes[1, 0].set_xlabel('Frequency (Hz)')751axes[1, 0].set_ylabel('Magnitude (dB)')752axes[1, 0].set_title('Frequency Response with Tolerance')753axes[1, 0].legend(loc='lower left', fontsize=8)754axes[1, 0].grid(True, which='both', alpha=0.3)755axes[1, 0].set_ylim([-40, 5])756757# Temperature coefficient effects758temps = np.linspace(-40, 85, 100) # Temperature range (C)759# Typical temperature coefficients760tc_r = 100e-6 # 100 ppm/C for metal film761tc_c = -750e-6 # -750 ppm/C for ceramic capacitor (X7R)762763R_temp = R_nom * (1 + tc_r * (temps - 25))764C_temp = C_nom * (1 + tc_c * (temps - 25))765f_c_temp = 1 / (2 * np.pi * R_temp * C_temp)766767axes[1, 1].plot(temps, f_c_temp, 'b-', linewidth=1.5)768axes[1, 1].axhline(y=f_c_nom, color='r', linestyle='--', alpha=0.7, label='Nominal')769axes[1, 1].axvline(x=25, color='g', linestyle=':', alpha=0.7, label='25°C')770axes[1, 1].set_xlabel('Temperature (°C)')771axes[1, 1].set_ylabel('Cutoff Frequency (Hz)')772axes[1, 1].set_title('Temperature Dependence')773axes[1, 1].legend(loc='upper right', fontsize=8)774axes[1, 1].grid(True, alpha=0.3)775776plt.tight_layout()777plt.savefig('rc_circuit_plot7.pdf', bbox_inches='tight', dpi=150)778plt.close()779780# Calculate statistics781fc_5pct_std = stds[1] # 5% tolerance782fc_temp_range = np.max(f_c_temp) - np.min(f_c_temp)783\end{pycode}784785\begin{figure}[H]786\centering787\includegraphics[width=0.95\textwidth]{rc_circuit_plot7.pdf}788\caption{Component sensitivity analysis: tolerance and temperature effects.}789\end{figure}790791\begin{table}[H]792\centering793\caption{Sensitivity Analysis Summary}794\begin{tabular}{lcc}795\toprule796\textbf{Parameter} & \textbf{Value} & \textbf{Unit} \\797\midrule798Nominal $f_c$ & \py{f"{f_c_nom:.1f}"} & Hz \\799Std Dev (5\% tolerance) & \py{f"{fc_5pct_std:.1f}"} & Hz \\800$f_c$ Range (-40 to 85°C) & \py{f"{fc_temp_range:.1f}"} & Hz \\801\bottomrule802\end{tabular}803\end{table}804805\section{Conclusions}806807This laboratory analysis of RC circuits demonstrated:808809\begin{enumerate}810\item \textbf{Transient Response}: The time constant $\tau = \py{f"{tau*1000:.3f}"}$ ms governs charging/discharging dynamics, with the circuit reaching 99.3\% of final value in $5\tau$.811812\item \textbf{Frequency Response}: The first-order RC filter exhibits a cutoff frequency of $f_c = \py{f"{f_cutoff:.1f}"}$ Hz with -20 dB/decade roll-off and -45° phase shift at cutoff.813814\item \textbf{Filter Design}: Low-pass, high-pass, and band-pass configurations were analyzed, showing how cascaded stages increase selectivity with -20n dB/decade roll-off for n stages.815816\item \textbf{Signal Processing}: RC filtering improved SNR by \py{f"{snr_improvement:.1f}"} dB for the test signal with high-frequency noise.817818\item \textbf{Sensitivity}: Component tolerances of 5\% result in cutoff frequency standard deviation of \py{f"{fc_5pct_std:.1f}"} Hz, requiring careful component selection for precision applications.819\end{enumerate}820821The computational analysis ensures all results are reproducible and can be easily modified for different circuit parameters.822823\end{document}824825826