Exemple #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
Exemple #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))
Exemple #3
0
    def __init__(self, window_len, dtype=Sfix):
        self._pyha_simulation_input_callback = NumpyToDataValid(
            dtype=dtype.default())

        self.WINDOW_LEN = window_len
        self.BIT_GROWTH = int(np.log2(window_len))

        self.shr = ShiftRegister([dtype()] * self.WINDOW_LEN)
        self.acc = dtype(0.0, self.BIT_GROWTH, -17)

        self.output = DataValid(
            dtype(0, 0, -17,
                  round_style='round'))  # negative trend without rounding!
        self.start_counter = DownCounter(1)
Exemple #4
0
    def __init__(self, window_len, dtype=Complex):
        assert window_len > 2
        self._pyha_simulation_input_callback = NumpyToDataValid(
            dtype=dtype.default())

        self.WINDOW_LEN = window_len
        self.averages = [
            MovingAverage(window_len, dtype),
            MovingAverage(window_len, dtype)
        ]

        # input must be delayed by group delay, we can use the SHR from the first averager to get the majority of the delay.
        self.delayed_input = ShiftRegister([dtype(0.0, 0, -17)] * 3)
        self.output = DataValid(dtype(0, 0, -17))
Exemple #5
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]
Exemple #6
0
    def main(self, input):
        """
        Args:
            input (DataValid): type not restricted

        Returns:
            DataValid: Lowest 36 bits from the result.
                Example: Input is 18 bits with format 0:-17, then output is 36 bits 1:-34

        """
        if not input.valid:
            return DataValid(self.output.data, valid=False)

        # (a + bi)(a - bi) = a**2 + b**2
        self.output.data = (input.data.real * input.data.real) + (
            input.data.imag * input.data.imag)
        self.output.valid = input.valid
        return self.output
Exemple #7
0
    def main(self, input):
        """
        Args:
            input (DataValid): -1.0 ... 1.0 range, up to 18 bits

        Returns:
            DataValid: Result rounded to 18 bits(-1.0 ... 1.0 range). Overflow impossible.

        """
        if not input.valid:
            return DataValid(self.output.data, valid=False)

        self.index_counter = (self.index_counter + 1) % self.WINDOW_LENGTH
        self.coef = self.WINDOW[self.index_counter]

        self.output.data = input.data * self.coef
        self.output.valid = input.valid
        return self.output
Exemple #8
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
Exemple #9
0
    def main(self, input):
        """
        Args:
            input (DataValid): -1.0 ... 1.0 range, up to 18 bits

        Returns:
            DataValid: Accumulator scaled and rounded to 18 bits(-1.0 ... 1.0 range). Overflow impossible.

        """
        if not input.valid:
            return DataValid(self.output.data, valid=False)

        self.shr.push_next(input.data)  # add new element to shift register
        self.acc = self.acc + input.data - self.shr.peek()
        self.output.data = scalb(
            self.acc, -self.BIT_GROWTH)  # round to standard 18bit format

        # make sure we don't propagate invalid samples
        self.start_counter.tick()
        self.output.valid = self.start_counter.is_over()
        return self.output
Exemple #10
0
    def main(self, input):
        """
        Args:
            input (DataValid): -1.0 ... 1.0 range, up to 18 bits

        Returns:
            DataValid:  DC-free output, 18 bits(-1.0 ... 1.0 range). Saturates on overflow.
                        Rounding it down to 12-bits (standard SDR IQ width) wont work,
                        you need ~16 bits to reliably remove the DC-offset.

        """
        avg_out = self.averages[1].main(self.averages[0].main(input))

        if not avg_out.valid:
            return DataValid(self.output.data, valid=False)

        # delay input -> use averager[0] delay to save alot of RAM
        self.delayed_input.push_next(self.averages[0].shr.peek())
        self.output.data = self.delayed_input.peek() - avg_out.data
        self.output.valid = True
        return self.output
Exemple #11
0
    def main(self, inp):
        if not inp.valid:
            return DataValid(self.out.data, valid=False)

        # Stage 1: handle the loopback memory; that sets the INPUT_STRIDE; also fetch the twiddle factor for stage 2
        if self.IS_NATURAL_ORDER:
            self.control = (self.control + 1) % (self.LOCAL_FFT_SIZE)
            self.twiddle = self.TWIDDLES[self.control & self.CONTROL_MASK]
        else:
            self.control = (self.control + 1) % (self.GLOBAL_FFT_SIZE)
            self.twiddle = self.TWIDDLES[self.control >> (self.STAGE_NR + 1)]
        mode = not (self.control & self.INPUT_STRIDE)
        self.mode_delay = mode
        if mode:
            self.shr.push_next(inp.data)
            self.stage1_out = self.shr.peek()
        else:
            up, down = self.butterfly(self.shr.peek(), inp.data)
            self.shr.push_next(down)
            self.stage1_out = up

        # Stage 2: complex multiply
        if self.mode_delay and not self.IS_TRIVIAL_MULTIPLIER:
            self.stage2_out = self.stage1_out * self.twiddle
        else:
            self.stage2_out = self.stage1_out

        # Stage 3: gain control and rounding
        if self.ALLOW_GAIN_CONTROL and not self.INVERSE:
            self.out.data = scalb(self.stage2_out, -1)
        else:
            self.out.data = self.stage2_out

        self.start_counter.tick()
        self.out.valid = self.start_counter.is_over()
        return self.out
Exemple #12
0
 def __init__(self):
     self._pyha_simulation_input_callback = NumpyToDataValid(
         dtype=default_complex)
     self.output = DataValid(Sfix(bits=36))
Exemple #13
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)
Exemple #14
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'))
Exemple #15
0
 def __init__(self):
     self.out = DataValid(Complex(0, 0, -17, overflow_style='saturate'))