You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.7 KiB
93 lines
2.7 KiB
"""
|
|
AC Analysis Example
|
|
|
|
This example demonstrates using the pyngspice Python extension
|
|
to perform AC analysis (frequency sweep) on an RC filter.
|
|
"""
|
|
|
|
try:
|
|
from pyngspice import SimRunner, RawRead
|
|
except ImportError:
|
|
print("pyngspice extension not installed. Run: pip install -e .")
|
|
exit(1)
|
|
|
|
import numpy as np
|
|
import os
|
|
|
|
# RC filter netlist with AC analysis
|
|
netlist_content = """
|
|
* RC Low-Pass Filter - AC Analysis
|
|
* Shows magnitude and phase response
|
|
|
|
V1 in 0 AC 1
|
|
R1 in out 1k
|
|
C1 out 0 100n
|
|
|
|
.ac dec 100 1 100k
|
|
.end
|
|
"""
|
|
|
|
def main():
|
|
output_dir = "./output"
|
|
os.makedirs(output_dir, exist_ok=True)
|
|
|
|
netlist_file = os.path.join(output_dir, "ac_filter.net")
|
|
with open(netlist_file, "w") as f:
|
|
f.write(netlist_content)
|
|
|
|
print("Running AC analysis...")
|
|
runner = SimRunner(output_folder=output_dir)
|
|
raw_file, log_file = runner.run_now(netlist_file)
|
|
|
|
raw = RawRead(raw_file)
|
|
print(f"Analysis type: {raw.analysis_type}")
|
|
print(f"Complex data: {raw.is_complex}")
|
|
print(f"\nTraces: {raw.get_trace_names()}")
|
|
|
|
# Get frequency and output voltage (complex)
|
|
freq = raw.get_trace("frequency").get_wave(0)
|
|
v_out_complex = raw.get_trace("V(out)").get_wave_complex(0)
|
|
|
|
# Calculate magnitude in dB and phase in degrees
|
|
magnitude_db = 20 * np.log10(np.abs(v_out_complex))
|
|
phase_deg = np.angle(v_out_complex, deg=True)
|
|
|
|
# Find -3dB cutoff frequency
|
|
idx_3db = np.argmin(np.abs(magnitude_db - (-3)))
|
|
f_cutoff = freq[idx_3db]
|
|
|
|
print(f"\n-3dB cutoff frequency: {f_cutoff:.2f} Hz")
|
|
print(f"Theoretical: {1/(2*np.pi*1e3*100e-9):.2f} Hz")
|
|
|
|
# Plot if matplotlib available
|
|
try:
|
|
import matplotlib.pyplot as plt
|
|
|
|
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), sharex=True)
|
|
|
|
ax1.semilogx(freq, magnitude_db)
|
|
ax1.axhline(-3, color='r', linestyle='--', alpha=0.5, label='-3dB')
|
|
ax1.axvline(f_cutoff, color='r', linestyle='--', alpha=0.5)
|
|
ax1.set_ylabel('Magnitude (dB)')
|
|
ax1.set_title('RC Low-Pass Filter Frequency Response')
|
|
ax1.legend()
|
|
ax1.grid(True, which='both', alpha=0.3)
|
|
|
|
ax2.semilogx(freq, phase_deg)
|
|
ax2.axhline(-45, color='r', linestyle='--', alpha=0.5, label='-45°')
|
|
ax2.set_xlabel('Frequency (Hz)')
|
|
ax2.set_ylabel('Phase (degrees)')
|
|
ax2.legend()
|
|
ax2.grid(True, which='both', alpha=0.3)
|
|
|
|
plt.tight_layout()
|
|
plot_file = os.path.join(output_dir, "ac_filter.png")
|
|
plt.savefig(plot_file, dpi=150)
|
|
print(f"\nPlot saved to: {plot_file}")
|
|
plt.show()
|
|
|
|
except ImportError:
|
|
print("\nInstall matplotlib for plotting: pip install matplotlib")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|