Esempio n. 1
0
 def __mul__(self,other):
     """overloads *
     @param other instance of class WaveformProcessor or float, int, complex to multiply by.
     @return instance of class Waveform with other multiplied by self
     @note does not affect self
     @note Waveform multiplication is an abstraction in some cases. The result for types
     of other is:
     - WaveformProcessor - returns self processed by the instance of WaveformProcessor.
     - float,int,complex - returns the Waveform produced by multiplying all of the values in
     self multiplied by the constant value supplied.
     @note The most obvious type of WaveformProcessor is a FirFilter, but there are others like
     WaveformTrimmer and WaveformDecimator.
     @throw SignalIntegrityExceptionWaveform if other cannot be multiplied.
     """
     # pragma: silent exclude
     from SignalIntegrity.Lib.TimeDomain.Filters.WaveformProcessor import WaveformProcessor
     # pragma: include
     if isinstance(other,WaveformProcessor):
         return other.ProcessWaveform(self)
     elif isinstance(other,(float,int,complex)):
         return Waveform(self.td,[v*other.real for v in self])
     elif isinstance(other,Waveform):
         [s,o]=AdaptedWaveforms([self,other])
         return Waveform(s.td,[s[k]*o[k] for k in range(len(s))])
     # pragma: silent exclude
     else:
         raise SignalIntegrityExceptionWaveform('cannot multiply waveform by type '+str(other.__class__.__name__))
Esempio n. 2
0
    def __add__(self,other):
        """overloads +
        @param other instance of class Waveform or float, int, complex to add.
        @return instance of class Waveform with other added to self
        @note does not affect self
        @note
        valid types of other to add are:

        - Waveform - if the other waveform has the same time descriptor, returns the waveform
        with self and others values added together, otherwise adapts other to self and then
        adds them.
        - float,int,complex - adds the constant value to all values in self.
        @throw SignalIntegrityExceptionWaveform if other cannot be added.
        @see AdaptedWaveforms
        """
        if isinstance(other,Waveform):
            if self.td == other.td:
                return Waveform(self.td,[self[k]+other[k] for k in range(len(self))])
            else:
                [s,o]=AdaptedWaveforms([self,other])
                return Waveform(s.td,[s[k]+o[k] for k in range(len(s))])
                #return awf[0]+awf[1]
        elif isinstance(other,(float,int,complex)):
            return Waveform(self.td,[v+other.real for v in self])
        # pragma: silent exclude
        else:
            raise SignalIntegrityExceptionWaveform('cannot add waveform to type '+str(other.__class__.__name__))
