Introduction
I recently embarked on a journey to design and refine an AM radio receiver in Python, using the PySpice framework for SPICE simulations. What made this experience special was that I essentially turned my design process into an interactive conversation with an AI—where the AI itself helped me adjust component values based on verbose code comments and expected operating conditions embedded in my PySpice code.
Below, I’ll walk you through why this approach worked so well, how I set it up, and how I used each round of simulation logs (and waveforms) to steer the AI’s suggestions toward a perfectly tuned circuit.
PySpice – A Pythonic Approach to SPICE Simulations
You probably use some sort of SPICE variant for analog circuit simulations, but you might also want the flexibility of Python to automate and analyze results quickly; that’s where PySpice comes in. PySpice lets you write SPICE netlists directly in Python, transforming traditional circuit design into a fully scriptable process.
With PySpice, you can:
- Write SPICE Netlists in Python: Define all your components—inductors, capacitors, transistors—as Python objects. This makes it easy to tweak values and re-run simulations without needing to use a separate SPICE GUI.
- Generate Integrated Signals: You can easily parameterize signal modulation index, amplitude, or frequency with just a few lines of code.
- Collect and Plot Data Effortlessly: Since everything lives in Python, you can quickly gather node voltages and time-series data, and then generate Matplotlib plots of the resulting waveforms to verify that they match your expectations.
In essence, PySpice gives you the full power of SPICE simulations combined with the versatility of Python, making it an ideal candidate for AI-based iterative circuit design and testing.
Verbose Comments – Setting Targets and Guiding AI
To enable an AI to help you fine-tune or design your electronic circuits, it’s crucial to embed super-verbose comments within your PySpice code. This strategy involves three key steps:
-
Include Detailed Comments:
Instead of simply noting component values, write extended commentary that explains the design rationale behind each component and the chosen values. For example, rather than just declaring a resistor value, add a comment like:“We want the transistor’s emitter to idle at ~1.1 V for proper headroom, so the bias network is designed to set the base at ~1.8 V.”
These comments serve as a clear, textual blueprint of your design expectations, detailing exactly what should occur at each critical node.
Note: You can get the AI to add these comments. -
Generate Log Files from Simulations:
When you run your PySpice simulation, log key data such as the peak and minimum voltages at various nodes. These log files capture the actual performance of your circuit. For instance, you might see:DEBUG: Node 'amp_out': peak=0.88 V, min=0.20 V
This logging data provides an accurate record of how the circuit behaves under simulation. -
Have the AI Compare Expectations to Results:
With both your verbose comments (detailing the expected conditions) and the actual log file results in hand, you can then ask the AI to compare the two. The AI looks for discrepancies between the expected operating conditions—like an emitter voltage of ~1.1 V—and the simulation logs. When it finds mismatches, the AI can suggest precise adjustments. For example, if a transistor emitter voltage is lower than expected, the AI can recommend tweaking the bias resistor ratios.
By pairing these detailed, target-oriented comments with real simulation data, you create a highly efficient feedback loop. This approach provides a clear design roadmap that the AI can use to propose logical refinements, helping you quickly bring your circuit’s performance in line with your design goals.
A Worked Example: Fine Tuning a AM Radio Circuit
Basic Circuit Structure
I started by using Claude.ai to create a PySpice Circuit object named “AM Radio Receiver” and specifying a few key stages:
- Signal Source: A 1 MHz carrier, amplitude 1 V, modulated by a 1 kHz tone at 50% depth.
- Demodulator: An LC tank circuit tuned to 1 MHz (with a 100 µH inductor and 100 pF capacitor) plus a diode envelope detector.
- Emitter Follower: A 2N2222 transistor biased from a 5 V rail to buffer the demodulated signal and prevent load-induced distortion.
Adding in Comments
I than asked ChatGPT (o1) to add in comments explaining the design decisions and expected node values into the PySPICE code describing a simple AM radio.
Note: I generally find Claude.ai technically better and ChatGPT better at verbal reasoning and description.
Click to Show PySpice Code
Every major node or stage got a similar explanation, plus a numeric target. This meant that when I ran the PySpice simulation and captured, for instance, Node ‘amp_out’: peak=0.2 V, min=0.0 V, I could say, “Hey, AI, our emitter is nowhere near the ~1.1 V we wrote in the comments. What happened?” and it could respond with an informed suggestion.
Running Transient Simulations and Logging Results
Once the circuit was in place, I performed a transient analysis by running the above code. I used Python’s built-in logging to output the peak and minimum voltages at each node after the simulation to a log file. I also plotted these time-series data using Matplotlib, to visualize if the waveform was clipping at the top, bottoming out, or otherwise looking suspicious.
First AI Feedback Loop
As you can see, the transistor emitter follower output is bottoming out, so I provided the following feedback to ChatGPT (o1) (by attaching both the image of the waveforms and also a zip of the logfile (the logfile didn’t attach unzipped, presumably because it was too big)).
“As you can see, the transistor emitter follower output bottoms out. Compare the values in the log file to the expected values per the code’s comments to determine what needs adjusting, and adjust the component values (and comments) accordingly.”
ChatGPT (o1) responded as follows:
“Below is an updated version of the circuit. The key change is in the transistor’s bias‐network resistor values. Previously, the base was biased too low (under 1 V), causing the emitter follower to “bottom out.” By increasing the base‐bias voltage to around 1.8 V, the emitter will sit roughly near 1.1 V. That sets a more suitable quiescent current through the transistor and keeps its emitter from saturating near 0 V. Comments have been updated to explain why these new values were chosen.”
Click to Show PySpice Code
What Changed
Bias Resistors
- Old:
R_B1=47 kΩ
,R_B2=10 kΩ
put the base near
, leaving the emitter around- New:
R_B1=39 kΩ
,R_B2=22 kΩ
raises the base to
, so the emitter idles nearComments
The comments now explain why the new resistor values help avoid “bottoming out” the emitter and ensure the transistor has enough headroom for the incoming audio signal.Everything else remains the same, including the logging setup to filter out Matplotlib’s debug messages and write circuit debug info to
circuit_simulation.log
.
(End of ChatGPT’s response.)
Testing Initial Improvements
Running the improved code design gave the following results.
As you can see, that is much improved over the original circuit. The transistor emitter follower output no longer bottoms out, but we still have some ringing and clipping at the top of the waveform.
Second AI Feedback Loop
I provided the following feedback to ChatGPT (o1) (again attaching an image of the waveform plots and a zip of the logfile):
That is an improvement. However, as you can see, the top of the transistor emitter output wave is noisier than the bottom, and is somewhat flattened out. Refer to the attached log file (and expected values in the code comments) to adjust the component values (and comments) to fix this issue.
ChatGPT responded as follows:
Below is an updated version of the code that addresses the “flattening” at the top of the emitter‐follower waveform. The key fix here is to lower the collector resistor so that the transistor’s collector voltage runs higher in quiescent operation. That extra headroom helps prevent the transistor from running into the supply rail at the top of the waveform. Comments have been updated accordingly.
Click to Show PySpice Code
What Changed
- Collector Resistor Reduced: Changed from
2.2 kΩ
to1 kΩ
. This raises the transistor’s collector voltage in quiescent conditions to around , giving the emitter‐follower more headroom on positive peaks.- Comments Updated: Additional comments now explain how lowering
R_C
reduces top‐end clipping and noise in the emitter output by preventing the transistor from saturating near the supply rail.- Transient Time Extended: Simulation runs to 10ms (
end_time = 1e-2 @ u_s
) so we can view more cycles of the 1 kHz modulation envelope.With these adjustments, the top portion of the emitter‐follower output should be cleaner, reducing flattening and noise.
(End of ChatGPT’s response.)
AI Improved AM Radio
Running the ChatGPT’s second pass gave the following analysis.
Which is a pretty good response for such a simple circuit.
Process and Conclusion
In essence, this entire process hinges on a simple feedback loop, enhanced by the strengths (and idiosyncrasies) of large language models:
-
Add Super-Verbose Comments to Your PySpice Code
Clearly spell out every design goal—component values, expected node voltages, and underlying rationales—right alongside the netlist. These comments act as the circuit’s “instruction manual,” giving the AI an unambiguous reference for how you intend the circuit to behave.
You can get an AI to generate these code comments. -
Run Simulations and Log the Results
PySpice’s Python interface makes it trivial to capture data (peak voltages, waveforms, etc.) and store them in a log file or display them in plots. With one click, you can re-run the entire circuit and gather fresh data. -
Have the AI Compare Expectations to Actual Performance
Because your code explicitly states something like “the transistor emitter should idle at ~1.1 V,” it’s very easy for the AI to notice if the logs say “0.2 V.” The AI can then suggest how to reconcile the difference until your real results align with the design comments.
Although large language models aren’t “super smart” in a rigorous engineering sense, they excel at consuming and generating text. This is because under the hood, they’re text-generation machines that rely on matching patterns in language. Therefore when you feed them your code’s verbose commentary (complete with numeric targets) and your circuit’s performance logs, you create a scenario in which they can identify discrepancies with surprising precision.
Each round of simulation nudges the circuit closer to your ideal specs, simply because the AI sees an explicit mismatch in the text (“expected 1.1 V, got 0.2 V”) and proposes the most likely solution—i.e., adjusting component values or explaining alternative topologies.
This method doesn’t replace deep engineering expertise. However, by combining:
- PySpice for quick, iterative simulations,
- Explicit Comments for stating your goals,
- AI Comparisons for bridging the gap between “what you want” and “what you got,”
you can accelerate the design and refinement of analog circuits—right from within a Pythonic environment. It’s a straightforward yet powerful synergy between human ingenuity, classical SPICE modeling, and the AI’s knack for textual alignment.
Happy designing!