Source code for spicelib.log.semi_dev_op_reader

#!/usr/bin/env python

# -------------------------------------------------------------------------------
#
#  ███████╗██████╗ ██╗ ██████╗███████╗██╗     ██╗██████╗
#  ██╔════╝██╔══██╗██║██╔════╝██╔════╝██║     ██║██╔══██╗
#  ███████╗██████╔╝██║██║     █████╗  ██║     ██║██████╔╝
#  ╚════██║██╔═══╝ ██║██║     ██╔══╝  ██║     ██║██╔══██╗
#  ███████║██║     ██║╚██████╗███████╗███████╗██║██████╔╝
#  ╚══════╝╚═╝     ╚═╝ ╚═════╝╚══════╝╚══════╝╚═╝╚═════╝
#
# Name:        SemiDevOpReader.py
# Purpose:     Read Semiconductor Device Operating Points from a log file
#
# Author:      Nuno Brum (nuno.brum@gmail.com)
#
# Created:     19-09-2021
# License:     refer to the LICENSE file
# -------------------------------------------------------------------------------

"""
Implements a parser for extracting Semiconductor Devices Operating Points from an LTSpice log file.
"""

import re
from ..utils.detect_encoding import detect_encoding


[docs] def opLogReader(filename: str) -> dict: """ This function is exclusively dedicated to retrieving operation point parameters of Semiconductor Devices. This is handled separately from the main LogReader class because of its specialization and therefore not judged to be of interest to the typical LTSpice user making board level simulations. Below is an excerpt of a Semiconductor Device Operating Points log: .. code-block:: text Semiconductor Device Operating Points: --- Diodes --- Name: d:m6:1:para2:1 d:m4:1:para2:1 d:m3:1:para2:1 d:m6:1:para1:2 Model: m6:1:para2:dpar_5v_psubnburd m4:1:para2:dpar_5v_psubnburd m3:1:para2:dpar_5v_psubnburd dpar_pburdnburdsw Id: 3.45e-19 3.45e-19 3.45e-19 1.11e-13 Vd: 3.27e-07 3.27e-07 3.27e-07 9.27e-02 ... CAP: 3.15e-14 3.15e-14 3.15e-14 5.20e-14 --- Bipolar Transistors --- Name: q:q2:1:2 q:q2:1:1 q:q1:1:2 q:q1:1:1 q:q7:3 Model: q2:1:qnl_pnp q2:1:qnl_m q1:1:qnl_pnp q1:1:qnl_m qpl_parc Ib: 3.94e-12 4.69e-08 7.43e-13 4.70e-08 3.75e-12 Ic: -2.34e-12 4.57e-06 -7.44e-13 4.50e-06 -2.35e-12 Vbe: 1.60e+00 7.40e-01 -7.88e-04 7.40e-01 1.40e+00 This function will parse the log file and will produce a dictionary that contains all the information retrieved with the following format: .. code-block:: python semi_ops = { 'Diodes': { 'd:m6:1:para2:1': { 'Model': 'm6:1:para2:dpar_5v_psubnburd', 'Id': 3.45e-19, 'Vd': 3.27e-07, ... 'CAP': 3.15e-14 }, 'd:m4:1:para2:1': { 'Model': 'm4:1:para2:dpar_5v_psubnburd', 'Id': 3.45e-19, 'Vd': 3.27e-07, ..., 'CAP': 3.15e-14 }, 'd:m3:1:para2:1': { 'Model': 'm3:1:para2:dpar_5v_psubnburd', 'Id': 3.45e-19, 'Vd': 3.27e-07, ..., 'CAP': 3.15e-14 }, 'd:m6:1:para1:2': { 'Model': 'dpar_pburdnburdsw', 'Id': 1.11e-13, 'Vd': 0.0927, ..., 'CAP': 5.2e-14 }, }, 'Bipolar Transistors': { 'q:q2:1:2': { 'Model': 'q2:1:qnl_pnp', 'Ib': 3.94e-12, 'Ic': -2.34e-12, 'Vbe': 160, ... }, 'q:q2:1:1': { 'Model': 'q2:1:qnl_m', 'Ib': 4.69e-08, 'Ic': 4.57e-06, 'Vbe': 0.074, ... }, 'q:q1:1:2': { 'Model': 'q1:1:qnl_pnp', 'Ib': 7.43e-13, 'Ic': -7.44e-13, 'Vbe': -0.000788, ... }, 'q:q1:1:1': { 'Model': 'q1:1:qnl_m', 'Ib': 4.7e-08, 'Ic': 4.5e-06, 'Vbe': 0.74, ... }, 'q:q7:3': { 'Model': 'qpl_parc', 'Ib': 3.75e-12, 'Ic': -2.35e-12, 'Vbe': 1.4, ... }, }, } :param filename: path to the log file containing the Semiconductor Device Operating Points :return: Dictionary containing the information as described above. """ dataset = {} is_title = re.compile(r"^\s*--- (.*) ---\s*$") encoding = detect_encoding(filename) log = open(filename, encoding=encoding) where = None n_devices = 0 line = None for line in log: if line.startswith("Semiconductor Device Operating Points:"): break if line is not None and line.startswith("Semiconductor Device Operating Points:"): for line in log: match = is_title.search(line) if match is not None: where = match.group(1) dataset[where.lower()] = {} # Creates a dictionary for each component type else: cols = re.split(r'\s+', line.rstrip('\r\n')) if len(cols) > 1 and (cols[0].endswith(":") or cols[0] == 'Gmb'): # The last 'or condition solves an # LTSpice bug where the Gmb parameter is not suffixed by : - Thanks to Amitkumar for finding this. if cols[0] == "Name:": devices = cols[1:] n_devices = len(devices) for dev in cols[1:]: dataset[where.lower()][dev] = {} else: if n_devices > 0 and len(cols) == (n_devices + 1): param = cols[0].rstrip(':') for i, val in enumerate(cols[1:]): try: value = float(val) except ValueError: value = val dataset[where.lower()][devices[i]][param] = value log.close() return dataset