Ejemplo n.º 1
0
    def main(self, input):
        """
        Args:
            input (DataValid): -1.0 ... 1.0 range, up to 18 bits

        Returns:
            DataValid: 18 bits(-1.0 ... 1.0 range) if transform size is up to 1024 points.
                Transforms over 1024 points start emphasizing smaller numbers e.g. 2048 would return a result with 18 bits
                but in -0.5 ... 0.5 range (one extra bit for smaller numbers) etc...

        """
        var = input
        if self.INVERSE:
            var = DataValid(Complex(input.data.imag, input.data.real),
                            input.valid)

        # execute stages
        for stage in self.stages:
            var = stage.main(var)

        if self.INVERSE:
            var = DataValid(Complex(var.data.imag, var.data.real), var.valid)

        # this part is active if transform is larger than 10 stages
        if self.POST_GAIN_CONTROL != 0:
            self.output.data = scalb(var.data, -self.POST_GAIN_CONTROL)
        else:
            self.output.data = var.data

        self.output.valid = var.valid
        return self.output
Ejemplo n.º 2
0
    def __init__(self,
                 fft_size,
                 twiddle_bits=9,
                 inverse=False,
                 input_ordering='natural'):
        self._pyha_simulation_input_callback = NumpyToDataValid(
            dtype=default_complex)
        self.INPUT_ORDERING = input_ordering
        self.INVERSE = inverse
        self.FFT_SIZE = fft_size
        self.N_STAGES = int(np.log2(fft_size))

        max_gain_control_stages = 10
        self.POST_GAIN_CONTROL = max(self.N_STAGES - max_gain_control_stages,
                                     0)

        self.stages = [
            StageR2SDF(self.FFT_SIZE,
                       i,
                       twiddle_bits,
                       inverse,
                       input_ordering,
                       allow_gain_control=i < max_gain_control_stages)
            for i in range(self.N_STAGES)
        ]

        self.output = DataValid(
            Complex(0, -self.POST_GAIN_CONTROL, -17 - self.POST_GAIN_CONTROL))
Ejemplo n.º 3
0
def test_all(input_power):
    dut = FFTPower()
    inp = (np.random.uniform(-1, 1, size=1280) +
           np.random.uniform(-1, 1, size=1280) * 1j) * input_power
    inp = [complex(Complex(x, 0, -17)) for x in inp]
    sims = simulate(dut,
                    inp,
                    pipeline_flush='auto',
                    simulations=['MODEL', 'HARDWARE'])
    assert sims_close(sims, rtol=1e-20, atol=1e-20)
Ejemplo n.º 4
0
    def __init__(self, cordic_iterations=14):
        """

        :param cordic_iterations:
        """
        self.cordic = Cordic(cordic_iterations, CordicMode.ROTATION)
        self.phase_acc = Sfix(0, 0, -17, wrap_is_ok=True)
        self.out = Complex(0, 0, -17, overflow_style='saturate')
        self.DELAY = self.cordic.ITERATIONS + 1 + 1
        self.INIT_X = 1.0 / 1.646760  # gets rid of cordic gain, could use for amplitude modulation
Ejemplo n.º 5
0
    def __init__(self, gain=1.0):
        """
        :param gain: inverse of tx sensitivity
        """
        self.gain = gain
        # components / registers
        precision = -35
        self.conjugate = Complex(0.0 + 0.0j, 0, -17, overflow_style='saturate')
        self.mult = Complex(0.0 + 0.0j, 0, precision)
        self.angle = Angle(precision=precision)
        self.y = Sfix(0, 0, -17, overflow_style='saturate')

        # pi term gets us to -1 to +1
        self.GAIN_SFIX = Sfix(gain * np.pi,
                              4,
                              -13,
                              round_style='round',
                              overflow_style='saturate')

        self.DELAY = 1 + 1 + self.angle.DELAY
Ejemplo n.º 6
0
    def main(self, c):
        """
        :type c: Complex
        :rtype: Sfix
        """
        self.conjugate = Complex(c.real, -c.imag)
        self.mult = c * self.conjugate
        # TODO: invalid data bug!
        angle = self.angle.main(self.mult)

        self.y = self.GAIN_SFIX * angle
        return self.y
Ejemplo n.º 7
0
    def main(self, phase_inc):
        """
        :param phase_inc: amount of rotation applied for next clock cycle, must be normalized to -1 to 1.
        :rtype: Complex
        """
        self.phase_acc = self.phase_acc + phase_inc

        start_x = self.INIT_X
        start_y = Sfix(0.0, 0, -17)

        x, y, phase = self.cordic.main(start_x, start_y, self.phase_acc)

        self.out = Complex(x, y)
        return self.out
