Examples

This wrapper lets us run any ADE-L simulation from Python. This enables us to run multiple algorithms, AI/ML models and optimization techniques native to Python by encapsulating the ADE-L simulation as a function call with a return value. The use cases are:

  • Running multiple simulations with different parameters

  • Storing the results of the simulation in a structured format or directly loading into Python variables/arrays

  • Run AI/ML algorithms by using the simulation as just an objective function in Python

  • Allows for the use of various Python libraries for data analysis and visualization on the simulation results

  • This wrapper allows us to run simulations in jupyter notebooks and other Python environments

The following examples demonstrate how to use the PyCadence wrapper to run simulations from Python.

Example 1: Running a Monte Carlo simulation

Consider a simple setup for a Monte Carlo simulation observing the phasenoise of a LC tank oscillator. The template ocn file generated is as follows.

 simulator( 'spectre )
    design(	 "/home/ABC/simulation/lc_tank_oscillator/spectre/schematic/netlist/netlist")
    resultsDir( "/home/ABC/simulation/lc_tank_oscillator/spectre/schematic" )
    modelFile( 
        'Some model files
    )
    analysis('pss ?fund "2.4G"  ?harms "5"  ?errpreset "conservative"  
            ?oscana t  ?p "/net017"  ?n "/net3"  ?oscic "lin"  
            ?ppv ""  )
    analysis('pnoise ?relharmnum "1"  ?start "10"  ?stop "1M"  
            ?p "/net017"  ?n "/net3"  ?oprobe ""  ?noisetype "timeaverage"  
            ?noiseout list("usb")  ?noisetypeUI ""  ?osc_version ""  ?osc_accuracy ""  
            ?ppv ""  )
    desVar(	  "C" {value}p	)  # {value} is the placeholder for the value to be substituted
    desVar(	  "L" {value}n	)
    desVar(	  "W1" {value}u	)
    desVar(	  "W2" {value}u	)
    desVar(	  "W3" {value}u	)
    desVar(	  "W4" {value}u	)
    desVar(	  "W5" {value}u	)
    envOption(
        'analysisOrder  list("pss" "pnoise") 
    )
    temp( 27 )
    run()
    phsns = db20((getData("out" ?resultsDir "/home/joelthomas/simulation/lc_tank_oscillator/spectre/schematic" ?result "pnoise") / complex(0.000279621 -0.000983934)))
    ocnPrint( ?output {output_log_path} phsns ?numSpaces 1 ?numberNotation 'scientific) # {output_log_path} is the placeholder to be used. It will automtically insert the 'output_file' argument passed in th simulate() function.

The following Python code demonstrates how to run the simulation using the PyCadence wrapper. Note: it is just an example implementation.

from pycadence.pycadence import Connector
import numpy as np

p = Connector(screen_name="session1")

def generate_monte_carlo_samples( N, X):
    '''
    Function to generate monte carlo samples
    --------------------------------
    N: int
        number of samples to generate
    X: list
        list of default values of design variables
    '''
    lower_bound = X - 0.1*X
    upper_bound = X + 0.1*X

    samples=[]
    for i in range(len(lower_bound)):
        samples.append(np.random.uniform(lower_bound[i],upper_bound[i],N))  # Assumed variance of 10% of the mean
    samples=np.array(samples)
    return samples.T

def outputReader(output_log_path):
    '''
    Helper function to parse the output file and return the data. Customize this as per need with reference to the output file format.
    The default implementation can be found Connector().read_output()
    --------------------------------
    output_log_path: str
        path to the output file
    '''
    with open(output_log_path, 'r+') as fp:
        # read an store all lines into list
        lines = fp.readlines()
        data=[]
        for line in lines[2:]:
            try:
                temp = line.strip().split(" ")
                # print(temp)
                data.append([float(temp[0]),float(temp[-1])])
            except Exception as e:
                # print("Error in reading output file")
                # print(e)
                pass
        data = np.array(data)
    return data

def objective_function(x):
    '''
    Objective function to be optimized
    --------------------------------
    x: list
        list of values to be passed to the simulation
    '''
    default = [0.1, 0.1, 0.1, 0.1, 0.1] # some default values

    data = p.simulate(x,default, "init.ocn", "monte_simulation.ocn", "output.txt", read_output = outputReader)
    return data[54][1] # I am only interested in the 55th data point not the whole series. Note: This is just an example


if __name__ == "__main__":
    N = 1000 # number of samples
    X = [0.1, 0.1, 0.1, 0.1, 0.1] # default values of design variables
    samples = generate_monte_carlo_samples(N, X)
    evaluations = []
    for sample in samples:
        evaluations.append(objective_function(sample))
    evaluations = np.array(evaluations)
    print(evaluations)
    print("Mean: ", np.mean(evaluations))
    print("Variance: ", np.var(evaluations))
    print("Standard Deviation: ", np.std(evaluations))
    print("Max: ", np.max(evaluations))
    print("Min: ", np.min(evaluations))