# -*- coding: utf-8 -*-
####################################################################################################
#
# PySpice - A Spice Package for Python
# Copyright (C) 2014 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
####################################################################################################
"""This module implements high level elements built on top of Spice elements."""
# Fixme: check NgSpice for discrepancies
####################################################################################################
from ..Math import rms_to_amplitude, amplitude_to_rms
from ..Tools.StringTools import join_list, join_dict, str_spice, str_spice_list
from ..Unit import as_s, as_V, as_A, as_Hz
from .BasicElement import VoltageSource, CurrentSource
####################################################################################################
class SourceMixinAbc:
    __as_unit__ = None
####################################################################################################
class VoltageSourceMixinAbc:
    __as_unit__ = as_V
####################################################################################################
class CurrentSourceMixinAbc:
    __as_unit__ = as_A
####################################################################################################
[docs]class SinusoidalMixin(SourceMixinAbc):
    r"""This class implements a sinusoidal waveform.
    +------+----------------+---------------+-------+
    | Name + Parameter      + Default Value + Units |
    +------+----------------+---------------+-------+
    | Vo   + offset         +               + V, A  |
    +------+----------------+---------------+-------+
    | Va   + amplitude      +               + V, A  |
    +------+----------------+---------------+-------+
    | f    + frequency      + 1 / TStop     + Hz    |
    +------+----------------+---------------+-------+
    | Td   + delay          + 0.0           + sec   |
    +------+----------------+---------------+-------+
    | Df   + damping factor + 0.01          + 1/sec |
    +------+----------------+---------------+-------+
    The shape of the waveform is described by the following formula:
    .. math::
        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}.
        \end{cases}
    Spice syntax::
        SIN ( Voffset Vamplitude Freq Tdelay DampingFactor )
    Public Attributes:
      :attr:`ac_magnitude`
      :attr:`amplitude`
      :attr:`damping_factor`
      :attr:`dc_offset`
      :attr:`delay`
      :attr:`frequency`
      :attr:`offset`
    """
    ##############################################
    def __init__(self,
                 dc_offset=0,
                 ac_magnitude=1,
                 offset=0, amplitude=1, frequency=50,
                 delay=0, damping_factor=0):
        self.dc_offset = self.__as_unit__(dc_offset)
        self.ac_magnitude = self.__as_unit__(ac_magnitude)
        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)
    ##############################################
    @property
    def rms_voltage(self):
        # Fixme: ok ???
        return amplitude_to_rms(self.amplitude * self.ac_magnitude)
    ##############################################
    @property
    def period(self):
        return self.frequency.period
    ##############################################
    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),
        )) 