Ejemplo n.º 8
0
def test_nonstandard_input_size():
    input_power = 0.0001
    dut = FFTPower()

    dtype = Complex(0, -4, -21, round_style='round')

    dut._pyha_simulation_input_callback = NumpyToDataValid(dtype)
    inp = (np.random.uniform(-1, 1, size=64) +
           np.random.uniform(-1, 1, size=64) * 1j) * input_power
    inp = [complex(dtype(x)) for x in inp]
    sims = simulate(dut,
                    inp,
                    pipeline_flush='auto',
                    conversion_path='/tmp/pyha_output')
    assert sims_close(sims, rtol=1e-20, atol=1e-20)
Ejemplo n.º 9
0
    def __init__(self, window_length, window='hanning', coefficient_bits=18):
        self._pyha_simulation_input_callback = NumpyToDataValid(
            dtype=default_complex)
        self.WINDOW_LENGTH = window_length
        self.window_pure = get_window(window, window_length)
        self.WINDOW = [
            Sfix(x,
                 0,
                 -(coefficient_bits - 1),
                 round_style='round',
                 overflow_style='saturate') for x in self.window_pure
        ]

        self.output = DataValid(Complex(0, 0, -17, round_style='round'))
        self.index_counter = 1
        self.coef = self.WINDOW[0]
Ejemplo n.º 10
0
def test_all(fft_size, avg_freq_axis, avg_time_axis, input_power):
    np.random.seed(0)
    input_size = (avg_time_axis) * fft_size
    if input_size < 1024:  # must be atleast DC-removal size?
        input_size = 1024
    orig_inp = (np.random.uniform(-1, 1, size=input_size) +
                np.random.uniform(-1, 1, size=input_size) * 1j) * input_power
    dut = Spectrogram(fft_size, avg_freq_axis, avg_time_axis)

    orig_inp_quant = np.vectorize(lambda x: complex(Complex(x, 0, -17)))(
        orig_inp)

    sims = simulate(dut,
                    orig_inp_quant,
                    pipeline_flush='auto',
                    simulations=['MODEL', 'HARDWARE'])
    assert sims_close(sims, rtol=1e-7, atol=1e-7)
Ejemplo n.º 11
0
    def __init__(self):
        self._pyha_simulation_input_callback = NumpyToDataValid(dtype=Complex(
            0.0, 0, -11, overflow_style='saturate', round_style='round'))

        # components
        fft_size = 1024 * 8
        avg_freq_axis = 16
        avg_time_axis = 8
        window_type = 'hamming'
        fft_twiddle_bits = 8
        window_bits = 8
        dc_removal_len = 1024
        self.spect = Spectrogram(fft_size, avg_freq_axis, avg_time_axis,
                                 window_type, fft_twiddle_bits, window_bits,
                                 dc_removal_len)
        # TODO: could be unsigned!
        self.output = DataValid(
            Sfix(0.0, upper_bits=32)
        )  # no need to round because result is positive i.e. truncation = rounding
Ejemplo n.º 12
0
def test_complex():
    class T(Hardware):
        def __init__(self, data):
            self.shr_new = ShiftRegister(data)
            self.shr_old = data

        def main(self, inp):
            self.shr_new.push_next(inp)
            self.shr_old = self.shr_old[1:] + [inp]
            return self.shr_new.peek(), self.shr_old[0]

    N = 128
    dut = T([Complex(0.0 + 0.0j, 0, -17) for _ in range(N)])

    inp = np.random.uniform(-1, 1,
                            N * 2) + np.random.uniform(-1, 1, N * 2) * 1j
    sims = simulate(dut, inp, simulations=['HARDWARE', 'RTL', 'NETLIST'])
    assert sims['HARDWARE'][0] == sims['HARDWARE'][1]
    assert sims_close(sims)
Ejemplo n.º 13
0
 def main(self, real, imag):
     self.out.data = scalb(Complex(real, imag), 4)
     self.out.valid = True
     return self.out
