All About Circuits

Introduction to SLiCAP for Analog Circuit Design

Learn how to design and verify analog circuits using SLiCAP, a Python-based symbolic simulator program.


Technical Article November 06, 2024 by Gilles Ackaert

Let’s face it—extracting useful design information from SPICE simulations can be challenging. If you’re an analog designer, how much time have you spent changing parameters in SPICE, iteratively re-running the program, and inspecting the numeric results?

In this article, we’ll discuss a helpful open-source Python package called SLiCAP (short for Symbolic Linear Circuit Analysis Program). As we’ll see, SLiCAP complements standard SPICE-based simulators by providing design information without the need for cumbersome trial-and-error procedures. We’ll start by going over some key features of SLiCAP; we’ll then demonstrate those features by using SLiCAP to design and verify a simple negative-feedback voltage amplifier.

 

What Can SLiCAP Do?

One of SLiCAP’s biggest selling points is its ability to solve linear circuit design equations. It can compute circuit solutions for both DC and dynamic frequency behavior, in the latter case using Laplace-domain transfer functions, root locus analysis, and pole-zero analysis. Both symbolic and numeric noise analysis are possible as well.

SLiCAP also has dedicated parameter-stepping functions. Many devices—transistors, for example—behave nonlinearly. We can use the parameter-stepping functions to change the operating point around which these components are linearized.

For those of us who don’t particularly enjoy documentation, SLiCAP can help in that area as well. The Python application allows us to directly use SLiCAP output in post-processing scripts. As we go through the design process, the application can simultaneously generate HTML pages documenting it.

Note that this is an introduction to SLiCAP’s features, not a comprehensive list. We’ll discuss a few more—those related to netlist generation, for example—later on in the article. However, the reader is advised to consult the SLiCAP manual for a more complete overview of the program’s functionalities.

The “How to Use SLiCAP” section of the manual includes a detailed workflow. We can roughly summarize it as:

  1. Set up a circuit netlist.
  2. Define a SLiCAP instruction in Python.
  3. Execute the instruction.
  4. Use the results to size circuit parameters (post-processing) and/or verify your design.
  5. Generate an indexed HTML report.

To better grasp what SLiCAP offers, let’s work through a design example.

 

Using SLiCAP to Design a Negative-Feedback Amplifier

In this example, we’ll use SLiCAP’s asymptotic gain model to design the gain and dynamic behavior of a negative-feedback amplifier. We’ll then use SLiCAP-generated Bode plots to evaluate our design in the frequency domain. Though we won’t go deep into coding technicalities, this example should provide sufficient detail to illustrate the program’s underlying design philosophy.

 

Requirements

Our goal is to design the key components of a voltage-to-voltage amplifier with the following specifications:

  • A source-to-load amplification factor of Av = 20 V/V.
  • –3 dB bandwidth (fBW) of 500 kHz or greater.

For demonstration purposes, we’ll assume that the load has infinite impedance and the source has zero impedance. Let’s further assume that the chosen circuit topology is a negative-feedback configuration with resistive voltage divider feedback and a high-gain op amp controller. Our original design goal now boils down to:

  • Sizing two resistors.
  • Selecting an operational amplifier.

The above must be done such that the requirements for Av and fBW are met.

 

Setting Up the SLiCAP Netlist

To solve a network, SLiCAP needs a circuit netlist as input. You can either create a netlist manually or import one—the netlist syntax is compatible with SPICE. If you choose to manually create a netlist, SLiCAP has a number of built-in models—including linearized models of op amps and transistors—for both passive and active components.

Because it’s easier to read a schematic than the netlist text, you may prefer to build a schematic in SPICE and generate a netlist. If you choose that route, it’s possible to use any of the following with SLiCAP device symbols:

  • KiCad.
  • LTspice.
  • gSchem.
  • Lepton-eda.

Instructions and syntax details can be found in the SLiCAP user guide.

Returning to our design example, I chose to generate a netlist in LTspice. This procedure, which results in a .cir file, is illustrated in Figure 1 along with the circuit topology.

 

Left: circuit topology and schematic capture in LTspice. Right: SLiCAP netlist creation.