####################################################################################################
[docs]class PulseMixin(SourceMixinAbc):
    """This class implements a pulse waveform.
    Nomenclature:
    +--------+---------------+---------------+-------+
    | Name   + Parameter     + Default Value + Units |
    +--------+---------------+---------------+-------+
    | V1     + initial value +               + V, A  |
    +--------+---------------+---------------+-------+
    | V2     + pulsed value  +               + V, A  |
    +--------+---------------+---------------+-------+
    | Td     + delay time    + 0.0           + sec   |
    +--------+---------------+---------------+-------+
    | Tr     + rise time     + Tstep         + sec   |
    +--------+---------------+---------------+-------+
    | Tf     + fall time     + Tstep         + sec   |
    +--------+---------------+---------------+-------+
    | Pw     + pulse width   + Tstop         + sec   |
    +--------+---------------+---------------+-------+
    | Period + period        + Tstop         + sec   |
    +--------+---------------+---------------+-------+
    | Phase  + phase         + 0.0           + sec   |
    +--------+---------------+---------------+-------+
    Phase is only possible when XSPICE is enabled
    Spice Syntax::
        PULSE ( V1 V2 Td Tr Tf Pw Period Phase )
    A single pulse so specified is described by the following table:
    +-------------+-------+
    | Time        | Value |
    +-------------+-------+
    | 0           | V1    |
    +-------------+-------+
    | Td          | V1    |
    +-------------+-------+
    | Td+Tr       | V2    |
    +-------------+-------+
    | Td+Tr+Pw    | V2    |
    +-------------+-------+
    | Td+Tr+Pw+Tf | V1    |
    +-------------+-------+
    | Tstop       | V1    |
    +-------------+-------+
    Note: default value in Spice for rise and fall time is the simulation transient step, pulse
    width and period is the simulation stop time.
    Public Attributes:
      :attr:`delay_time`
      :attr:`fall_time`
      :attr:`initial_value`
      :attr:`period`
      :attr:`phase`
      :attr:`pulse_width`
      :attr:`pulsed_value`
      :attr:`rise_time`
    """
    ##############################################
    def __init__(self,
                 initial_value, pulsed_value,
                 pulse_width, period,
                 delay_time=0, rise_time=0, fall_time=0,
                 phase=None,
                 dc_offset=0):
        # Fixme: default
        #  rise_time, fall_time = Tstep
        #  pulse_width, period = Tstop
        self.dc_offset = self.__as_unit__(dc_offset) # Fixme: -> SourceMixinAbc
        self.initial_value = self.__as_unit__(initial_value)
        self.pulsed_value = self.__as_unit__(pulsed_value)
        self.delay_time = as_s(delay_time)
        self.rise_time = as_s(rise_time)
        self.fall_time = as_s(fall_time)
        self.pulse_width = as_s(pulse_width)
        self.period = as_s(period) # Fixme: protect by setter?
        # XSPICE
        if phase is not None:
            self.phase = as_s(phase)
        else:
            self.phase = None
        # # Fixme: to func?
        # # Check parameters
        # found_none = False
        # for parameter in ('rise_time', 'fall_time', 'pulse_width', 'period'):
        #     parameter_value = getattr(self, parameter)
        #     if found_none:
        #         if parameter_value is not None:
        #             raise ValueError("Parameter {} is set but some previous parameters was not set".format(parameter))
        #     else:
        #         found_none = parameter_value is None
    ##############################################
    @property
    def frequency(self):
        return self.period.frequency
    ##############################################
    def format_spice_parameters(self):
        # if DC is not provided, ngspice complains
        #   Warning: vpulse: no DC value, transient time 0 value used
        # Fixme: to func?
        return join_list((
            'DC {}'.format(str_spice(self.dc_offset)),
            'PULSE(' +
            join_list((self.initial_value, self.pulsed_value, self.delay_time,
                       self.rise_time, self.fall_time, self.pulse_width, self.period,
                       self.phase)) +
            ')')) 
####################################################################################################
[docs]class ExponentialMixin(SourceMixinAbc):
    r"""This class implements a Exponential waveform.
    Nomenclature:
    +------+--------------------+---------------+-------+
    | Name + Parameter          + Default Value + Units |
    +------+--------------------+---------------+-------+
    | V1   + Initial value      +               + V, A  |
    +------+--------------------+---------------+-------+
    | V2   + pulsed value       +               + V, A  |
    +------+--------------------+---------------+-------+
    | Td1  + rise delay time    + 0.0           + sec   |
    +------+--------------------+---------------+-------+
    | tau1 + rise time constant + Tstep         + sec   |
    +------+--------------------+---------------+-------+
    | Td2  + fall delay time    + Td1+Tstep     + sec   |
    +------+--------------------+---------------+-------+
    | tau2 + fall time constant + Tstep         + sec   |
    +------+--------------------+---------------+-------+
    Spice Syntax::
        EXP ( V1 V2 TD1 TAU1 TD2 TAU2 )
    The shape of the waveform is described by the following formula:
    Let V21 = V2 - V1 and V12 = V1 - V2.
    .. math::
        V(t) = \begin{cases}
          V_1 & \text{if}\ 0 \leq t < T_{d1}, \\
          V_1 + V_{21} ( 1 − e^{-\frac{t-T_{d1}}{\tau_1}} )
          & \text{if}\ T_{d1} \leq t < T_{d2}, \\
          V_1 + V_{21} ( 1 − e^{-\frac{t-T_{d1}}{\tau_1}} ) + V_{12} ( 1 − e^{-\frac{t-T_{d2}}{\tau_2}} )
          & \text{if}\ T_{d2} \leq t < T_{stop}
        \end{cases}
    """
    ##############################################
    def __init__(self,
                 initial_value, pulsed_value,
                 rise_delay_time=.0, rise_time_constant=None,
                 fall_delay_time=None, fall_time_constant=None):
        # Fixme: default
        self.initial_value = self.__as_unit__(initial_value)
        self.pulsed_value = self.__as_unit__(pulsed_value)
        self.rise_delay_time = as_s(rise_delay_time)
        self.rise_time_constant = as_s(rise_time_constant)
        self.fall_delay_time = as_s(fall_delay_time)
        self.fall_time_constant = as_s(fall_time_constant)
    ##############################################
    def format_spice_parameters(self):
        # Fixme: to func?
        return ('EXP(' +
                join_list((self.initial_value, self.pulsed_value,
                           self.rise_delay_time, self.rise_time_constant,
                           self.fall_delay_time, self.fall_time_constant,
                       )) +
                ')') 
