Loading...
    Content is user-generated and unverified.
    import numpy as np import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec # Circuit parameters Av_intrinsic = -357 Av_with_RB = -4.0 fH = 188e3 # Hz (188 kHz) wH = 2 * np.pi * fH # rad/s # Generate frequency range (10 Hz to 100 MHz) freq = np.logspace(1, 8, 1000) w = 2 * np.pi * freq # Calculate transfer function for both cases def calculate_response(Av, w, wH): s = w / wH # Transfer function: H(jw) = Av / (1 + jw/wH) H = Av / (1 + 1j * s) magnitude_dB = 20 * np.log10(np.abs(H)) phase_deg = np.angle(H) * (180 / np.pi) return magnitude_dB, phase_deg mag_intrinsic, phase_intrinsic = calculate_response(Av_intrinsic, w, wH) mag_with_RB, phase_with_RB = calculate_response(Av_with_RB, w, wH) # Create figure with professional styling plt.style.use('seaborn-v0_8-darkgrid') fig = plt.figure(figsize=(14, 10)) gs = GridSpec(2, 1, height_ratios=[1, 1], hspace=0.3) # Color scheme color_intrinsic = '#2563eb' # Blue color_rb = '#dc2626' # Red color_cutoff = '#059669' # Green # ==================== MAGNITUDE PLOT ==================== ax1 = fig.add_subplot(gs[0]) # Plot magnitude responses ax1.semilogx(freq, mag_intrinsic, color=color_intrinsic, linewidth=2.5, label=f'Intrinsic Gain (Av = {Av_intrinsic})', zorder=3) ax1.semilogx(freq, mag_with_RB, color=color_rb, linewidth=2.5, linestyle='--', label=f'Gain with RB (Av = {Av_with_RB})', zorder=3) # Mark cutoff frequency ax1.axvline(fH, color=color_cutoff, linestyle=':', linewidth=2, label=f'fH = {fH/1e3:.0f} kHz', alpha=0.7, zorder=2) # Mark -3dB points dc_gain_intrinsic = 20 * np.log10(np.abs(Av_intrinsic)) dc_gain_rb = 20 * np.log10(np.abs(Av_with_RB)) ax1.plot(fH, dc_gain_intrinsic - 3, 'o', color=color_intrinsic, markersize=8, markerfacecolor='white', markeredgewidth=2, zorder=4) ax1.plot(fH, dc_gain_rb - 3, 's', color=color_rb, markersize=8, markerfacecolor='white', markeredgewidth=2, zorder=4) # Add annotation for -3dB point ax1.annotate(f'-3 dB\n({fH/1e3:.0f} kHz)', xy=(fH, dc_gain_intrinsic - 3), xytext=(fH*5, dc_gain_intrinsic - 3), fontsize=10, ha='left', bbox=dict(boxstyle='round,pad=0.5', facecolor='yellow', alpha=0.7), arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0', lw=1.5)) # Add asymptotic lines (Bode approximation) freq_flat = freq[freq < fH] freq_slope = freq[freq >= fH] ax1.semilogx(freq_flat, np.ones_like(freq_flat) * dc_gain_intrinsic, color=color_intrinsic, linestyle=':', linewidth=1.5, alpha=0.5) slope_intrinsic = dc_gain_intrinsic - 20 * np.log10(freq_slope / fH) ax1.semilogx(freq_slope, slope_intrinsic, color=color_intrinsic, linestyle=':', linewidth=1.5, alpha=0.5) # Formatting ax1.set_xlabel('Frequency (Hz)', fontsize=13, fontweight='bold') ax1.set_ylabel('Magnitude (dB)', fontsize=13, fontweight='bold') ax1.set_title('BJT Common-Emitter Amplifier - Frequency Response', fontsize=15, fontweight='bold', pad=20) ax1.grid(True, which='both', alpha=0.3, linewidth=0.5) ax1.legend(loc='upper right', fontsize=11, framealpha=0.95, edgecolor='black') ax1.set_xlim([10, 1e8]) # Add text box with key parameters textstr = '\n'.join(( 'Key Parameters:', f'DC Gain (intrinsic): {dc_gain_intrinsic:.1f} dB', f'DC Gain (with RB): {dc_gain_rb:.1f} dB', f'Cutoff Frequency: {fH/1e3:.0f} kHz', f'Roll-off: -20 dB/decade' )) props = dict(boxstyle='round', facecolor='wheat', alpha=0.9, edgecolor='black') ax1.text(0.02, 0.05, textstr, transform=ax1.transAxes, fontsize=10, verticalalignment='bottom', bbox=props, family='monospace') # ==================== PHASE PLOT ==================== ax2 = fig.add_subplot(gs[1]) # Plot phase responses ax2.semilogx(freq, phase_intrinsic, color=color_intrinsic, linewidth=2.5, label=f'Intrinsic Gain (Av = {Av_intrinsic})', zorder=3) ax2.semilogx(freq, phase_with_RB, color=color_rb, linewidth=2.5, linestyle='--', label=f'Gain with RB (Av = {Av_with_RB})', zorder=3) # Mark cutoff frequency ax2.axvline(fH, color=color_cutoff, linestyle=':', linewidth=2, label=f'fH = {fH/1e3:.0f} kHz', alpha=0.7, zorder=2) # Mark -225° point at cutoff phase_at_cutoff_intrinsic = np.interp(fH, freq, phase_intrinsic) ax2.plot(fH, phase_at_cutoff_intrinsic, 'o', color=color_intrinsic, markersize=8, markerfacecolor='white', markeredgewidth=2, zorder=4) # Add phase annotations ax2.annotate(f'{phase_at_cutoff_intrinsic:.0f}°', xy=(fH, phase_at_cutoff_intrinsic), xytext=(fH*5, phase_at_cutoff_intrinsic), fontsize=10, ha='left', bbox=dict(boxstyle='round,pad=0.5', facecolor='lightblue', alpha=0.7), arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0', lw=1.5)) # Add horizontal reference lines ax2.axhline(-180, color='gray', linestyle='--', linewidth=1, alpha=0.5) ax2.axhline(-225, color='gray', linestyle='--', linewidth=1, alpha=0.5) ax2.axhline(-270, color='gray', linestyle='--', linewidth=1, alpha=0.5) # Add reference line labels ax2.text(15, -180, '-180°', fontsize=10, va='bottom', color='gray', fontweight='bold') ax2.text(15, -225, '-225°', fontsize=10, va='bottom', color='gray', fontweight='bold') ax2.text(15, -270, '-270°', fontsize=10, va='top', color='gray', fontweight='bold') # Formatting ax2.set_xlabel('Frequency (Hz)', fontsize=13, fontweight='bold') ax2.set_ylabel('Phase (degrees)', fontsize=13, fontweight='bold') ax2.set_title('Phase Response', fontsize=15, fontweight='bold', pad=20) ax2.grid(True, which='both', alpha=0.3, linewidth=0.5) ax2.legend(loc='lower left', fontsize=11, framealpha=0.95, edgecolor='black') ax2.set_xlim([10, 1e8]) ax2.set_ylim([-280, -170]) ax2.set_yticks(np.arange(-270, -170, 15)) # Add text box with phase info textstr_phase = '\n'.join(( 'Phase Characteristics:', '• -180° due to inverting gain', '• -45° shift at cutoff', '• -90° total from pole', '• Approaches -270° at HF' )) props_phase = dict(boxstyle='round', facecolor='lightcyan', alpha=0.9, edgecolor='black') ax2.text(0.02, 0.95, textstr_phase, transform=ax2.transAxes, fontsize=10, verticalalignment='top', bbox=props_phase, family='monospace') # Overall figure adjustments fig.suptitle('BJT Common-Emitter Amplifier Bode Plot\nβ=100, RC=4kΩ, RB=100kΩ, Cπ=50pF, Cμ=2pF', fontsize=17, fontweight='bold', y=0.995) plt.tight_layout() plt.savefig('bjt_bode_plot.png', dpi=300, bbox_inches='tight', facecolor='white') plt.show() print("Professional Bode plot saved as 'bjt_bode_plot.png'")
    Content is user-generated and unverified.