Ejemplo n.º 14
0
def resize(fix: Sfix,
           left=0,
           right=-17,
           size_res=None,
           overflow_style='wrap',
           round_style='truncate',
           wrap_is_ok=False,
           signed=None) -> Sfix:
    """
    Resize fixed point number.

    :param fix: Sfix object to resize
    :param left: new left bound
    :param right: new right bound
    :param size_res: provide another Sfix object as size reference
    :param overflow_style: 'wrap' or 'saturate'
    :param round_style: 'truncate' or 'round'
    :param wrap_is_ok: silences logging about WRAP
    :return: New resized Sfix object

    >>> a = Sfix(0.89, left=0, right=-17)
    >>> a
    0.8899993896484375 [0:-17]
    >>> b = resize(a, 0, -6)
    >>> b
    0.890625 [0:-6]

    >>> c = resize(a, size_res=b)
    >>> c
    0.890625 [0:-6]


    """
    if signed is None:
        signed = fix.signed
    try:
        return fix.resize(left,
                          right,
                          size_res,
                          overflow_style=overflow_style,
                          round_style=round_style,
                          wrap_is_ok=wrap_is_ok,
                          signed=signed)
    except:
        # fix is int/float
        if size_res:
            left = size_res.left
            right = size_res.right
        try:
            return Sfix(fix,
                        left,
                        right,
                        overflow_style=overflow_style,
                        round_style=round_style,
                        wrap_is_ok=wrap_is_ok,
                        signed=signed)
        except:
            from pyha import Complex
            return Complex(fix,
                           left,
                           right,
                           overflow_style=overflow_style,
                           round_style=round_style,
                           wrap_is_ok=wrap_is_ok,
                           signed=signed)
Ejemplo n.º 15
0
 def __init__(self):
     self.A = Complex()
Ejemplo n.º 16
0
 def main(self, complex_in):
     """ Apply FIR filters to 'real' and 'imag' channels """
     real = self.fir[0].main(complex_in.real)
     imag = self.fir[1].main(complex_in.imag)
     return Complex(real, imag)
Ejemplo n.º 17
0
 def __init__(self):
     self.out = DataValid(Complex(0, 0, -17, overflow_style='saturate'))
Ejemplo n.º 18
0
    def __init__(self):
        self._pyha_simulation_input_callback = NumpyToDataValid(
            dtype=Complex(0.0, 0, -11, overflow_style='saturate', round_style='round'))

        self.dc_removal = DCRemoval(window_len=2048)
        self.out = DataValid(Complex(0, 0, -15, round_style='round'))
Ejemplo n.º 19
0
    def __init__(self,
                 global_fft_size,
                 stage_nr,
                 twiddle_bits=18,
                 inverse=False,
                 input_ordering='natural',
                 allow_gain_control=True):
        self._pyha_simulation_input_callback = NumpyToDataValid(
            dtype=default_complex)

        self.ALLOW_GAIN_CONTROL = allow_gain_control
        self.INVERSE = inverse
        self.GLOBAL_FFT_SIZE = global_fft_size
        self.STAGE_NR = stage_nr
        self.INPUT_ORDERING = input_ordering

        if input_ordering == 'bitreversed':
            self.IS_NATURAL_ORDER = False
            self.INPUT_STRIDE = 2**stage_nr  # distance from butterfly input a to b
            self.LOCAL_FFT_SIZE = global_fft_size // self.INPUT_STRIDE
            self.CONTROL_MASK = (self.LOCAL_FFT_SIZE - 1)

            twid = [
                W(i, self.LOCAL_FFT_SIZE)
                for i in range(self.LOCAL_FFT_SIZE // 2)
            ]
            twid = toggle_bit_reverse(twid)
            twid = np.roll(twid, 1, axis=0)
            self.TWIDDLES = [
                Complex(x,
                        0,
                        -(twiddle_bits - 1),
                        overflow_style='saturate',
                        round_style='round') for x in twid
            ]

        elif input_ordering == 'natural':
            self.IS_NATURAL_ORDER = True
            self.LOCAL_FFT_SIZE = global_fft_size // 2**stage_nr
            self.INPUT_STRIDE = self.LOCAL_FFT_SIZE // 2
            self.CONTROL_MASK = (self.INPUT_STRIDE - 1)

            self.TWIDDLES = [
                Complex(W(i, self.LOCAL_FFT_SIZE),
                        0,
                        -(twiddle_bits - 1),
                        overflow_style='saturate',
                        round_style='round') for i in range(self.INPUT_STRIDE)
            ]

        self.IS_TRIVIAL_MULTIPLIER = len(
            self.TWIDDLES) == 1  # mult by 1.0, useless
        self.shr = ShiftRegister([Complex() for _ in range(self.INPUT_STRIDE)])
        self.twiddle = self.TWIDDLES[0]
        self.stage1_out = Complex(0, 0, -17)
        self.stage2_out = Complex(0, 0, -17 - (twiddle_bits - 1))
        self.output_index = 0
        self.mode_delay = False
        self.control = 0  # replacing this with fixed-point counter saves no resources..

        self.out = DataValid(Complex(0, 0, -17, round_style='round'),
                             valid=False)
        self.start_counter = DownCounter(2 + self.INPUT_STRIDE)