Figure 1. Left: Circuit topology and schematic capture in LTspice. Right: SLiCAP netlist creation.

 

The built-in device model (OV in the .model statement above) is used as the controller of the amplifier. A voltage-source at the output is controlled by the differential voltage between the input terminals, modeling the small-signal dynamic behavior of a voltage-feedback op amp.

The model parameters can be used to attribute input and output impedance and voltage gain. Because we want to keep this example simple, we’re using a highly idealized op amp model. It has an integrating voltage gain equal to \(\frac{2 \pi GB}{s}\), where GB is the gain-bandwidth product of the op amp.

 

The Design Method and Asymptotic Feedback Model

Before we run the SLiCAP simulation, let’s examine the two-step design method we’ll use for our negative-feedback amplifier.

In the first step, we determine the ideal gain by replacing the op amp with a nullor (an ideal amplifier with infinite current, voltage, transconductance, and transimpedance gain). This coincides with the asymptotic gain, A(s), if the loop gain reference variable is chosen correctly. The asymptotic gain is found by assuming an infinite controller gain.

In the second step, we determine the influence of the controller’s non-idealities, including a finite gain and bandwidth limitations. This information is embedded in the Laplace-domain servo function, S(s), which can be found through the following equation:

$$S(s)~=~\frac{-L(s)}{1~-~L(s)}$$

 

where L(s) is the loop gain.

The source-to-load gain, G(s), is the product of the asymptotic gain and the servo gain:

$$G(s)~=~A_{\infty}(s)~\times~S(s)$$

 

In short, Step 1 tells you how to design the feedback network based on the desired transfer function. Step 2 tells you how to select the performance aspects (such as gain and bandwidth) of the controller such that the source-to-load gain, G(s), is still acceptable. The elegance of this method lies in separating the design of the feedback network from the design of the controller.

For more information on the two-step design method and the asymptotic feedback model, please refer to “Structured Electronics Design: A Conceptual Approach to Amplifier Design” by Anton Montagne. This book is available as a free PDF online.

 

Defining and Executing Instructions

Let’s pick up where we left off in the SLiCAP design process. So far, we’ve defined our circuit through a netlist. The next step will be to define SLiCAP instructions that provide information for the specific performance aspects we’re interested in. This is where coding in Python starts.

The first step in defining an instruction is to create an instance of an instruction object and assign a circuit object to the instruction. As the code snippet in Figure 2 shows, this means connecting the earlier created .cir netlist file to the instruction.

 

Creating a SLiCAP instruction instance and connecting it to the .cir netlist file.

Figure 2. Creating a SLiCAP instruction instance and connecting it to the .cir netlist file.

 

Remember that we’re interested in designing the source-to-load transfer function G(s) in such a way that the DC voltage gain is Av = 20 and the bandwidth fBW = 500 kHz. We therefore want to obtain symbolic design equations. Accordingly, we set the simulation type to symbolic. Since these need to be Laplace-domain transfer functions, we also set the data type to Laplace.

The source voltage and the load (detector) voltage need to be defined as well. We also want to use the asymptotic gain model as a design method, which requires us to define a loop gain reference variable. This will be the voltage-controlled voltage source of the op amp model that is used as the controller.

All of the above instruction attributes are coded and shown in Figure 3.

 

Python code snippet showing the SLiCAP instruction attributes.

Figure 3. [Click to enlarge] Coding the SLiCAP instruction attributes in Python and executing the instructions.

 

We have one last step to complete before executing the instruction—namely, defining the gain type. Recall from the previous section that there’s a relationship between the source-to-load transfer, the asymptotic gain, and the servo gain. Furthermore, the servo gain depends on the loop gain. This is why, in Figure 3, we execute the instruction once for every gain type.

 

Designing With SLiCAP Output

Now that we’ve run the simulation, we can use the results to facilitate our design process. Figure 4 shows part of the HTML report generated by running the Python script.

 

Snippet of HTML report showing the transfer functions for the different gain types.

Figure 4. Snippet of the generated HTML report showing the voltage amplifier transfer functions for the different gain types.

 

