From 86268f5da577a008dfb7fbe53635943fd2a6d0d5 Mon Sep 17 00:00:00 2001 From: fgarbu Date: Thu, 28 Nov 2024 11:16:10 +0100 Subject: [PATCH 1/3] extended SinuoidalMixin with phases and ac magnitude. Suppressed errors in NGSpiceShared to work with ngspice-43 --- PySpice/Spice/HighLevelElement.py | 46 ++++++++++++++++++++++++------- PySpice/Spice/NgSpice/Shared.py | 11 ++++++-- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/PySpice/Spice/HighLevelElement.py b/PySpice/Spice/HighLevelElement.py index dbce6238..ef8eb9cd 100644 --- a/PySpice/Spice/HighLevelElement.py +++ b/PySpice/Spice/HighLevelElement.py @@ -65,6 +65,8 @@ class SinusoidalMixin(SourceMixinAbc): +------+----------------+---------------+-------+ | Df + damping factor + 0.01 + 1/sec | +------+----------------+---------------+-------+ + | phi + phase + 0.0 + deg | + +------+----------------+---------------+-------+ The shape of the waveform is described by the following formula: @@ -72,12 +74,12 @@ class SinusoidalMixin(SourceMixinAbc): V(t) = \begin{cases} V_o & \text{if}\ 0 \leq t < T_d, \\ - V_o + V_a e^{-D_f(t-T_d)} \sin\left(2\pi f (t-T_d)\right) & \text{if}\ T_d \leq t < T_{stop}. + V_o + V_a e^{-D_f(t-T_d)} \sin\left(2\pi f (t-T_d) + \phi\right) & \text{if}\ T_d \leq t < T_{stop}. \end{cases} Spice syntax:: - SIN ( Voffset Vamplitude Freq Tdelay DampingFactor ) + SIN ( Voffset Vamplitude Freq Tdelay DampingFactor Phase) Public Attributes: @@ -95,6 +97,8 @@ class SinusoidalMixin(SourceMixinAbc): :attr:`offset` + :attr:`phase` + """ ############################################## @@ -102,16 +106,33 @@ class SinusoidalMixin(SourceMixinAbc): def __init__(self, dc_offset=0, ac_magnitude=1, - offset=0, amplitude=1, frequency=50, - delay=0, damping_factor=0): + ac_phase=0, + offset=None, amplitude=None, frequency=None, + delay=None, damping_factor=None, phase=None): + + self.no_sin_part = False + if all(x is None for x in (offset, amplitude, frequency, delay, damping_factor, phase)): + self.no_sin_part = True + if offset is None: + offset = 0 + if amplitude is None: + amplitude = 1 + if frequency is None: + frequency = 50 + if delay is None: + delay = 0 self.dc_offset = self.AS_UNIT(dc_offset) self.ac_magnitude = self.AS_UNIT(ac_magnitude) + self.ac_phase = ac_phase self.offset = self.AS_UNIT(offset) self.amplitude = self.AS_UNIT(amplitude) self.frequency = as_Hz(frequency) # Fixme: protect by setter? self.delay = as_s(delay) - self.damping_factor = as_Hz(damping_factor) + self.damping_factor = damping_factor + self.phase = phase # TODO: implement unit (as_deg?) + + ############################################## @@ -129,11 +150,16 @@ def period(self): ############################################## def format_spice_parameters(self): - sin_part = join_list((self.offset, self.amplitude, self.frequency, self.delay, self.damping_factor)) - return join_list(( - 'DC {} AC {}'.format(*str_spice_list(self.dc_offset, self.ac_magnitude)), - 'SIN({})'.format(sin_part), - )) + sin_part = join_list((self.offset, self.amplitude, self.frequency, self.delay, self.damping_factor, self.phase)) + if self.no_sin_part: + return join_list(( + 'DC {} AC {} {}'.format(*str_spice_list(self.dc_offset, self.ac_magnitude, self.ac_phase)), + )) + else: + return join_list(( + 'DC {} AC {} {}'.format(*str_spice_list(self.dc_offset, self.ac_magnitude, self.ac_phase)), + 'SIN({})'.format(sin_part), + )) #################################################################################################### diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index 183c08a4..f1eccc0a 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -90,7 +90,7 @@ import numpy as np from cffi import FFI - +import warnings #################################################################################################### from PySpice.Config import ConfigInstall @@ -621,6 +621,9 @@ def _send_char(message_c, ngspice_id, user_data): if content.startswith('Warning:'): func = self._logger.warning # elif content.startswith('Warning:'): + elif content.strip() == "Using SPARSE 1.3 as Direct Linear Solver": + self._logger.warning('Using SPARSE 1.3 as Direct Linear Solver') + func = self._logger.warning else: self._error_in_stderr = True func = self._logger.error @@ -848,7 +851,8 @@ def exec_command(self, command, join_lines=True): raise NameError("ngSpice_Command '{}' returned {}".format(command, rc)) if self._error_in_stdout or self._error_in_stderr: - raise NgSpiceCommandError("Command '{}' failed".format(command)) + # raise NgSpiceCommandError("Command '{}' failed".format(command)) + warnings.warn('NgSpiceCommandError: Command {} failed'.format(command)) if join_lines: return self.stdout @@ -1167,7 +1171,8 @@ def load_circuit(self, circuit): # Fixme: https://sourceforge.net/p/ngspice/bugs/496/ if self._error_in_stdout: self._logger.error('\n' + self.stdout) - raise NgSpiceCircuitError('') + # raise NgSpiceCircuitError('') + warnings.warn('NgSpiceCircuitError') # for line in circuit_lines: # rc = self._ngspice_shared.ngSpice_Command(('circbyline ' + line).encode('utf8')) From 024304efad5dd2ad64de9b335e410efb246bd956 Mon Sep 17 00:00:00 2001 From: fgarbu Date: Thu, 28 Nov 2024 11:29:10 +0100 Subject: [PATCH 2/3] extended SinuoidalMixin with phases and ac magnitude. Suppressed errors in NGSpiceShared to work with ngspice-43 --- PySpice/Spice/HighLevelElement.py | 50 ++++++++++++++++++++++++------- PySpice/Spice/NgSpice/Shared.py | 11 +++++-- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/PySpice/Spice/HighLevelElement.py b/PySpice/Spice/HighLevelElement.py index dbce6238..4b1d4b82 100644 --- a/PySpice/Spice/HighLevelElement.py +++ b/PySpice/Spice/HighLevelElement.py @@ -65,6 +65,8 @@ class SinusoidalMixin(SourceMixinAbc): +------+----------------+---------------+-------+ | Df + damping factor + 0.01 + 1/sec | +------+----------------+---------------+-------+ + | phi + sin_phase + 0.0 + deg | + +------+----------------+---------------+-------+ The shape of the waveform is described by the following formula: @@ -72,12 +74,12 @@ class SinusoidalMixin(SourceMixinAbc): V(t) = \begin{cases} V_o & \text{if}\ 0 \leq t < T_d, \\ - V_o + V_a e^{-D_f(t-T_d)} \sin\left(2\pi f (t-T_d)\right) & \text{if}\ T_d \leq t < T_{stop}. + V_o + V_a e^{-D_f(t-T_d)} \sin\left(2\pi f (t-T_d) + \phi\right) & \text{if}\ T_d \leq t < T_{stop}. \end{cases} Spice syntax:: - SIN ( Voffset Vamplitude Freq Tdelay DampingFactor ) + SIN ( Voffset Vamplitude Freq Tdelay DampingFactor Phase) Public Attributes: @@ -95,6 +97,10 @@ class SinusoidalMixin(SourceMixinAbc): :attr:`offset` + :attr:`phase` (phase of the AC component) + + :attr:`sin_phase` (phase of the sinusoidal component) + """ ############################################## @@ -102,16 +108,35 @@ class SinusoidalMixin(SourceMixinAbc): def __init__(self, dc_offset=0, ac_magnitude=1, - offset=0, amplitude=1, frequency=50, - delay=0, damping_factor=0): + ac_phase=0, + offset=None, amplitude=None, frequency=None, + delay=None, damping_factor=None, sin_phase=None): + + self.no_sin_part = False + if all(x is None for x in (offset, amplitude, frequency, delay, damping_factor, sin_phase)): + self.no_sin_part = True + if offset is None: + offset = 0 + if amplitude is None: + amplitude = 1 + if frequency is None: + frequency = 50 + if delay is None: + delay = 0 + if sin_phase is None: + sin_phase = 0 self.dc_offset = self.AS_UNIT(dc_offset) self.ac_magnitude = self.AS_UNIT(ac_magnitude) + self.ac_phase = ac_phase self.offset = self.AS_UNIT(offset) self.amplitude = self.AS_UNIT(amplitude) self.frequency = as_Hz(frequency) # Fixme: protect by setter? self.delay = as_s(delay) - self.damping_factor = as_Hz(damping_factor) + self.damping_factor = damping_factor + self.sin_phase = sin_phase # TODO: implement unit (as_deg?) + + ############################################## @@ -129,11 +154,16 @@ def period(self): ############################################## def format_spice_parameters(self): - sin_part = join_list((self.offset, self.amplitude, self.frequency, self.delay, self.damping_factor)) - return join_list(( - 'DC {} AC {}'.format(*str_spice_list(self.dc_offset, self.ac_magnitude)), - 'SIN({})'.format(sin_part), - )) + sin_part = join_list((self.offset, self.amplitude, self.frequency, self.delay, self.damping_factor, self.sin_phase)) + if self.no_sin_part: + return join_list(( + 'DC {} AC {} {}'.format(*str_spice_list(self.dc_offset, self.ac_magnitude, self.ac_phase)), + )) + else: + return join_list(( + 'DC {} AC {} {}'.format(*str_spice_list(self.dc_offset, self.ac_magnitude, self.ac_phase)), + 'SIN({})'.format(sin_part), + )) #################################################################################################### diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index 183c08a4..f1eccc0a 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -90,7 +90,7 @@ import numpy as np from cffi import FFI - +import warnings #################################################################################################### from PySpice.Config import ConfigInstall @@ -621,6 +621,9 @@ def _send_char(message_c, ngspice_id, user_data): if content.startswith('Warning:'): func = self._logger.warning # elif content.startswith('Warning:'): + elif content.strip() == "Using SPARSE 1.3 as Direct Linear Solver": + self._logger.warning('Using SPARSE 1.3 as Direct Linear Solver') + func = self._logger.warning else: self._error_in_stderr = True func = self._logger.error @@ -848,7 +851,8 @@ def exec_command(self, command, join_lines=True): raise NameError("ngSpice_Command '{}' returned {}".format(command, rc)) if self._error_in_stdout or self._error_in_stderr: - raise NgSpiceCommandError("Command '{}' failed".format(command)) + # raise NgSpiceCommandError("Command '{}' failed".format(command)) + warnings.warn('NgSpiceCommandError: Command {} failed'.format(command)) if join_lines: return self.stdout @@ -1167,7 +1171,8 @@ def load_circuit(self, circuit): # Fixme: https://sourceforge.net/p/ngspice/bugs/496/ if self._error_in_stdout: self._logger.error('\n' + self.stdout) - raise NgSpiceCircuitError('') + # raise NgSpiceCircuitError('') + warnings.warn('NgSpiceCircuitError') # for line in circuit_lines: # rc = self._ngspice_shared.ngSpice_Command(('circbyline ' + line).encode('utf8')) From 5635ce8b044470c9d47d2a6ab50308285bc49cd6 Mon Sep 17 00:00:00 2001 From: fgarbu Date: Fri, 6 Dec 2024 13:58:42 +0100 Subject: [PATCH 3/3] ignore some messages from ngspice 43 --- PySpice/Spice/NgSpice/Shared.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PySpice/Spice/NgSpice/Shared.py b/PySpice/Spice/NgSpice/Shared.py index f1eccc0a..2878093e 100644 --- a/PySpice/Spice/NgSpice/Shared.py +++ b/PySpice/Spice/NgSpice/Shared.py @@ -621,9 +621,9 @@ def _send_char(message_c, ngspice_id, user_data): if content.startswith('Warning:'): func = self._logger.warning # elif content.startswith('Warning:'): - elif content.strip() == "Using SPARSE 1.3 as Direct Linear Solver": - self._logger.warning('Using SPARSE 1.3 as Direct Linear Solver') - func = self._logger.warning + elif content.startswith('Error: Using SPARSE 1.3') or content.startswith('Error: bad set form'): + func = lambda x: None + else: self._error_in_stderr = True func = self._logger.error @@ -639,6 +639,7 @@ def _send_char(message_c, ngspice_id, user_data): # if self._error_in_stdout: # self._logger.warning(content) + # Fixme: ??? return self.send_char(message, ngspice_id) @@ -852,7 +853,7 @@ def exec_command(self, command, join_lines=True): if self._error_in_stdout or self._error_in_stderr: # raise NgSpiceCommandError("Command '{}' failed".format(command)) - warnings.warn('NgSpiceCommandError: Command {} failed'.format(command)) + warnings.warn('NgSpiceCommandError: Command {} warning'.format(command)) if join_lines: return self.stdout