From 4f36a1654ff6560c915a39e1f9999e0efc4a9680 Mon Sep 17 00:00:00 2001 From: Tanner Robison Date: Tue, 7 Jul 2026 20:48:28 -0700 Subject: SPICE model in the loop testing --- MIL_testing/integration_test.py | 14 +++++++++ MIL_testing/ng_test1.cir | 25 +++++++++++++++ MIL_testing/spice_backend.py | 70 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 MIL_testing/integration_test.py create mode 100644 MIL_testing/ng_test1.cir create mode 100644 MIL_testing/spice_backend.py (limited to 'MIL_testing') diff --git a/MIL_testing/integration_test.py b/MIL_testing/integration_test.py new file mode 100644 index 0000000..7c8e2fa --- /dev/null +++ b/MIL_testing/integration_test.py @@ -0,0 +1,14 @@ +import subprocess + +result = subprocess.run( + ["ngspice", "-b", "ng_test1.cir"], + capture_output=True, + text=True +) + +print("Return code:", result.returncode) +print(result.stdout) + +if result.stderr: + print("Errors:") + print(result.stderr) diff --git a/MIL_testing/ng_test1.cir b/MIL_testing/ng_test1.cir new file mode 100644 index 0000000..892a284 --- /dev/null +++ b/MIL_testing/ng_test1.cir @@ -0,0 +1,25 @@ +* RC Charging Circuit + +V1 in 0 PULSE(0 5 1u 1u 1u 100m 200m) + +R1 in out 1k + +C1 out 0 1u + +.tran 10u 50m + +.control +run + +set finalindex = $&{length(v(in)) - 1} + +let final_vin = v(in)[$finalindex] +let final_vout = v(out)[$finalindex] +let final_current = v1#branch[$finalindex] + +echo "----- final time analysis -----" +print final_vin final_vout +print final_current + +.endc +.end diff --git a/MIL_testing/spice_backend.py b/MIL_testing/spice_backend.py new file mode 100644 index 0000000..674ae30 --- /dev/null +++ b/MIL_testing/spice_backend.py @@ -0,0 +1,70 @@ +import subprocess +import re + +class SpiceBackend: + """This is what actually does all of the spice stuff""" + def __init__(self, device_file: str): + self.conductance = 0 + self.voltage = 0 + self.current = 0 + self.time = 0 + + def simulate(self, voltage_signal: float, return_current: bool = False) -> float: + """runs the simulation for one time step""" + len_voltage_signal = 1 + try: + len_voltage_signal = len(voltage_signal) + except: + voltage_signal = [voltage_signal] + + if return_current: + current = np.zeros(len_voltage_signal) + + for t in enumerate(len_voltage_signal): + result = self.run_spice(voltage_signal) + + single_current = result.current + self.conductance = result.conductance + + if return_current: + current[t] = single_current + + if return_current: + return current + + + def set_conductance(self, conductance: float): + """Handled by spice now""" + """Could probably still add some safety checks just to be sure later""" + self.conductance = conductance + + def run_spice(self, voltage: float) -> float: + """returns the current after given a voltage signal""" + #need to find a way to pass voltage signal to ngspice here + #also maybe a time series resolution?? + result = subprocess.run( + ["ngspice" "-b" "spicefile.cir"], + capture_output=True, + text=True + ) + if result.returncode != 0: + raise RuntimeError(result.stderr) + + # parse current into float variable + output = result.stdout + #is there a better (less rigid) way of grabbing the output + current_match = re.search("final_current = ([-\deE.+]+)", output) + if current_match is None: + raise RuntimeError("Could not find current in ngspice output") + + current = float(current_match.group(1)) + + if abs(voltage) > 1e-12: + conductance = current / voltage + else: + conductance = self.conductance + + return { + "current": current, + "conductance": conductance, + } -- cgit v1.2.3