Esempio n. 3
0
    def __sub__(self,other):
        """overloads -
        @param other instance of class Waveform or float, int, complex to subtract.
        @return instance of class Waveform with other subtracted from self
        @note does not affect self
        @note
        valid types of other to subtract are:

        - Waveform - if the other waveform has the same time descriptor, returns the waveform
        with self and others values subtracted, otherwise adapts other to self and then
        subtracts them.
        - float,int,complex - subtracts the constant value from all values in self.
        @throw SignalIntegrityExceptionWaveform if other cannot be subtracted.
        @see AdaptedWaveforms
        """
        if isinstance(other,Waveform):
            if self.td == other.td:
                return Waveform(self.td,[self[k]-other[k] for k in range(len(self))])
            else:
                [s,o]=AdaptedWaveforms([self,other])
                return Waveform(s.td,[s[k]-o[k] for k in range(len(s))])
        elif isinstance(other,(float,int,complex)):
            return Waveform(self.td,[v-other.real for v in self])
        # pragma: silent exclude
        else:
            raise SignalIntegrityExceptionWaveform('cannot subtract type' + str(other.__class__.__name__) + ' from waveform')
 def __init__(self,pattern,bitRate,amplitude=1.0,risetime=0.,delay=0.,tdOrFs=None):
     """constructor
     @param pattern list of bits in pattern which must be 0 or 1
     @param bitrate float bitrate in bits/s
     @param amplitude (optional, defaults to 1.0) float amplitude of zero centered serial data waveform (pk-pk amplitude is twice this value)
     @param risetime (optional, defaults to 0.0) float risetime of a 1/2 cosine response.
     @param delay (optional, defaults to 0,0) float delay in time into the pattern.
     @param tdOrFs (optional, defaults to None) time descriptor or float sample rate.  If None is specified, then
     the descriptor is generated for one pattern length with a sample rate of 10x the bitrate.  Otherwise, if a float
     is specified, then a time descriptor for one pattern length is generated with the sample rate specified.  Otherwise
     the time descriptor specified is used.
     @return self, a waveform.
     @throw SignalIntegrityExceptionWaveform exception is raised if the risetime exceeds 59% of the unit interval as this causes
     the calculation to fail.
     @todo the failure for a given risetime is due to the simplicity of the algorithm which should be improved at some point.
     this simplicity is that it only looks at adjacent bits to determine the intersymbol effect of the risetime.
     @note the left edge of the first bit in the pattern is at the delay time.  But because a cosine is used for
     the risetime emulation, the 50% point of the cosine is reached at this edge.
     @note the risetime is adjusted if it is too low relative to the sample period.
     """
     if tdOrFs is None:
         sampleRate=10.*bitRate
         td=self.TimeDescriptor(bitRate, sampleRate, len(pattern))
     elif isinstance(tdOrFs,float):
         sampleRate=tdOrFs
         td=self.TimeDescriptor(bitRate, sampleRate, len(pattern))
     else:
         td=tdOrFs
     T=max(risetime/self.rtvsT,1/td.Fs)
     patternTimeLength=len(pattern)/bitRate
     unitInterval=1./bitRate
     if T>unitInterval:
         # todo: would like to handle this case in the future
         raise SignalIntegrityExceptionWaveform('PRBS risetime too high\nfor waveform generation. '+\
                'Limit is '+ToSI(unitInterval*self.rtvsT,'s')+' for given bitrate')
     v=[0. for _ in range(len(td))]
     for k in range(len(td)):
         t=td[k]
         timeInPattern=((t-delay)%patternTimeLength+patternTimeLength)%patternTimeLength
         thisBit=int(math.floor(timeInPattern/unitInterval))
         timeInBit=timeInPattern-thisBit*unitInterval
         thisBitValue=pattern[thisBit]
         if timeInBit>=T/2. and (timeInBit-unitInterval)<=-T/2.:
             v[k]=2.*amplitude*(thisBitValue-0.5)
         elif timeInBit<T/2.:
             previousBit=(thisBit-1+len(pattern))%len(pattern)
             previousBitTransition=thisBitValue-pattern[previousBit]
             if previousBitTransition==0:
                 v[k]=2.*amplitude*(thisBitValue-0.5)
             else:
                 v[k]=amplitude*previousBitTransition*math.cos(math.pi*(timeInBit/T+3./2.))
         elif (timeInBit-unitInterval)>-T/2.:
             nextBit=(thisBit+1)%len(pattern)
             nextBitTransition=pattern[nextBit]-thisBitValue
             if nextBitTransition==0:
                 v[k]=2.*amplitude*(thisBitValue-0.5)
             else:
                 v[k]=amplitude*nextBitTransition*math.cos(math.pi*((timeInBit-unitInterval)/T+3./2.))
     Waveform.__init__(self,Waveform(td,v))
Esempio n. 5
0
 def Adapt(self,td):
     """adapts waveform to time descriptor  
     Waveform adaption is performed using upsampling, decimation, fractional delay,
     and waveform point trimming.
     @param td instance of class TimeDescriptor to adapt waveform to
     @return instance of class Waveform containing self adapted to the time descriptor
     @note does not affect self.
     @note the static member variable adaptionStrategy determines how to interpolate.  'SinX' means
     to use sinx/x interpolation, 'Linear' means to use linear interpolation.
     @see InterpolatorSinX
     @see SignalIntegrity.TimeDomain.Filters.InterpolatorSinX.FractionalDelayFilterSinX
     @see SignalIntegrity.TimeDomain.Filters.InterpolatorSinX.FractionalDelayFilterSinX
     @see SignalIntegrity.TimeDomain.Filters.InterpolatorLinear.InterpolatorLinear
     @see SignalIntegrity.TimeDomain.Filters.InterpolatorLinear.FractionalDelayFilterLinear
     @see SignalIntegrity.TimeDomain.Filters.WaveformTrimmer.WaveformTrimmer
     @see SignalIntegrity.TimeDomain.Filters.WaveformDecimator.WaveformDecimator
     @see SignalIntegrity.Rat.Rat
     """
     # pragma: silent exclude
     from SignalIntegrity.Lib.TimeDomain.Filters.InterpolatorSinX import InterpolatorSinX
     from SignalIntegrity.Lib.TimeDomain.Filters.InterpolatorSinX import FractionalDelayFilterSinX
     from SignalIntegrity.Lib.TimeDomain.Filters.InterpolatorLinear import InterpolatorLinear
     from SignalIntegrity.Lib.TimeDomain.Filters.InterpolatorLinear import FractionalDelayFilterLinear
     from SignalIntegrity.Lib.TimeDomain.Filters.WaveformTrimmer import WaveformTrimmer
     from SignalIntegrity.Lib.TimeDomain.Filters.WaveformDecimator import WaveformDecimator
     from SignalIntegrity.Lib.Rat import Rat
     # pragma: include
     wf=self
     (upsampleFactor,decimationFactor)=Rat(td.Fs/wf.td.Fs)
     if upsampleFactor>1:
         # pragma: silent exclude
         if wf.td.K*upsampleFactor > self.maximumWaveformSize:
             raise SignalIntegrityExceptionWaveform('waveform too large to process')
         # pragma: include
         wf=wf*(InterpolatorSinX(upsampleFactor) if wf.adaptionStrategy=='SinX'
             else InterpolatorLinear(upsampleFactor))
     ad=td/wf.td
     f=ad.D-int(math.floor(ad.D))
     if not ((f<self.epsilon) or ((1-f)<self.epsilon)):
         wf=wf*(FractionalDelayFilterSinX(f,True) if wf.adaptionStrategy=='SinX'
             else FractionalDelayFilterLinear(f,True))
         ad=td/wf.td
     if decimationFactor>1:
         decimationPhase=int(round(ad.TrimLeft())) % decimationFactor
         wf=wf*WaveformDecimator(decimationFactor,decimationPhase)
         ad=td/wf.td
     tr=WaveformTrimmer(max(0,int(round(ad.TrimLeft()))),
                        max(0,int(round(ad.TrimRight()))))
     wf=wf*tr
     return wf