####################################################################################################
[docs]class PieceWiseLinearMixin(SourceMixinAbc):
    r"""This class implements a Piece-Wise Linear waveform.
    Spice Syntax::
        PWL( T1 V1 <T2 V2 T3 V3 T4 V4 ... > ) <r=value> <td=value>
    Each pair of values (Ti , Vi) specifies that the value of the source is Vi (in Volts or Amps) at
    time = Ti . The value of the source at intermediate values of time is determined by using linear
    interpolation on the input values. The parameter r determines a repeat time point. If r is not
    given, the whole sequence of values (Ti , Vi ) is issued once, then the output stays at its
    final value. If r = 0, the whole sequence from time = 0 to time = Tn is repeated forever. If r =
    10ns, the sequence between 10ns and 50ns is repeated forever. the r value has to be one of the
    time points T1 to Tn of the PWL sequence. If td is given, the whole PWL sequence is delayed by a
    delay time time = td. The current source still needs to be patched, td and r are not yet
    available.
    `values` should be given as a list of (`Time`, `Value`)-tuples, e.g.::
        PieceWiseLinearVoltageSource(
            circuit,
            'pwl1', '1', '0',
            values=[(0, 0), (10@u_ms, 0), (11@u_ms, 5@u_V), (20@u_ms, 5@u_V)],
        )
    """
    ##############################################
    def __init__(self, values, repeate_time=0, delay_time=.0):
        # Fixme: default
        self.values = sum(([as_s(t), self.__as_unit__(x)] for (t, x) in values), [])
        self.repeate_time = as_s(repeate_time)
        self.delay_time = as_s(delay_time)
    ##############################################
    def format_spice_parameters(self):
        # Fixme: to func?
        return ('PWL(' +
                join_list(self.values) +
                ' ' +
                join_dict({'r':self.repeate_time, 'td':self.delay_time}) + # OrderedDict(
                ')') 
####################################################################################################
[docs]class SingleFrequencyFMMixin(SourceMixinAbc):
    r"""This class implements a Single-Frequency FM waveform.
    Spice Syntax::
        SFFM (VO VA FC MDI FS )
   +------+-------------------+---------------+-------+
   | Name + Parameter         + Default Value + Units |
   +------+-------------------+---------------+-------+
   | Vo   + offset            +               + V, A  |
   +------+-------------------+---------------+-------+
   | Va   + amplitude         +               + V, A  |
   +------+-------------------+---------------+-------+
   | Fc   + carrier frequency + 1 / Tstop     + Hz    |
   +------+-------------------+---------------+-------+
   | Mdi  + modulation index  +               +       |
   +------+-------------------+---------------+-------+
   | Fs   + signal frequency  + 1 / Tstop     + Hz    |
   +------+-------------------+---------------+-------+
    The shape of the waveform is described by the following equation:
    .. math::
        V(t) = V_o + V_a \sin (2\pi F_c\, t + M_{di} \sin (2\pi F_s\,t))
    """
    ##############################################
    def __init__(self, offset, amplitude, carrier_frequency, modulation_index, signal_frequency):
        self.offset = self.__as_unit__(offset)
        self.amplitude = self.__as_unit__(amplitude)
        self.carrier_frequency = as_Hz(carrier_frequency)
        self.modulation_index = modulation_index
        self.signal_frequency = as_Hz(signal_frequency)
    ##############################################
    def format_spice_parameters(self):
        # Fixme: to func?
        return ('SFFM(' +
                join_list((self.offset, self.amplitude, self.carrier_frequency,
                           self.modulation_index, self.signal_frequency)) +
                ')') 
