Skip to content

Commit

Permalink
Merge branch 'main' into v1.3.3
Browse files Browse the repository at this point in the history
  • Loading branch information
nunobrum authored Jan 1, 2025
2 parents 3d83383 + a620d0b commit 0bede45
Show file tree
Hide file tree
Showing 12 changed files with 40 additions and 32 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,10 @@ runner = SimRunner(output_folder='./tmp',
AscEditor.prepare_for_simulator(MySpiceInstallation)

# You can also add your own library paths to the search paths
AscEditor.set_custom_library_paths(["/mypath/lib/sub",
"/mypath/lib/sym",
"/mypath/lib/sym/OpAmps",
"/mypath/lib/cmp"])
AscEditor.set_custom_library_paths("/mypath/lib/sub",
"/mypath/lib/sym",
"/mypath/lib/sym/OpAmps",
"/mypath/lib/cmp")

```

Expand Down Expand Up @@ -388,9 +388,9 @@ AscEditor has some limitations and differences in regard to SpiceEditor.
OpAmp. AscEditor will require `U1`.
* AscEditor and SpiceEditor only work with the information in their respective schema/circuit files. The problem is that LTspice does not store any of the underlying symbol's default parameter values in the .asc files. SpiceEditor works on netlists, and netlists do contain all parameters.

This can affect the behaviour when using symbols like `OpAmps/UniversalOpAmp2`. Although the LTspice GUI shows the parameters like `Avol`, `GBW` and `Vos`, even when they have the default values, `AscEditor.get_component_parameters()` will not return these parameters unless they have been modified. `SpiceEditor.get_component_parameters()` on the contrary will show all parameters, regardless of if they were modified. It is however possible for AscEditor to set or modify the parameters with `AscEditor.set_component_parameters()`. Example: `set_component_parameters("U1", Value2="Avol=2Meg GBW=10Meg Slew=10Meg")`.
This can affect the behaviour when using symbols like `OpAmps/UniversalOpAmp2`. Although the LTspice GUI shows the parameters like `Avol`, `GBW` and `Vos`, even when they have the default values, `AscEditor.get_component_parameters()` will not return these parameters unless they have been modified. `SpiceEditor.get_component_parameters()` on the contrary will show all parameters, regardless of if they were modified. It is however possible for AscEditor to set or modify the parameters with `AscEditor.set_component_parameters()`. Example: `set_component_parameters("U1", Value2="Avol=2Meg GBW=10Meg Slew=10Meg")`.

Note here that you must know the correct attribute holding that parameter, and make sure that you know and set all the other parameters in that attribute. If the attribute is in 'SpiceLine' however (as with the majority of the simpler components), you may address the parameter individually (see the voltage source example above).
Note here that you must know the correct attribute holding that parameter, and make sure that you know and set all the other parameters in that attribute. If the attribute is in 'SpiceLine' however (as with the majority of the simpler components), you may address the parameter individually (see the voltage source example above).

Resumed, it is better to use SpiceEditor than AscEditor, as it is more straightforward. On MacOS, it is recommended to use LTspice under wine, or to export the netlist manually, as MacOS's LTspice does not support automated export of netlists.

Expand Down
1 change: 1 addition & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
author = 'Nuno Brum'

# The full version, including alpha/beta/rc tags

release = '1.3.3'

try:
Expand Down
25 changes: 14 additions & 11 deletions examples/run_montecarlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@
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

# Finally the netlist is saved to a file. This file contians all the instructions to run the simulation in LTspice
mc.save_netlist('./testfiles/temp/sallenkey_mc.asc')
# -- End of Example 1 --

mc.run_testbench(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.obtain_amplitude_and_phase_from_complex_values() # Splits the complex values into real and imaginary parts
logs.export_data('./temp_mc/data_testbench.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
manually_simulating_in_LTspice = False

if manually_simulating_in_LTspice:
# Finally the netlist is saved to a file. This file contains all the instructions to run the simulation in LTspice
mc.save_netlist('./testfiles/temp/sallenkey_mc.asc')
# -- End of Example 1 --
else:
# Using the Toolkit to run the simulation.
mc.run_testbench(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.obtain_amplitude_and_phase_from_complex_values() # Splits the complex values into real and imaginary parts
logs.export_data('./temp_mc/data_testbench.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

print("=====================================")
a = input("Make 1000 simulations ? [Y/N]")
Expand All @@ -43,4 +47,3 @@
logs.export_data('./temp_mc/data_sims.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

2 changes: 1 addition & 1 deletion examples/sub_circuit_edits.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

E = SpiceEditor('testfiles/spice_edit_test.net')
print("Circuit Nodes", E.get_all_nodes())
E.set_custom_library_paths([r"C:\SVN\Electronic_Libraries\LTSpice\lib"])
E.set_custom_library_paths(r"C:\SVN\Electronic_Libraries\LTSpice\lib")
print("All components:\n", E.get_components())
print("Only resistors:\n", E.get_components('R'))
print("Components inside XX1:\n", E.get_subcircuit('XX1').get_components())
Expand Down
2 changes: 2 additions & 0 deletions spicelib/editor/asc_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ def reset_netlist(self, create_blank: bool = False) -> None:
if len(line_elements) == 11:
arc.line_style.pattern = line_elements[10]
self.shapes.append(arc)
elif line.startswith("DATAFLAG"):
pass # DATAFLAG is the placeholder to show simulation information. It is ignored by AscEditor
else:
raise NotImplementedError("Primitive not supported for ASC file\n"
f'"{line}"')
Expand Down
12 changes: 6 additions & 6 deletions spicelib/editor/base_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ def prepare_for_simulator(cls, simulator: Simulator) -> None:
return

@classmethod
def set_custom_library_paths(cls, paths: Union[str, List[str]]) -> None:
def set_custom_library_paths(cls, *paths) -> None:
"""
Set the given library search paths to the list of directories to search when needed.
It will delete any previous list of custom paths, but will not affect the default paths
Expand All @@ -845,16 +845,16 @@ def set_custom_library_paths(cls, paths: Union[str, List[str]]) -> None:
Note that this method is a class method and will affect all instances of the class.
:param paths: Path(s) to add to the Search path
:type paths: Union[str, List[str]]
:return: Nothing
"""
# empty the list
cls.custom_lib_paths = []
# and then fill it with the new paths
if isinstance(paths, str):
cls.custom_lib_paths.append(paths)
elif isinstance(paths, list):
cls.custom_lib_paths.extend(paths)
for path in paths:
if isinstance(path, str):
cls.custom_lib_paths.append(path)
elif isinstance(path, list):
cls.custom_lib_paths.extend(path)

def is_read_only(self) -> bool:
"""Check if the component can be edited. This is useful when the editor is used on non modifiable files.
Expand Down
4 changes: 2 additions & 2 deletions spicelib/editor/spice_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ def remove_component(self, designator: str) -> None:
self.netlist[line] = '' # Blanks the line

@staticmethod
def add_library_search_paths(paths: Union[str, List[str]]) -> None:
def add_library_search_paths(*paths) -> None:
"""
.. deprecated:: 1.1.4 Use the class method `set_custom_library_paths()` instead.
Expand All @@ -984,7 +984,7 @@ def add_library_search_paths(paths: Union[str, List[str]]) -> None:
:type paths: str
:return: Nothing
"""
SpiceCircuit.set_custom_library_paths(paths)
SpiceCircuit.set_custom_library_paths(*paths)

def get_all_nodes(self) -> List[str]:
"""
Expand Down
2 changes: 1 addition & 1 deletion spicelib/log/ltsteps.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def reformat_LTSpice_export(export_file: str, tabular_file: str):
go_header = True
run_no = 0 # Just to avoid warning, this is later overridden by the step information
param_values = "" # Just to avoid warning, this is later overridden by the step information
regx = re.compile(r"Step Information: ([\w=\d\. -]+) +\(Run: (\d*)/\d*\)\n")
regx = re.compile(r"Step Information: ([\w=\d\. \-]+) +\((?:Run|Step): (\d*)/\d*\)\n")
for line in fin:
if line.startswith("Step Information:"):
match = regx.match(line)
Expand Down
2 changes: 1 addition & 1 deletion spicelib/sim/sim_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def wait_completion(self, timeout=None, abort_all_on_timeout=False) -> bool:
...


class SimRunner(object):
class SimRunner(AnyRunner):
"""
The SimRunner class implements all the methods required for launching batches of Spice simulations.
Expand Down
2 changes: 2 additions & 0 deletions spicelib/sim/tookit/tolerance_deviations.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ def run_testbench(self, *,
super()._reset_netlist()
self.play_instructions()
self.prepare_testbench()
else:
self.play_instructions()
self.editor.remove_instruction(".step param run -1 %d 1" % self.last_run_number) # Needs to remove this instruction
self.clear_simulation_data()
# calculate the ideal number of runs per simulation to avoid orphan runs. This is to avoid having a simulation
Expand Down
6 changes: 3 additions & 3 deletions spicelib/sim/tookit/worst_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ def prepare_testbench(self, **kwargs):
if self._set_component_deviation(ref, index):
index += 1

self.editor.add_instruction(".func binary(run,idx) floor(run/(2**idx))-2*floor(run/(2**(idx+1)))")
self.editor.add_instruction(".func wc(nom,tol,idx) {nom*if(binary(run,idx),1-tol,1+tol)}")
self.editor.add_instruction(".func wc1(nom,min,max,idx) {nom*if(binary(run,idx),min,max)}")
self.editor.add_instruction(".func binary(run,idx) {floor(run/(2**idx))-2*floor(run/(2**(idx+1)))}")
self.editor.add_instruction(".func wc(nom,tol,idx) {if(run<0,nom,nom*(1+tol*(2*binary(run,idx)-1)))}")
self.editor.add_instruction(".func wc1(nom,min,max,idx) {if(run<0, nom, if(binary(run,idx),max,min))}")
self.last_run_number = 2**index - 1
self.editor.add_instruction(".step param run -1 %d 1" % self.last_run_number)
self.editor.set_parameter('run', -1) # in case the step is commented.
Expand Down
2 changes: 1 addition & 1 deletion spicelib/simulators/ltspice_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ def run(cls, netlist_file: Union[str, Path], cmd_line_switches: list = None, tim
if sys.platform == "linux" or sys.platform == "darwin":
if cls.using_macos_native_sim():
# native MacOS simulator, which has its limitations
if netlist_file.lower().endswith(".asc"):
if netlist_file.suffix.lower().endswith(".asc"):
raise NotImplementedError("MacOS native LTspice cannot run simulations on '.asc' files. Simulate '.net' or '.cir' files or use LTspice under wine.")

cmd_run = cls.spice_exe + ['-b'] + [netlist_file.as_posix()] + cmd_line_switches
Expand Down

0 comments on commit 0bede45

Please sign in to comment.