Esempio n. 6
0
 def __truediv__(self,other):
     """overloads /
     @param other instance of float, int, complex to divide by.
     @return instance of class Waveform with other divided into it.
     @note only handles float, int, complex where the constant values are divided into the
     values in self.
     @note should consider allowing a two waveforms to be divided, but frankly never came
     upon the need for that.
     @throw SignalIntegrityExceptionWaveform if other cannot be multiplied.
     """
     if isinstance(other,(float,int,complex)):
         return Waveform(self.td,[v/other.real for v in self])
     # pragma: silent exclude
     else:
         raise SignalIntegrityExceptionWaveform('cannot divide waveform by type '+str(other.__class__.__name__))
Esempio n. 7
0
 def __init__(self,polynomial,bitrate,amplitude=1.0,risetime=0.,delay=0.,tdOrFs=None):
     """constructor
     @param polynomial integer polynomial number
     @param bitrate, amplitude, risetime, delay, tdOrFs all pertain to the derived SerialDataWaveform class
     @see SerialDataWaveform
     @return self, a waveform.
     @throw SignalIntegrityWaveform exception is raised if the polynomial number cannot be found
     @see PseudoRandomPolynomial
     """
     try:
         if isinstance(tdOrFs,TimeDescriptor):
             td=tdOrFs
             SerialDataWaveform.__init__(self,PseudoRandomPolynomial(polynomial).Pattern(math.ceil(td.K*bitrate/td.Fs)),bitrate,amplitude,risetime,delay,tdOrFs)
         else:
             SerialDataWaveform.__init__(self,PseudoRandomPolynomial(polynomial).Pattern(),bitrate,amplitude,risetime,delay,tdOrFs)
     except SignalIntegrityException as e:
         raise SignalIntegrityExceptionWaveform(e.message)
Esempio n. 8
0
    def __init__(self, wf, fd=None):
        """Constructor
        @param wf in instance of class Waveform
        @param fd (optional) an instance of class FrequencyList (defaults to None)
        @remark
        initializes itself internally by computing the frequency content of the waveform.

        If fd is None then the frequency descriptor is simply the frequency descriptor corresponding to the time
        descriptor of the waveform and the frequency content is computed from the DFT.

        Otherwise, the CZT is used to compute the frequency content and the time descriptor corresponds to the
        frequency descriptor.

        the time descriptor and frequency descriptor are retained so a waveform can be obtained from the frequency content.

        @note the frequency content is scaled differently from the raw DFT or CZT outputs in that the absolute value of each
        complex number in the frequency content represents the amplitude of a cosine wave.  This is not true with the raw
        DFT output and scaling things this way helps in the proper interpretation of the frequency content without having
        to think about the vagaries of the DFT.

        @see TimeDescriptor
        @see FrequencyList
        @see ChirpZTransform
        """
        td = wf.td
        if fd is None:
            X = fft.fft(wf.Values())
            K = int(td.K)
            Keven = (K // 2) * 2 == K
            fd = td.FrequencyList()
        else:
            # pragma: silent exclude
            if not fd.EvenlySpaced():
                raise SignalIntegrityExceptionWaveform(
                    'cannot generate frequency content')
            # pragma: include
            K = fd.N * 2
            Keven = True
            X = CZT(wf.Values(), td.Fs, 0, fd.Fe, fd.N, True)
            td = TimeDescriptor(td.H, fd.N * 2, fd.Fe * 2.)
        FrequencyDomain.__init__(self,fd,[X[n]/K*\
            (1. if (n==0 or ((n==fd.N) and Keven)) else 2.)*\
            cmath.exp(-1j*2.*math.pi*fd[n]*td.H) for n in range(fd.N+1)])
        self.td = td