From 80e9b79bbaf876529f53b10bc750194e95f21215 Mon Sep 17 00:00:00 2001 From: Marcus Mellor Date: Wed, 21 Jun 2023 11:22:13 -0500 Subject: [PATCH 1/4] Display all measurement lines in results --- PySpice/Spice/NgSpice/Shared.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index 183c08a4..817f28f0 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -1189,13 +1189,25 @@ def run(self, background=False): # in the background thread and wait until the simulation is done command = 'bg_run' if background else 'run' - self.exec_command(command) + results = self.exec_command(command) if background: self._is_running = True else: self._logger.debug("Simulation is done") + # Parse out measurement results + results = results if isinstance(results, list) else results.splitlines() + for line in results: + if line.startswith('Measurements'): + meas_start_index = results.index(line) + 1 + elif meas_start_index and '=' in line: + meas_end_index = results.index(line) + if meas_end_index: + for line in results[meas_start_index:meas_end_index]: + # Extract each measurement result as a k,v pair + print(line) + # time.sleep(.1) # required before to test if the simulation is running # while (self._ngspice_shared.ngSpice_running()): # time.sleep(.1) From 99330e79d3111625e99916a59db9391b93613944 Mon Sep 17 00:00:00 2001 From: Marcus Mellor Date: Wed, 21 Jun 2023 11:27:11 -0500 Subject: [PATCH 2/4] Fix invalid use of index vars --- PySpice/Spice/NgSpice/Shared.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index 817f28f0..fdb17f19 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -1198,12 +1198,14 @@ def run(self, background=False): # Parse out measurement results results = results if isinstance(results, list) else results.splitlines() + meas_start_index = 0 + meas_end_index = 0 for line in results: if line.startswith('Measurements'): meas_start_index = results.index(line) + 1 elif meas_start_index and '=' in line: meas_end_index = results.index(line) - if meas_end_index: + if meas_start_index and meas_end_index: for line in results[meas_start_index:meas_end_index]: # Extract each measurement result as a k,v pair print(line) From 75b65d9fb50c75e82eaf3fe63dc4b7ec4cdf87f4 Mon Sep 17 00:00:00 2001 From: Marcus Mellor Date: Wed, 21 Jun 2023 12:08:22 -0500 Subject: [PATCH 3/4] Pass measurements through to Analysis object --- PySpice/Probe/WaveForm.py | 12 ++++++++++-- PySpice/Spice/NgSpice/Shared.py | 30 +++++++++++++++++------------ PySpice/Spice/NgSpice/Simulation.py | 4 ++-- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/PySpice/Probe/WaveForm.py b/PySpice/Probe/WaveForm.py index ca92d15f..072e84a7 100644 --- a/PySpice/Probe/WaveForm.py +++ b/PySpice/Probe/WaveForm.py @@ -244,7 +244,7 @@ class Analysis: ############################################## - def __init__(self, simulation, nodes=(), branches=(), elements=(), internal_parameters=()): + def __init__(self, simulation, nodes=(), branches=(), elements=(), internal_parameters=(), measurements={}): # Fixme: branches are elements in fact, and elements is not yet supported ... @@ -254,6 +254,7 @@ def __init__(self, simulation, nodes=(), branches=(), elements=(), internal_para self._branches = {waveform.name:waveform for waveform in branches} self._elements = {waveform.name:waveform for waveform in elements} self._internal_parameters = {waveform.name:waveform for waveform in internal_parameters} + self._measurements = measurements ############################################## @@ -277,6 +278,10 @@ def elements(self): @property def internal_parameters(self): return self._internal_parameters + + @property + def measurements(self): + return self._measurements ############################################## @@ -291,6 +296,8 @@ def _get_item(self, name): return self._elements[name] elif name in self._internal_parameters: return self._internal_parameters[name] + elif name in self._measurements: + return self._measurements[name] else: raise IndexError(name) @@ -320,7 +327,8 @@ def __getattr__(self, name): 'Nodes :' + os.linesep + self._format_dict(self._nodes) + os.linesep + 'Branches :' + os.linesep + self._format_dict(self._branches) + os.linesep + 'Elements :' + os.linesep + self._format_dict(self._elements) + os.linesep + - 'Internal Parameters :' + os.linesep + self._format_dict(self._internal_parameters) + 'Internal Parameters :' + os.linesep + self._format_dict(self._internal_parameters) + + 'Measurements :' + os.linesep + self._format_dict(self._measurements) ) #################################################################################################### diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index fdb17f19..e59affc8 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -262,28 +262,31 @@ def elements(self, abscissa=None): ############################################## - def to_analysis(self): + def to_analysis(self, measurements={}): if self.plot_name.startswith('op'): - return self._to_operating_point_analysis() + analysis = self._to_operating_point_analysis() elif self.plot_name.startswith('sens'): - return self._to_sensitivity_analysis() + analysis = self._to_sensitivity_analysis() elif self.plot_name.startswith('dc'): - return self._to_dc_analysis() + analysis = self._to_dc_analysis() elif self.plot_name.startswith('ac'): - return self._to_ac_analysis() + analysis = self._to_ac_analysis() elif self.plot_name.startswith('tran'): - return self._to_transient_analysis() + analysis = self._to_transient_analysis() elif self.plot_name.startswith('disto'): - return self._to_distortion_analysis() + analysis = self._to_distortion_analysis() elif self.plot_name.startswith('noise'): - return self._to_noise_analysis() + analysis = self._to_noise_analysis() elif self.plot_name.startswith('pz'): - return self._to_polezero_analysis() + analysis = self._to_polezero_analysis() elif self.plot_name.startswith('tf'): - return self._to_transfer_function_analysis() + analysis = self._to_transfer_function_analysis() else: raise NotImplementedError("Unsupported plot name {}".format(self.plot_name)) + + analysis._measurements = measurements # Unsafe! TODO: use a proper setter + return analysis ############################################## @@ -1198,17 +1201,20 @@ def run(self, background=False): # Parse out measurement results results = results if isinstance(results, list) else results.splitlines() + measurements = {} meas_start_index = 0 meas_end_index = 0 for line in results: if line.startswith('Measurements'): meas_start_index = results.index(line) + 1 elif meas_start_index and '=' in line: - meas_end_index = results.index(line) + meas_end_index = results.index(line) + 1 if meas_start_index and meas_end_index: for line in results[meas_start_index:meas_end_index]: # Extract each measurement result as a k,v pair - print(line) + [k, _, v, *_] = line.split() + measurements[k] = v + return measurements # time.sleep(.1) # required before to test if the simulation is running # while (self._ngspice_shared.ngSpice_running()): diff --git a/PySpice/Spice/NgSpice/Simulation.py b/PySpice/Spice/NgSpice/Simulation.py index 92b62ec2..fc01dd57 100644 --- a/PySpice/Spice/NgSpice/Simulation.py +++ b/PySpice/Spice/NgSpice/Simulation.py @@ -116,7 +116,7 @@ def _run(self, analysis_method, *args, **kwargs): # load circuit and simulation # Fixme: Error: circuit not parsed. self._ngspice_shared.load_circuit(str(self)) - self._ngspice_shared.run() + measurements = self._ngspice_shared.run() self._logger.debug(str(self._ngspice_shared.plot_names)) self.reset_analysis() @@ -124,4 +124,4 @@ def _run(self, analysis_method, *args, **kwargs): if plot_name == 'const': raise NameError('Simulation failed') - return self._ngspice_shared.plot(self, plot_name).to_analysis() + return self._ngspice_shared.plot(self, plot_name).to_analysis(measurements) From 531269d64b518759863d01c1bb13f2e7ec51c672 Mon Sep 17 00:00:00 2001 From: Marcus Mellor Date: Wed, 21 Jun 2023 12:44:20 -0500 Subject: [PATCH 4/4] Change Analysis.measurements to a public member --- PySpice/Probe/WaveForm.py | 12 ++++-------- PySpice/Spice/NgSpice/Shared.py | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/PySpice/Probe/WaveForm.py b/PySpice/Probe/WaveForm.py index 072e84a7..d86b4dd9 100644 --- a/PySpice/Probe/WaveForm.py +++ b/PySpice/Probe/WaveForm.py @@ -254,7 +254,7 @@ def __init__(self, simulation, nodes=(), branches=(), elements=(), internal_para self._branches = {waveform.name:waveform for waveform in branches} self._elements = {waveform.name:waveform for waveform in elements} self._internal_parameters = {waveform.name:waveform for waveform in internal_parameters} - self._measurements = measurements + self.measurements = measurements ############################################## @@ -278,10 +278,6 @@ def elements(self): @property def internal_parameters(self): return self._internal_parameters - - @property - def measurements(self): - return self._measurements ############################################## @@ -296,8 +292,8 @@ def _get_item(self, name): return self._elements[name] elif name in self._internal_parameters: return self._internal_parameters[name] - elif name in self._measurements: - return self._measurements[name] + elif name in self.measurements: + return self.measurements[name] else: raise IndexError(name) @@ -328,7 +324,7 @@ def __getattr__(self, name): 'Branches :' + os.linesep + self._format_dict(self._branches) + os.linesep + 'Elements :' + os.linesep + self._format_dict(self._elements) + os.linesep + 'Internal Parameters :' + os.linesep + self._format_dict(self._internal_parameters) + - 'Measurements :' + os.linesep + self._format_dict(self._measurements) + 'Measurements :' + os.linesep + self._format_dict(self.measurements) ) #################################################################################################### diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index e59affc8..14d5936e 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -285,7 +285,7 @@ def to_analysis(self, measurements={}): else: raise NotImplementedError("Unsupported plot name {}".format(self.plot_name)) - analysis._measurements = measurements # Unsafe! TODO: use a proper setter + analysis.measurements = measurements return analysis ############################################## @@ -1213,7 +1213,7 @@ def run(self, background=False): for line in results[meas_start_index:meas_end_index]: # Extract each measurement result as a k,v pair [k, _, v, *_] = line.split() - measurements[k] = v + measurements[k] = float(v) return measurements # time.sleep(.1) # required before to test if the simulation is running