As expected, the asymptotic gain (A) depends only on the resistive feedback ratio. Because of the voltage gain requirement (Av = 20), this ratio is already fixed.

The loop gain, on the other hand, behaves as an integrator with unity-gain frequency equal to the product of GB and the resistive feedback ratio. As we can also observe from the output in Figure 4, the unity-gain frequency of the loop gain will determine the bandwidth of the servo function, S(s), and the source-to-load transfer, G(s).

These observations lay the foundation for our design. Because the resistive ratio is already fixed by the Av requirement, it’s clear that bandwidth of the circuit can only be designed by changing the gain-bandwidth product of the selected op amp.

Next, let’s use Python as a calculator to finalize our design. Figure 5 shows the HTML output produced when we use the design equations to size the resistors so that Av = 20.

 

Snippet of the HTML report showing the calculation of R1 based on the voltage gain requirement.

Figure 5. Snippet of the generated HTML report showing the calculation of R1 based on the Av requirement.

 

Based on this resistive divider ratio, we have one degree of freedom in choosing R1 and R2. In this situation, we choose R1 and calculate R2 from the given formula. In general, we would add noise and power dissipation requirements that limit the design freedom, but these are beyond the scope of this simple example.

Finally, Figure 6 shows the HTML output for determining the minimum gain-bandwidth product of the op amp.

 

Snippet of the HTML report showing the calculation of the minimum gain-bandwidth product for the bandwidth requirement.

Figure 6. Snippet of the generated HTML report showing the calculation of the minimum GB for the bandwidth requirement.

 

As an aside, you may have noticed something called the “loop gain-poles product” in the figure above. While we won’t discuss it in this article, the concept (and importance)of the loop gain-poles product is thoroughly explained in Chapter 11 of the textbook I mentioned earlier.

 

Design Verification in SLiCAP

Our original design goal—properly sizing R1, R2, and GB—has now been reached. However, we still need to verify that these three parameters meet the performance requirements. To do so, we run a numeric simulation in SLiCAP with the selected parameter values. The SLiCAP Python package will then create Bode plots for the different gain types we’ve been examining:

  • Asymptotic gain.
  • Loop gain.
  • Servo gain.
  • Source-to-load transfer (denoted simply as gain).

Figures 7 and 8 show the magnitude and phase Bode plots, respectively.

 

Magnitude Bode plot generated by SLiCAP.

Figure 7. Magnitude Bode plot generated by SLiCAP for R1 = 190 kΩ, R2 = 10 kΩ, GB = 10 MHz.

 

Phase Bode plot generated by SLiCAP.

Figure 8. Phase Bode plot generated by SLiCAP for R1 = 190 kΩ, R2 = 10 kΩ, GB = 10 MHz.

 

The source-to-load transfer has a DC magnitude of Av = 20 (which is equal to about 26 dB) and a bandwidth fBW = 500 kHz, meaning that the requirements were met. The other gain types correspond to the Laplace transfer functions that we found earlier. The first-order decay of G(s) and S(s) beyond the bandwidth comes from the first-order integrator in the loop gain, which itself originates from the voltage gain of the op amp.

 

Wrapping Up

The models we used in this article are very simple, probably too much so to accurately represent a real application. A more realistic example circuit might have included any or all of the following:

  • Load impedance.
  • Source impedance.
  • Op amp input and output impedance.
  • Additional poles and zeros in the op amp voltage gain.

During the first part of the design process, the trick is to understand the model components that introduce dominant poles and/or zeros in the loop gain. This should return limited-order loop gain transfer functions, helping to ensure that pole-zero placement meets the bandwidth requirements. We can add complexity later on, in a numeric simulation, to verify the complete circuit.

Despite its simplicity, our design example accurately reflects SLiCAP’s structured design philosophy. On a more practical level, it demonstrates that SLiCAP is capable of presenting equations that aid in component selection, verifying the circuit, and documenting the process, all in a fairly short amount of time. All in all, SLiCAP provides an excellent opportunity for analog electronics engineers to speed up and automate some of their amplifier designs.

 

All images used courtesy of Gilles Ackaert