Create, Simulate, and Plot

This example will create a new workspace in your HOME directory called “create_simulate_plot_example”. In the workspace a new library and schematic are created and populate with an RC filter. Next, the circuit will be simulated and finally the response from the filter will be plotted inline in the ADS Python console.

../../../_images/low_pass_filter_var.png
# Copyright Keysight Technologies 2023 - 2023
import os
from pathlib import Path

import keysight.ads.de as de
from keysight.ads.de import db_uu as db


def create_workspace_and_design_then_simulate_and_plot() -> None:
    home_dir = os.environ["HOME"]
    workspace_path = os.path.join(home_dir, "create_simulate_plot_example")

    # ensure to start from a closed workspace
    if de.workspace_is_open():
        de.close_workspace()

    # create the workspace
    workspace = de.create_workspace(workspace_path)
    workspace.open()

    create_design_then_simulate_and_plot(workspace)


def create_design_then_simulate_and_plot(workspace: de.Workspace) -> None:
    from keysight.edatoolbox import util

    target_output_dir = os.path.join(workspace.path, "output")

    # create the simulation output directory
    util.safe_makedirs(target_output_dir)

    lib_dir = os.path.join(workspace.path, "low_pass_filter_lib")
    de.create_new_library("low_pass_filter_lib", lib_dir)
    workspace.add_library("low_pass_filter_lib", lib_dir, de.LibraryMode.NON_SHARED)

    # create the schematic
    design = db.create_schematic("low_pass_filter_lib:cell:schematic")

    # add components to the schematic
    design.add_instance(("ads_sources", "V_AC", "symbol"), (-2, 0), name="SRC1", angle=-90)

    r = design.add_instance(("ads_rflib", "R", "symbol"), (0, 0), name="R1", angle=0)
    r.parameters["R"].value = "3.0 kOhm"

    c = design.add_instance(("ads_rflib", "C", "symbol"), (2, 0), name="C1", angle=-90)
    c.parameters["C"].value = "1.0 uF"

    design.add_instance(("ads_rflib", "GROUND", "symbol"), (-2, -1), angle=-90)
    design.add_instance(("ads_rflib", "GROUND", "symbol"), (2, -1), angle=-90)

    design.add_wire([(-2.0, 0.0), (0.0, 0.0)])
    wire = design.add_wire([(1.0, 0.0), (2.0, 0.0)])
    wire.add_wire_label("R1_v")

    ac = design.add_instance(("ads_simulation", "AC", "symbol"), (-4, 1), name="AC1", angle=0)

    ac.parameters["Start"].value = "1.0 Hz"
    ac.parameters["Stop"].value = "1.0 MHz"
    ac.parameters["Dec"].value = "5"
    ac.parameters["Step"].value = ""

    v = design.add_instance(("ads_datacmps", "VAR", "symbol"), (0, 2), name="VAR1", angle=-90)
    assert v.is_var_instance
    v.vars["X"] = "1.0"
    v.vars["Y"] = "X/2.0"
    design.save_design()

    # data plot cannot be run in automation mode
    if de.is_pde_app():
        simulate_and_plot(design, target_output_dir)


# plot() not testable in automation mode
def simulate_and_plot(design: db.Design, output_dir: str) -> None:
    import os

    # use the dataset module to grab the output
    import keysight.ads.dataset as dataset
    from IPython.core import getipython
    from keysight.edatoolbox import ads

    ipython = getipython.get_ipython()
    if ipython is None:
        print("The remaining portion of the script must be run in an IPython environment. Exiting.")
        return

    # capture the netlist in a string
    netlist = design.generate_netlist()

    # access to the simulator object to run netlists
    simulator = ads.CircuitSimulator()

    # run the netlist, this will block output
    simulator.run_netlist(netlist, output_dir=output_dir)

    output_data = dataset.open(Path(os.path.join(output_dir, "cell.ds")))

    # switch to a dataframe representation
    # reset the index to normalize the data
    dataf = output_data["AC1.AC"].to_dataframe().reset_index()

    # plot using matplotlib/seaborn
    import matplotlib.pyplot as plt

    # plot using inline
    ipython.run_line_magic("matplotlib", "inline")  # type: ignore

    # make sure we plot the magnitude
    import numpy as np

    def dB(x) -> float:  # noqa: ANN001
        return 10.0 * np.log10(abs(x))

    _, ax = plt.subplots()
    ax.set_xscale("log")  # type: ignore
    ax.set_title("Filter response")  # type: ignore
    plt.plot(dataf["freq"], dB(dataf["R1_v"]))

    # alternatively show as dedicated window
    # plt.show()
On this page