####################################################################################################
[docs]class AmplitudeModulatedMixin(SourceMixinAbc):
    r"""This class implements a Amplitude Modulated source.
    +------+----------------------+---------------+-------+
    | Name + Parameter            + Default Value + Units |
    +------+----------------------+---------------+-------+
    | Vo   + offset               +               + V, A  |
    +------+----------------------+---------------+-------+
    | Va   + amplitude            +               + V, A  |
    +------+----------------------+---------------+-------+
    | Mf   + modulating frequency +               + Hz    |
    +------+----------------------+---------------+-------+
    | Fc   + carrier frequency    + 1 / Tstop     + Hz    |
    +------+----------------------+---------------+-------+
    | Td   + signal delay         +               + s     |
    +------+----------------------+---------------+-------+
    Spice Syntax::
        AM(VA VO MF FC TD)
    The shape of the waveform is described by the following equation:
    .. math::
        V(t) = V_a (V_o + \sin (2\pi M_f\,t)) \sin (2\pi F_c\,t)
    """
    ##############################################
    def __init__(self, offset, amplitude, modulating_frequency, carrier_frequency, signal_delay):
        # Fixme: default
        self.offset = self.__as_unit__(offset)
        self.amplitude = self.__as_unit__(amplitude)
        self.carrier_frequency = as_Hz(carrier_frequency)
        self.modulating_frequency = as_Hz(modulating_frequency)
        self.signal_delay = as_s(signal_delay)
    ##############################################
    def format_spice_parameters(self):
        # Fixme: to func?
        return ('AM(' +
                join_list((self.offset, self.amplitude, self.carrier_frequency,
                           self.modulating_frequency, self.signal_delay)) +
                ')') 
####################################################################################################
[docs]class RandomMixin(SourceMixinAbc):
    r"""This class implements a Random Voltage source.
    The TRRANDOM option yields statistically distributed voltage values, derived from the ngspice
    random number generator. These values may be used in the transient simulation directly within a
    circuit, e.g. for generating a specific noise voltage, but especially they may be used in the
    control of behavioral sources (B, E, G sources, voltage controllable A sources, capacitors,
    inductors, or resistors) to simulate the circuit dependence on statistically varying device
    parameters. A Monte-Carlo simulation may thus be handled in a single simulation run.
    Spice Syntax::
        TRRANDOM( TYPE TS <TD <PARAM1 <PARAM2> > >)
    TYPE determines the random variates generated: 1 is uniformly distributed, 2 Gaussian, 3
    exponential, 4 Poisson. TS is the duration of an individual voltage value. TD is a time delay
    with 0 V output before the random voltage values start up. PARAM1 and PARAM2 depend on the type
    selected.
    +-------------+---------------+---------+-------------+---------+
    | Type        + Parameter 1   + Default + Parameter 2 + Default |
    +-------------+---------------+---------+-------------+---------+
    | uniform     + range         + 1       + offset      + 0       |
    +-------------+---------------+---------+-------------+---------+
    | gaussian    + standard dev. + 1       + mean        + 0       |
    +-------------+---------------+---------+-------------+---------+
    | exponential + mean          + 1       + offset      + 0       |
    +-------------+---------------+---------+-------------+---------+
    | poisson     + lambda        + 1       + offset      + 0       |
    +-------------+---------------+---------+-------------+---------+
    """
    ##############################################
    def __init__(self, random_type, duration=0, time_delay=0, parameter1=1, parameter2=0):
        # Fixme: random_type and parameters
        self.random_type = random_type
        self.duration = as_s(duration)
        self.time_delay = as_s(time_delay)
        self.parameter1 = parameter1
        self.parameter2 = parameter2
    ##############################################
    def format_spice_parameters(self):
        if self.random_type == 'uniform':
            random_type = 1
        elif self.random_type == 'exponential':
            random_type = 2
        elif self.random_type == 'gaussian':
            random_type = 3
        elif self.random_type == 'poisson':
            random_type = 4
        else:
            raise ValueError("Wrong random type {}".format(self.random_type))
        # Fixme: to func?
        return ('TRRANDOM(' +
                join_list((random_type, self.duration, self.time_delay,
                           self.parameter1, self.parameter2)) +
                ')') 
####################################################################################################
[docs]class SinusoidalVoltageSource(VoltageSource, VoltageSourceMixinAbc, SinusoidalMixin):
    r"""This class implements a sinusoidal waveform voltage source.
    See :class:`SinusoidalMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        SinusoidalMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = SinusoidalMixin.format_spice_parameters 
####################################################################################################
[docs]class SinusoidalCurrentSource(CurrentSource, CurrentSourceMixinAbc, SinusoidalMixin):
    r"""This class implements a sinusoidal waveform current source.
    See :class:`SinusoidalMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        SinusoidalMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = SinusoidalMixin.format_spice_parameters 
####################################################################################################
[docs]class AcLine(SinusoidalVoltageSource):
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, rms_voltage=230, frequency=50):
        super().__init__(netlist, name, node_plus, node_minus,
                         amplitude=rms_to_amplitude(rms_voltage),
                         frequency=frequency) 
####################################################################################################
[docs]class PulseVoltageSource(VoltageSource, VoltageSourceMixinAbc, PulseMixin):
    r"""This class implements a pulse waveform voltage source.
    See :class:`PulseMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        PulseMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = PulseMixin.format_spice_parameters 
