A set of tools to operate with QSPICE
Project description
PyQSPICE
QSPICE is a toolchain of python utilities design to interact specifically with QSPICE.
What is contained in this repository
-
raw_read.py A pure python class that serves to read raw files into a python class.
-
spice_editor.py and qsch_editor.py Scripts that can update spice netlists. The following methods are available to manipulate the component values, parameters as well as the simulation commands. These methods allow to update a netlist without having to open the schematic in Qspice. The simulations can then be run in batch mode (see sim_runner.py).
set_element_model('D1', '1N4148') # Replaces the Diode D1 with the model 1N4148
set_component_value('R2', '33k') # Replaces the value of R2 by 33k
set_parameters(run=1, TEMP=80) # Creates or updates the netlist to have .PARAM run=1 or .PARAM TEMP=80
add_instructions(".STEP run -1 1023 1", ".dc V1 -5 5")
remove_instruction(".STEP run -1 1023 1") # Removes previously added instruction
reset_netlist() # Resets all edits done to the netlist.
-
sim_runner.py A python script that can be used to run Qspice simulations in batch mode without having to open the Qspice GUI. This in cooperation with the classes defined in spice_editor.py or qsch_editor.py is useful because:
- Can overcome the limitation of only stepping 3 parameters
- Different types of simulations .TRAN .AC .NOISE can be run in a single batch
- The RAW Files are smaller and easier to treat
- When used with the RawRead.py and LTSteps.py, validation of the circuit can be done automatically.
- Different models can be simulated in a single batch, by using the following instructions:
Note: It was only tested with Windows based installations.
It is based on the spicelib library and therefore most documentation can be found there.
The major difference is that in this library all defaults point to the QSpice and the tools that are not pertaining to QSPICE are not mapped
How to Install
pip install qspice
Updating qspice
pip install --upgrade qspice
Requirements
- spicelib
How to use
Here follows a quick outlook on how to use each of the tools.
More comprehensive documentation can be found in https://spicelib.readthedocs.io/en/latest/ This is the base package on which this libray is based, however, not all functionalities are ported to this packages.
LICENSE
GNU V3 License (refer to the LICENSE file)
RawRead
The example below reads the data from a Spice Simulation called "TRAN - STEP.raw" and displays all steps of the "I(R1)" trace in a matplotlib plot
from qspice import RawRead
from matplotlib import pyplot as plt
rawfile = RawRead("TRAN - STEP.raw")
print(rawfile.get_trace_names())
print(rawfile.get_raw_property())
IR1 = rawfile.get_trace("I(R1)")
x = rawfile.get_trace('time') # Gets the time axis
steps = rawfile.get_steps()
for step in range(len(steps)):
# print(steps[step])
plt.plot(x.get_wave(step), IR1.get_wave(step), label=steps[step])
plt.legend() # order a legend
plt.show()
SpiceEditor, QschEditor and SimRunner.py
This module is used to launch Qspice simulations. Results then can be processed with either the RawRead or with the QspiceLogReader module to obtain .MEAS results.
The script will firstly invoke the Qspice in command line to generate a netlist, and then this netlist can be updated directly by the script, in order to change component values, parameters or simulation commands.
Here follows an example of operation.
from qspice import SimRunner, SpiceEditor, RawRead, sweep_log
def processing_data(raw_file, log_file):
print("Handling the simulation data of %s, log file %s" % (raw_file, log_file))
raw_data = RawRead(raw_file)
vout = raw_data.get_wave('V(out)')
return raw_file, vout.max()
# select spice model
sim = SimRunner(output_folder='./temp')
netlist = SpiceEditor('./testfiles/testfile.net')
# set default arguments
netlist.set_component_value('R1', '4k')
netlist.set_element_model('V1', "SINE(0 1 3k 0 0 0)") # Modifying the
netlist.add_instruction(".tran 1n 3m")
netlist.add_instruction(".plot V(out)")
netlist.add_instruction(".save all")
sim_no = 1
# .step dec param cap 1p 10u 1
for cap in sweep_log(1e-12, 10e-6, 10):
netlist.set_component_value('C1', cap)
sim.run(netlist, callback=processing_data, run_filename=f'testfile_qspice_{sim_no}.net')
sim_no += 1
# Reading the data
results = {}
for raw_file, vout_max in sim: # Iterate over the results of the callback function
results[raw_file.name] = vout_max
# The block above can be replaced by the following line
# results = {raw_file.name: vout_max for raw_file, vout_max in sim}
print(results)
# Sim Statistics
print('Successful/Total Simulations: ' + str(sim.okSim) + '/' + str(sim.runno))
input('Press Enter to delete simulation files...')
sim.file_cleanup()
The example above is using the SpiceEditor to create and modify a spice netlist, but it is also possible to use the QschEditor to directly modify the .qsch file. The edited .qsch file can then be opened by the Qspice GUI and the simulation can be run from there.
QschEditor
This module is used to create and modify Qspice schematics. The following methods are available to manipulate the component values, parameters as well as the simulation commands. These methods allow to update a schematic without having to open the Qspice GUI. The simulations can then be run in batch mode (see sim_runner.py).
The following example shows how to read a Qspice schematic, get the information about the components, change the value of a resistor, change the value of a parameter, add a simulation instruction and write the netlist to a file.
from qspice import QschEditor
audio_amp = QschEditor("./testfiles/AudioAmp.qsch")
print("All Components", audio_amp.get_components())
print("Capacitors", audio_amp.get_components('C'))
print("R1 info:", audio_amp.get_component_info('R1'))
print("R2 value:", audio_amp.get_component_value('R2'))
audio_amp.set_parameter('run', 1)
print(audio_amp.get_parameter('run'))
audio_amp.set_parameter('run', -1)
print(audio_amp.get_parameter('run'))
audio_amp.add_instruction('.tran 0 5m')
audio_amp.save_as("./testfiles/AudioAmp_rewritten.qsch")
audio_amp.save_netlist("./testfiles/AudioAmp_rewritten.net")
Simulation Analysis Toolkit
All the Analysis Toolkit classes are located in the spicelib.sim.toolkit package. The following classes are available:
- SensitivityAnalysis
- Montecarlo
- WorstCaseAnalysis
Please refer to the spicelib documentation for more information.
from qspice import SimRunner, QschEditor # Imports the class that manipulates the qsch file
from spicelib.sim.tookit.montecarlo import Montecarlo # Imports the Montecarlo toolkit class
sallenkey = QschEditor("./testfiles/AudioAmp.qsch") # Reads the qsch file into memory
runner = SimRunner(output_folder='./temp_mc') # Instantiates the runner with a temp folder set
mc = Montecarlo(sallenkey, runner) # Instantiates the Montecarlo class, with the qsch file already in memory
# The following lines set the default tolerances for the components
mc.set_tolerance('R', 0.01) # 1% tolerance, default distribution is uniform
mc.set_tolerance('C', 0.1, distribution='uniform') # 10% tolerance, explicit uniform distribution
mc.set_tolerance('V', 0, distribution='normal') # 10% tolerance, but using a normal distribution
# Some components can have a different tolerance
mc.set_tolerance('R1', 0.05) # 5% tolerance for R1 only. This only overrides the default tolerance for R1
mc.add_instruction('.func mc(x, tol) {x * (1 + tol * 2 * (random() - 0.5))}') # Creates the missing mc() function
# Tolerances can be set for parameters as well
# mc.set_parameter_deviation('Vos', 3e-4, 5e-3, 'uniform') # The keyword 'distribution' is optional
mc.prepare_testbench(num_runs=1000) # Prepares the testbench for 1000 simulations
mc.editor.save_as('./testfiles/AudioAmp_mc.qsch') # Saves the modified qsch file
# Finally the netlist is saved to a file
mc.save_netlist('./testfiles/AudioAmp_mc.net') # TODO: Implement the conversion to spice file
mc.run(max_runs_per_sim=100) # Runs the simulation with splits of 100 runs each
logs = mc.read_logfiles() # Reads the log files and stores the results in the results attribute
logs.export_data('./temp_mc/data.csv') # Exports the data to a csv file
logs.plot_histogram('fcut') # Plots the histograms for the results
mc.cleanup_files() # Deletes the temporary files
The following updates were made to the circuit:
- The value of each component was replaced by a function that generates a random value within the specified tolerance.
- The .step param run command was added to the netlist. Starts at -1 which it's the nominal value simulation, and finishes that the number of simulations specified in the prepare_testbench() method.
- A default value for the run parameter was added. This is useful if the .step param run is commented out.
- The R1 tolerance is different from the other resistors. This is because the tolerance was explicitly set for R1.
- The Vos parameter was added to the .param list. This is because the parameter was explicitly set using the set_parameter_deviation method.
- Functions utol, ntol and urng were added to the .func list. These functions are used to generate random values. Uniform distributions use the mc() function that is inspired on the approach for monte-carlo used in LTspice.
Similarly, the worst case analysis can also be setup by using the class WorstCaseAnalysis. Refer to spicelib for more information.
QspiceLogReader
This module defines a class that can be used to parse Qspice log files where the information about .STEP information is written. There are two possible usages of this module, either programmatically by importing the module and then accessing data through the class as exemplified here:
from qspice import QspiceLogReader
data = QspiceLogReader("Batch_Test_AD820_15.log")
print("Number of steps :", data.step_count)
step_names = data.get_step_vars()
meas_names = data.get_measure_names()
# Printing Headers
print(' '.join([f"{step:15s}" for step in step_names]), end='') # Print steps names with no new line
print(' '.join([f"{name:15s}" for name in meas_names]), end='\n')
# Printing data
for i in range(data.step_count):
print(' '.join([f"{data[step][i]:15}" for step in step_names]), end='') # Print steps names with no new line
print(' '.join([f"{data[name][i]:15}" for name in meas_names]), end='\n') # Print Header
print("Total number of measures found :", data.measure_count)
Other features (Toolkit, logging, etc..)
Refer to the spicelib documentation for more information.
To whom do I talk to?
- Tools website : https://www.nunobrum.com/pyltspice.html
- Repo owner : me@nunobrum.com
- Alternative contact : nuno.brum@gmail.com
History
- Version 0.2
- First operating version
- Version 0.1
- Reserving library name
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.