Source code for PyLTSpice.sim.ltspice_simulator

#!/usr/bin/env python
# coding=utf-8

# -------------------------------------------------------------------------------
#    ____        _   _____ ____        _
#   |  _ \ _   _| | |_   _/ ___| _ __ (_) ___ ___
#   | |_) | | | | |   | | \___ \| '_ \| |/ __/ _ \
#   |  __/| |_| | |___| |  ___) | |_) | | (_|  __/
#   |_|    \__, |_____|_| |____/| .__/|_|\___\___|
#          |___/                |_|
#
# Name:        ltspice_simulator.py
# Purpose:     Represents a LTspice tool and it's command line options
#
# Author:      Nuno Brum (nuno.brum@gmail.com)
#
# Created:     23-12-2016
# Licence:     refer to the LICENSE file
# -------------------------------------------------------------------------------
import sys
import os

from pathlib import Path
from typing import Union
import logging
_logger = logging.getLogger("PyLTSpice.LTSpiceSimulator")

from .simulator import Simulator, run_function


[docs]class LTspice(Simulator): """Stores the simulator location and command line options and is responsible for generating netlists and running simulations.""" """Searches on the any usual locations for a simulator""" if sys.platform == "linux": spice_folder = os.environ.get("LTSPICEFOLDER") spice_executable = os.environ.get("LTSPICEEXECUTABLE") if spice_folder and spice_executable: spice_exe = ["wine", os.path.join(spice_folder, spice_executable)] process_name = spice_executable elif spice_folder: spice_exe = ["wine", os.path.join(spice_folder, "/XVIIx64.exe")] process_name = "XVIIx64.exe" elif spice_executable: default_folder = os.path.expanduser( "~/.wine/drive_c/Program Files/LTC/LTspiceXVII" ) spice_exe = ["wine", os.path.join(default_folder, spice_executable)] process_name = spice_executable else: default_folder = os.path.expanduser( "~/.wine/drive_c/Program Files/LTC/LTspiceXVII" ) spice_exe = ["wine", os.path.join(default_folder, "XVIIx64.exe")] process_name = "XVIIx64.exe" elif sys.platform == "darwin": spice_exe = ['/Applications/LTspice.app/Contents/MacOS/LTspice'] process_name = "XVIIx64" else: # Windows for exe in ( # Placed in order of preference. The first to be found will be used. os.path.expanduser(r"~\AppData\Local\Programs\ADI\LTspice\LTspice.exe"), r"C:\Program Files\ADI\LTspice\LTspice.exe", r"C:\Program Files\LTC\LTspiceXVII\XVIIx64.exe", r"C:\Program Files (x86)\LTC\LTspiceIV\scad3.exe", # Legacy LTspice IV ): if os.path.exists(exe): _logger.debug(f"Using LTspice installed in : '{exe}' ") spice_exe = [exe] break else: spice_exe = [] _logger.error("================== ALERT! ====================") _logger.error("Unable to find a LTSpice executable.") _logger.error("A specific location of the LTSPICE can be set") _logger.error("using the create_from(<location>) class method") _logger.error("==============================================") process_name = "XVIIx64.exe" ltspice_args = { 'alt' : ['-alt'], # Set solver to Alternate. 'ascii' : ['-ascii'], # Use ASCII.raw files. Seriously degrades program performance. # 'batch': ['-b <path>'], # Used by run command: Run in batch mode.E.g. "ltspice.exe-b deck.cir" will leave the data infile deck.raw 'big' : ['-big'], # Start as a maximized window. 'encrypt' : ['-encrypt'], # Encrypt a model library.For 3rd parties wishing to allow people to use libraries without # revealing implementation details. Not used by AnalogDevices models. 'fastaccess': ['-FastAccess'], # Batch conversion of a binary.rawfile to Fast Access format. 'FixUpSchematicFonts': ['-FixUpSchematicFonts'], # Convert the font size field of very old user - authored schematic text to the modern default. 'FixUpSymbolFonts': ['-FixUpSymbolFonts'], # Convert the font size field of very old user - authored symbols to the modern default. # See Changelog.txt for application hints. 'ini' : ['- ini', '<path>'], # Specify an .ini file to use other than %APPDATA%\LTspice.ini 'I' : ['-I<path>'], # Specify a path to insert in the symbol and file search paths. # Must be the last specified option. # No space between "-I" and < path > is allowed. 'max' : ['-max'], # Synonym for -big 'netlist' : ['-netlist'], # Batch conversion of a schematic to a netlist. 'norm' : ['-norm'], # Set solver to Normal. 'PCBnetlist': ['-PCBnetlist'], # Batch conversion of a schematic to a PCB format netlist. #'run' : ['-Run', '-b', '{path}'], # Start simulating the schematic opened on the command line without # # pressing the Run button. 'SOI' : ['-SOI'], # Allow MOSFET's to have up to 7 nodes even in subcircuit expansion. 'sync' : ['-sync'], # Update component libraries 'uninstall' : ['-uninstall'], # Please don't. Executes one step of the uninstallation process. }
[docs] @classmethod def valid_switch(cls, switch, path='') -> list: """ Validates a command line switch. The following options are available for LTSpice: * 'alt' : Set solver to Alternate. * 'ascii' : Use ASCII.raw files. Seriously degrades program performance. * 'encrypt' : Encrypt a model library.For 3rd parties wishing to allow people to use libraries without revealing implementation details. Not used by AnalogDevices models. * 'fastaccess': Batch conversion of a binary.rawfile to Fast Access format. * 'FixUpSchematicFonts' : Convert the font size field of very old user - authored schematic text to the modern default. * 'FixUpSymbolFonts' : Convert the font size field of very old user - authored symbols to the modern default. See Changelog.txt for application hints. * 'ini <path>' : Specify an .ini file to use other than %APPDATA%\LTspice.ini * 'I<path>' : Specify a path to insert in the symbol and file search paths. Must be the last specified option. * 'netlist' : Batch conversion of a schematic to a netlist. * 'normal' : Set solver to Normal. * 'PCBnetlist': Batch conversion of a schematic to a PCB format netlist. * 'SOI' : Allow MOSFET's to have up to 7 nodes even in subcircuit expansion. * 'sync' : Update component libraries * 'uninstall' : Executes one step of the uninstallation process. Please don't. :param switch: switch to be added. If the switch is not on the list above, it should be correctly formatted with the preceding '-' switch :type switch: str :param path: path to the file related to the switch being given. :type path: str, optional :return: Nothing :rtype: None """ if switch in cls.ltspice_args: switches = cls.ltspice_args[switch] switches = [switch.replace('<path>', path) for switch in switches] return switches else: raise ValueError("Invalid switch for class ")
[docs] @classmethod def run(cls, netlist_file, cmd_line_switches, timeout): if sys.platform == 'darwin': cmd_run = cls.spice_exe + ['-b'] + [netlist_file] + cmd_line_switches else: cmd_run = cls.spice_exe + ['-Run'] + ['-b'] + [netlist_file] + cmd_line_switches # start execution return run_function(cmd_run, timeout=timeout)
[docs] @classmethod def create_netlist(cls, circuit_file: Union[str, Path]) -> Path: # prepare instructions, two stages used to enable edits on the netlist w/o open GUI # see: https://www.mikrocontroller.net/topic/480647?goto=5965300#5965300 circuit_file = Path(circuit_file) if sys.platform == 'darwin': NotImplementedError("In this platform LTSpice doesn't have netlist generation capabilities") cmd_netlist = cls.spice_exe + ['-netlist'] + [circuit_file.as_posix()] + cmd_line_switches # print(f'Creating netlist file from "{circuit_file}"', end='...') error = run_function(cmd_netlist) if error == 0: netlist = circuit_file.with_suffix('.net') if netlist.exists(): _logger.debug("OK") return netlist msg = "Failed to create netlist" # print(msg) _logger.error(msg) raise RuntimeError(msg)