####################################################################################################
[docs]class PulseCurrentSource(CurrentSource, CurrentSourceMixinAbc, PulseMixin):
    r"""This class implements a pulse waveform current source.
    See :class:`PulseMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        PulseMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = PulseMixin.format_spice_parameters 
####################################################################################################
[docs]class ExponentialVoltageSource(VoltageSource, VoltageSourceMixinAbc, ExponentialMixin):
    r"""This class implements a exponential waveform voltage source.
    See :class:`ExponentialMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        ExponentialMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = ExponentialMixin.format_spice_parameters 
####################################################################################################
[docs]class ExponentialCurrentSource(CurrentSource, CurrentSourceMixinAbc, ExponentialMixin):
    r"""This class implements a exponential waveform current source.
    See :class:`ExponentialMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        ExponentialMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = ExponentialMixin.format_spice_parameters 
####################################################################################################
[docs]class PieceWiseLinearVoltageSource(VoltageSource, VoltageSourceMixinAbc, PieceWiseLinearMixin):
    r"""This class implements a piece wise linear waveform voltage source.
    See :class:`PieceWiseLinearMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        PieceWiseLinearMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = PieceWiseLinearMixin.format_spice_parameters 
####################################################################################################
[docs]class PieceWiseLinearCurrentSource(CurrentSource, CurrentSourceMixinAbc, PieceWiseLinearMixin):
    r"""This class implements a piece wise linear waveform current source.
    See :class:`PieceWiseLinearMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        PieceWiseLinearMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = PieceWiseLinearMixin.format_spice_parameters 
####################################################################################################
[docs]class SingleFrequencyFMVoltageSource(VoltageSource, VoltageSourceMixinAbc, SingleFrequencyFMMixin):
    r"""This class implements a single frequency FM waveform voltage source.
    See :class:`SingleFrequencyFMMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        SingleFrequencyFMMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = SingleFrequencyFMMixin.format_spice_parameters 
####################################################################################################
[docs]class SingleFrequencyFMCurrentSource(CurrentSource, CurrentSourceMixinAbc, SingleFrequencyFMMixin):
    r"""This class implements a single frequency FM waveform current source.
    See :class:`SingleFrequencyFMMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        SingleFrequencyFMMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = SingleFrequencyFMMixin.format_spice_parameters 
####################################################################################################
[docs]class AmplitudeModulatedVoltageSource(VoltageSource, VoltageSourceMixinAbc, AmplitudeModulatedMixin):
    r"""This class implements a amplitude modulated waveform voltage source.
    See :class:`AmplitudeModulatedMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        AmplitudeModulatedMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = AmplitudeModulatedMixin.format_spice_parameters 
####################################################################################################
[docs]class AmplitudeModulatedCurrentSource(CurrentSource, CurrentSourceMixinAbc, AmplitudeModulatedMixin):
    r"""This class implements a amplitude modulated waveform current source.
    See :class:`AmplitudeModulatedMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        AmplitudeModulatedMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = AmplitudeModulatedMixin.format_spice_parameters 
####################################################################################################
[docs]class RandomVoltageSource(VoltageSource, VoltageSourceMixinAbc, RandomMixin):
    r"""This class implements a random waveform voltage source.
    See :class:`RandomMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        VoltageSource.__init__(self, netlist, name, node_plus, node_minus)
        RandomMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = RandomMixin.format_spice_parameters 
####################################################################################################
[docs]class RandomCurrentSource(CurrentSource, CurrentSourceMixinAbc, RandomMixin):
    r"""This class implements a random waveform current source.
    See :class:`RandomMixin` for documentation.
    """
    ##############################################
    def __init__(self, netlist, name, node_plus, node_minus, *args, **kwargs):
        CurrentSource.__init__(self, netlist, name, node_plus, node_minus)
        RandomMixin.__init__(self, *args, **kwargs)
    ##############################################
    format_spice_parameters = RandomMixin.format_spice_parameters