nunobrum / spicelib Goto Github PK
View Code? Open in Web Editor NEWPython library to interact with spice simulators such as LTSpice, QSPICE, NGSpice and others.
License: GNU General Public License v3.0
Python library to interact with spice simulators such as LTSpice, QSPICE, NGSpice and others.
License: GNU General Public License v3.0
Currently sim_client allows only one circuit file to be sent to the server. However, some simulations consist of multiple files which are included/used in the main netlist. For example, models of transmission lines might be in another asc
file which is included into the main simulation file.
spicelib/spicelib/client_server/sim_client.py
Line 121 in ce7bb03
As a workaround, I copy paste the required circuits to HOME/temp directory of the server beforehand.
I suggest taking two parameters: circuit_dir, circuit_name
circuit_dir is the directory/folder which contains all required files including the main circuit. For example ./circuits.
circuit_name is the main circuit file. For example tran_sim.asc (which is at ./circuits/tran_sim.asc)
Then, server can just extract the files (circuits.zip) as usual and run the main circuit ./circuits/tran_sim.asc
Problem description:
(latest github version of spicelib)
Imagine a symbol with the following content in the .asc file:
SYMBOL OpAmps/opamp2 4288 -864 R0
SYMATTR InstName U1
SYMATTR Value OPAx189
that leads to the following info in the .net file:
XU1 N001 N002 +V -V N002 OPAx189
When calling
netlist = spicelib.SpiceEditor(netlistname)
netlist.set_component_value("XU1", "OPAx140")
that results in
XU1 N001 OPAx140 +V -V N002 OPAx189
instead of
XU1 N001 N002 +V -V N002 OPAx140
... as expected.
AscEditor works without problems.
Cause:
spicelib/editor/spce_editor.py:95
'X': r"^(?P<designator>X§?\w+)(?P<nodes>(\s+\S+){1,99}?)\s+(?P<value>\w+)"
r"(\s+params:)?" + PARAM_RGX + ".*$",
It is rather messy to do correctly, as X components can have any number of pins/nets.
TODO:
I'll create some test cases with and without parameters. Right now, X returns only 1 of the elements as value, and nothing as parameters. It should be possible to improve that.
ngspice is now better integrated with kicad, and is multi platform. This means that more people will likely be interested in better support for ngspice. I am planning to work on that. It will however be based on the work from PR #71 / Issue #69 .
Branch: ngspice-72
Is it possible to expose hard codded timeout duration for server jobs.
LTSpice treats all symbols case insensitive it seems, as we can have both
SYMBOL res 4912 -608 R90
SYMATTR InstName R2
....
SYMBOL Res 4208 -800 R90
SYMATTR InstName R3
in the .asc files. The asc_editor however fails on this, with
File "[redacted]/spicelib/spicelib/editor/asc_editor.py", line 249, in _get_symbol
raise FileNotFoundError(f"File {asy_filename} not found")
FileNotFoundError: File Res.asy not found
on R3, while searching for "Res.asy". While R2 works, as the file is named "res.asy".
This is on MacOS, but Linux will surely suffer from this as well, and maybe even Windows.
Will provide a PR.
See branch case-sensitivity-68
When trying to perform:
# Open the Spice Model, and creates the .net
netlist = SpiceEditor("myCircuit.asc")
as shown in the documentation I always get the error of:
EncodingDetectError: Expected string "*" not found in file:myCircuit.asc
I am coming from pyltspice and this was not a problem there. Is there something I am missing?
There is an incoherence between SpiceEditor and AscEditor:
SpiceEditor
handles all components of the values of a component as one value, and they can be set via set_component_value
.AscEditor
has properties "Value" and "Value2". The latter has no possibility to be set.Example: "V3 0 AC 2": that is a Voltage source of 0 volt, but with AC small signal analysis voltage of 2.
With SpiceEditor, the value of V3 = "V3 0 AC 2". If I do set_component_value({"V3":"0"})
, the AC part disappears.
With AscEditor, the value of V3 = "0", and Value2 = "AC 2". If I do set_component_value({"V3":"0"})
, the AC part remains intact, and there is no possibility to modify it.
Question:
AscEditor.set_component_value()
set all sections of a value, just like SpiceEditor.set_component_value()
?This log level is too high to my taste. It generates a lot of log lines, without much info when all is OK.
Would it be OK to lower that to DEBUG?
Hi.
I find there's another repository in GitHub that is similar to 'spicelib'.
I found its ideas interesting.
PySpice
A PPT illustrating its idea
The basic idea: in general, doing a spice simulation has three steps: 1. edit circuit; 2. run simulation; 3. data analysis.
The PySpice lets the user do the first and last steps in Python.
However, firstly, it can only support ngspice and xyce. The second reason I dislike it is that I have to learn its internally defined method to edit circuits rather than use general spice language. And the code complexity and bugs.
It's possible to learn from it and improve spicelib. Here are my suggestions:
(They may be wrong.)
but in ngspice and xyce, as I know, the user can directly create their circuit by writing codes. That is useful when simulating large circuits or doing version control.
I suggest providing a way for the user to create a blank circuit netlist and directly manipulate it. #3
Since you can read the asc file, is it possible to convert the asc into the net in Python? Each time I modified my asc circuit, I had to convert it to net manually.
Can the spicelib provide simulated data results in numpy array? It can convenience the data analysis and visualization for the user.
We can build more examples and documentation to show how to use numpy and matplotlib to do something more. (I may help)
Hi Nuno,
there is a small change with the latest LTspice update (24.0.0+). The log file now contains the version info in the first line and not "Circuit:" anymore. Changing line 304 in spicelib/log/ltsteps.py to "self.encoding = detect_encoding(log_filename, "LTspice")" and line 758 in spicelib/raw/raw_read.py to "encoding = detect_encoding(logfile, "LTspice")" solved the issue. Maybe you could update this in the next release. Thank you for this amazing project.
New:
LTspice 24.0.9 for Windows
Circuit: * RDSon_template.net
Start Time: Fri Feb 9 10:11:48 2024
solver = Normal
Maximum thread count: 8
tnom = 27
temp = 27
method = modified trap
rdson2v5: v(drain)/i(v0)=5.24717 at 2.5
rdson4v5: v(drain)/i(v0)=2.59594 at 4.5
rdson10v: v(drain)/i(v0)=2.20168 at 10
Total elapsed time: 0.113 seconds.
Old:
Circuit: * RDSon_template.net
rdson2v5: v(drain)/i(v0)=5.24717 at 2.5
rdson4v5: v(drain)/i(v0)=2.59594 at 4.5
rdson10v: v(drain)/i(v0)=2.20168 at 10
Date: Thu Feb 8 16:49:39 2024
Total elapsed time: 0.034 seconds.
tnom = 27
temp = 27
method = trap
totiter = 281
traniter = 0
tranpoints = 0
accept = 0
rejected = 0
matrix size = 21
fillins = 7
solver = Normal
Avg thread counts: 7.1/0.0/8.0/7.1
Matrix Compiler1: 1.37 KB object code size 0.3/0.3/[0.2]
Matrix Compiler2: off [0.2]/0.4/0.2
Hi,
I have a circuit that is a little complicated. When I ran ltspice to simulate it in multiple tasks, I found it may stuck like this:
Please take a look at the project in the attachment. To run it, replace the ltspice exe path first.
The key parameter is parallel_sim=4
in SimRunner
. The larger the value of it, the more possibility to reproduce the bug.
(I tried [1, 4, 16]. For '1', it can succeed to end; For '16', it stuck immediately.)
That may be caused by the waiting and lock mechanism in multithread running.
system: Windows 10 22H2
Ltspice version: 17.0.37.0 (Jul 20 2023)
Thanks.
example.zip
When setting set_component_value("R2","10k")
on a resistor that has "1G" as value, the value becomes "10kG".
On which LTSPice does not complain, but which leads to unexpected results.
Reason:
the various regex strings in spice_editor.py
have the following constructions:
[0-9\.E+-]+(Meg|[kmuµnpf]
(3 times)[0-9\.E+-]+[kmuµnpf]
(1 time)t and g are missing here, so that should become
[0-9\.E+-]+(Meg|[kmuµnpftg]
(3 times)[0-9\.E+-]+[kmuµnpftg]
(1 time)I tested that, and it works.
Also, base_editor.py
is missing support for T and G.
I can create a PR for that if you want. I will then also test more, as there might be more issues with the suffixes.
OK first of all this is not really a bug of spicelib or PyLTSpirce but I found some strange behaviour today.
I have 3 different PCs , all on Win10 64 bit, all of them run the very same python3 version (3.11.5) and on all of the PCs there is a virtual environment in which the latest version of PyLTspice and spicelib are installed via an pip requirements file (to really have the same setup everywhere). Also, on all the machines, the very same version of LTSpice is running, i.e. the currently latest 24.0.12.
I have a script that runs a very simple transistor simulation and then does some plotting of the results. On two of the machines everything runs file. On one machine, spicelib has trouble reading the raw file. this looks like this
Traceback (most recent call last):
File "C:\Users\myuser\printBjtQ1_modify_for_bjt_abs00.py", line 5, in <module>
LTR = RawRead("bjtQ1_1.raw")
File "C:\py311LTSpice\Lib\site-packages\spicelib\raw\raw_read.py", line 601, in __init__
self._load_step_information(raw_filename)
File "C:\py311LTSpice\Lib\site-packages\spicelib\raw\raw_read.py", line 758, in _load_step_information
encoding = detect_encoding(logfile, "^(.*\n)?Circuit:")
File "C:\py311LTSpice\Lib\site-packages\spicelib\utils\detect_encoding.py", line 77, in detect_encoding
raise EncodingDetectError(f"Expected pattern \"{expected_pattern}\" not found in file:{file_path}")
spicelib.utils.detect_encoding.EncodingDetectError: Expected pattern "^(.*
)?Circuit:" not found in file:bjtQ1_1.log
Now, after having a look, I found that the very same LTSpice Version run by the the very same python script produces a different .log file on the machine that raises the error
The log file that WORKS looks like
LTspice 24.0.12 for Windows
Circuit: * C:\filepath\bjtQ1.asc
Start Time: Fri Jul 26 15:37:19 2024
Warning: Multiple definitions of model "2scr375p" Type: BJT
Warning: Multiple definitions of model "bc857b" Type: BJT
Warning: Multiple definitions of model "bc847c" Type: BJT
Warning: Multiple definitions of model "bc847b" Type: BJT
solver = Normal
Maximum thread count: 8
tnom = 27
temp = 27
method = modified trap
.step ib=8e-06
.step ib=5e-05
.step ib=0.0001
.step ib=0.0002
Total elapsed time: 0.012 seconds.
The log file that RAISES THE ERROR in SPICELIB looks like
LTspice 24.0.12 for Windows
Start Time: Fri Jul 26 15:37:37 2024
Warning: Multiple definitions of model "2scr375p" Type: BJT
Warning: Multiple definitions of model "bc857b" Type: BJT
Warning: Multiple definitions of model "bc847c" Type: BJT
Warning: Multiple definitions of model "bc847b" Type: BJT
--- Expanded Deck Component Count ---
I's 1
Q's 1
V's 1
tot: 3
--- Expanded Netlist ---
* C:\filepath\bjtQ1.asc
q1 n001 n002 0 0 2n2222
ib 0 n002 10u
vce n001 0 1
.model 2n2222 npn(is=1e-14 vaf=100 bf=200 ikf=0.3 xtb=1.5 br=3 cjc=8e-12 cje=25e-12 tr=100e-9 tf=400e-12 itf=1 vtf=2 xtf=3 rb=10 rc=.3 re=.2 vceo=30 icrating=800m mfg=nxp)
.dc vce 0 2.5 10m ib list 8u 50u 100u 200u
.end
solver = Normal
Maximum thread count: 12
tnom = 27
temp = 27
method = modified trap
.step ib=8e-06
.step ib=5e-05
.step ib=0.0001
.step ib=0.0002
Total elapsed time: 0.009 seconds.
As one can see the "corrupted" .log file does not seem to mention the word "Ciruit" before the file path and it looks in general "different". I have no idea why the same version of LTSpice should behave differently on different PCs if the same script is called and the same circuit is simulated (I sync the files between machines in a shared directory so I can be sure the files are the same, I also diffed the .asc files, they are identical on all machines).
So really this would be a question for the LTSpice Forum but has anyone here seen something like this also?
Also: What about parsing for just the .asc ending in the log file? That would overcome that error I assume...
All editors should support a hierarchical design.
This is not supported in either ASC or QSCH and Spice has a not fully documented implementation.
... as the file encoding is UTF-16 LE, without BOM. As a result, you get a NotImplementedError exception in reset_netlist.
There is no easy way out, one needs to test if the file is "normal", and it not, open with utf16-LE encoding.
Another way is to test and rewrite the file. For that, I use the code below:
def check_and_correct_encoding(asc_file: str):
"""Needed with MacOS's LTSpice, as it writes .asc files with incomplete
encoding (utf-16-le without BOM). This function checks if the file has that
encoding, and if so, rewrites the file with a 'normal' encoding.
Args:
asc_file (str): File name of the .asc file
Raises:
FileNotFoundError: When the file is not found
NotImplementedError: When the encoding cannot be determined
"""
# test if file exists.
asc_file_path = Path(asc_file)
if not asc_file_path.exists():
raise FileNotFoundError(f"File {asc_file} not found")
# test if format detection works.
try:
with open(asc_file_path, 'r') as asc_file:
line = asc_file.readline().lower()
if line.startswith("version"):
return
except:
pass
# NOT. so test in utf16-LE
asc_file = open(asc_file_path, 'r', encoding='utf-16-le')
line = asc_file.readline().lower()
if line.startswith("version"):
# Yes, that works. So rewrite the file
# rewind to the start, read everything and close
asc_file.seek(0)
content = asc_file.read()
asc_file.close()
# now write the same content back to the file (overwriting the content)
with open(asc_file_path, 'w') as asc_file:
asc_file.write(content)
return
else:
asc_file.close()
raise NotImplementedError(f"Format not supported for ASC file {asc_file}")
It might be interesting to include that in spicelib or do automatic correction.
Appended a test file.
encodingtest.asc.zip
Right now, I see these search paths:
AscEditor._lib_file_find():
os.path.expanduser("~/AppData/Local/LTspice/lib/sub"),
os.path.expanduser("~/Documents/LtspiceXVII/lib/sub"),
os.path.expanduser("~/AppData/Local/Programs/ADI/LTspice/lib.zip"),
AscEditor._asy_file_find():
os.path.expanduser("~/AppData/Local/LTspice/lib/sym"),
os.path.expanduser("~/Documents/LtspiceXVII/lib/sym"),
SpiceCircuit.get_subcircuit():
os.path.join(os.path.expanduser('~'), "Documents/LTspiceXVII/lib/sub", lib)
asc_to_qsch.convert_asc_to_qsch():
os.path.expanduser("~/AppData/Local/LTspice/lib/sym"),
os.path.expanduser("~/Documents/LtspiceXVII/lib/sym"),
3 issues show up:
SpiceCircuit.add_library_search_paths()
or SpiceEditor.LibSearchPaths.append()
), or potentially worse: point to a potentially outdated MacOS version without complaining.~/AppData/Local/Programs/ADI/LTspice/lib.zip
, as that points to the default installation, not the updated files that are normally in one of the paths mentioned above.I propose to tweak these searches to base the search on where the simulator really is installed. Will provide a PR.
I've tried
netlist = SpiceEditor("example.net", encoding='utf-8')
on a simple netlist (example.net) that contains only this:
*
R1 N001 0 R
C1 N001 0 C
L1 N001 0 L
V1 N001 0 V
.BACKANNO
.END
I get this error:
raise UnrecognizedSyntaxError(line, regex.pattern) spicelib.editor.spice_editor.UnrecognizedSyntaxError: Line: "R1 N001 0 R " doesn't match regular expression "^(?P<designator>R§?\w+)(?P<nodes>(\s+\S+){2})(?P<model>\s+\w+)?\s+(R=)?(?P<value>(?P<formula>{)?(?(formula).*}|[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?(Meg|[kRmuµnpfgt])?\d*))(?P<params>(\s+\w+\s*(=\s*[\w\{\}\(\)\-\+\*\/%\.]+)?)*)?.*$"
Am I missing something obvious, or is this an actual issue? (the net file is encoded as UTF-8).
Am I running LT-SPice on Mac OSX natively
Hello again,
i wanted to tell you that there is a bug inside the tolerance_deviations.py. You might check it out.
self.log_data.stepset = {'run': [round(val.real) for val in self.log_data.dataset['run']]}
^^^^^^^^
AttributeError: 'str' object has no attribute 'real'
i tried by taking val as a float, but it seems that LTComplex classes cant be conversed to floats. Maybe you can check this out.
Best regards,
Dominik
Pretty simple one here:
Inside AscEditor.add_instruction
:
while i < len(self.directives):
directive = self.directives[i]
if directive.type == TextTypeEnum.COMMENT:
continue # this is a comment
should become
while i < len(self.directives):
directive = self.directives[i]
if directive.type == TextTypeEnum.COMMENT:
i += 1
continue # this is a comment
I could make a PR, but this is so simple....
Hello,
Im not sure if others experience the same issue however when i try to load a .asc file with spicelib i get a error: 'utf-8' codec can't decode byte 0xb5 in position 376: invalid start byte.
I tried to changed the asc_editor.py: reset_netlist encoding to unicode_escape (not sure why this one works) now the spicelib import runs and works atleast on the surface.
I attached a zip with a ltspcie file where i have the issue and a jupyter notebook of the issue and a few things i tried. (if that works)
I could not figure out the problem or why i am not able to import with utf-8. (the utf-8 is likely the root issue)
Any idea what the issue is? and if it is only me which experiences it with .asc files? (latest LTspice version as of 28.05.2024 incase it is related with the new 17 version of LTspice x64 24.0.12)
RawReader doesn't read QSPICE .AC simulation files.
For a Windows 10 VM running in QEMU/KVM, "localhost" ip/url is not reachable from the host machine.
However, If I pass an empty string, it works.
('', port),
I suggest adding an extra argument --url
which has localhost
as default if it is not specified.
Hi.
I'm editing my circuit using methods from the SpiceEditor
class (netlist_A
).
I need to add a subcircuit from a library, so I would like to call the find_subckt_in_lib()
method.
The problem is the return value of it is an instance of the SpiceCircuit
class (netlist_B
). So, the netlist_A and netlist_B are separated, and I have yet to find a method to build a connection between them. (Maybe simply appending netlist_B.netlist
into netlist_A.netlist
can work, but is it the recommended way?)
SpiceEditor
or SpiceCircuit
instance to receive SpiceCircuit
instances could be helpful.SpiceEditor
is the top-level netlist descriptor. The SpiceCircuit
can also nest other SpiceCircuit
.when an asy has a line like
LINE Normal -16 89 -16 96 2
spicelib\spicelib\editor\asy_reader.py:71
elif line.startswith("LINE"):
tag, weight, x1, y1, x2, y2 = line.split()
Exception has occurred: ValueError (note: full exception trace is shown but execution is paused at: _run_module_as_main)
too many values to unpack (expected 6)
File "...spicelib/spicelib/editor/asy_reader.py", line 72, in __init__
tag, weight, x1, y1, x2, y2 = line.split()
^^^^^^^^^^^^^^^^^^^^^^^^^^^
....
asc_editor handles this correctly. The same is likely to happen with rectangle, circle and arc.
Will provide a PR for this.
The Run Simulations multiprocessing example does not work for me.
When I call the line
runner.run(netlist, run_filename=run_netlist_file, callback=processing_data)
I get the error:
RunTask # 1:Simulation Raw file or Log file were not found
RunTask # 2:Simulation Raw file or Log file were not found
RunTask # 3:Simulation Raw file or Log file were not found
RunTask # 4:Simulation Raw file or Log file were not found
(Actually it produces errors with no space between # and the number, but I don't want to make links to pull requests.)
Running it without a run_filename
parameter works.
I have not yet figured out why it is not working when I run it with a run_filename
parameter. I think it should be creating raw and log files based on the run_netlist_file
parameter, but it appears to error out when it fails to find raw and log files. I expect the run function to create raw and log files, so the fact that it errors when it fails to find those raw and log files doesn't make sense to me.
With a Voltage source having a serial resistance, like
V1 NC_08 NC_09 2 AC 1 Rser=3
,
get_component_value => "2 AC 1 Rser=3"
get_component_parameters => crashes
I would expect the following:
get_component_value() => "2 AC 1"
get_component_parameters() => {"Rser": 3}
(for once, AscEditor does this correctly)
This is a regex issue in spice_editor, REPLACE_REGEXS['V']
The crash is another problem, easily solved, have done that in branch "Explanations-#46", see commit 4b81472.
Not being a regex expert,can you check commit d88eb7a ?
Hi,
I am running into an issue when using AscEditor.set_parameter().
I have a base .asc with already predefined parameters. When trying to modify this using the AscEditor.set_parameter() I do get two different results depending on the parameter being changed.
I have the parameter: .param T0 = 100u. Using asc.set_parameter('T0', 1/5000)
gets the following in the .asc: .param T0=100u 200u
I have the paremeter .param Ceq = 10p. asc.set_parameter('Ceq', 10e-12)
simply creates a new paremeter .param Ceq = 10p in a new line while keeping the original one and dus duplicating it.
...because
TEXT_REGEX = re.compile(r"TEXT (-?\d+)\s+(-?\d+)\s+(Left|Right|Top|Bottom)\s(\d+)\s*(?P<type>[!;])(?P<text>.*)",
re.IGNORECASE)
does not detect VLeft, VRight,...
Since the relevant code is undergoing movements (TEXT_REGEX is in asc_editor.py in the public version, but it got moved to ltspiceutils.py recently in the repo), and it looks like Work In Progress, I don't want to disturb that work.
But be aware that you are missing text orientation cases.
Hello,
i wanted to ask if this was done purposly.
When i start the Sallenkey.py Testcase for the WCA, the simulation starts and the terminal outputs Starting Simulation 1.
An empty LTSpice window opens and afterwards nothing happens.
When i close the LTSPice window, the output tells me the log files were not found etc.
But is this behaviour done on purpose? Do i need to manually click the run button on the .asc and so on?
This would defeat the purpose.
Im running spicelib 0.8 on ubuntu 22.04
Thanks and best regards,
Dominik
For example series resistance and parallel capacitance of a voltage source.
A workaround:
Open the asc file on LTSpice and manualy put the parameters in place of parasitic values {Rpar}
, {Vpar}
. Then set these parameters using set_parameter method.
After trying the same thing with your PyLTSpice library which you seem to be moving away from, I cannot get a file to run.
I will preface this with that I am a beginner when it comes to python, so while im doing my best to read and understand, I could be missing something obvious.
I am primarily trying to use https://spicelib.readthedocs.io/en/latest/modules/run_simulations.html, but
from spicelib import SimRunner, SpiceEditor, LTspice
does not work, seems like this is because you removed LTspice from __init__
here
chatGPT is trying to import ltspice_pytool when I ask it, but my understanding is that your library isnt built on that one. Am I mistaken there?
Thank you for your time!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.