def test_sample_and_hold_ff(self):
        src_data1 = tuple([i for i in range(10)])
        src_data2 =       (0, 0, 1, 1, 0, 1, 0, 0, 1, 1)
        expected_result = (0, 0, 2, 3, 3, 5, 5, 5, 8, 9)

        src1 = gr.vector_source_f(src_data1)
        src2 = gr.vector_source_b(src_data2)
        op = gr.sample_and_hold_ff()
        dst = gr.vector_sink_f()

        self.tb.connect(src1, op)
        self.tb.connect(src2, op)
        self.tb.connect(op, dst)
        self.tb.run()
        result_data = dst.data()

        self.assertFloatTuplesAlmostEqual(expected_result, result_data)
    def test_sample_and_hold_ff(self):
        src_data1 = tuple([i for i in range(10)])
        src_data2 = (0, 0, 1, 1, 0, 1, 0, 0, 1, 1)
        expected_result = (0, 0, 2, 3, 3, 5, 5, 5, 8, 9)

        src1 = gr.vector_source_f(src_data1)
        src2 = gr.vector_source_b(src_data2)
        op = gr.sample_and_hold_ff()
        dst = gr.vector_sink_f()

        self.tb.connect(src1, op)
        self.tb.connect(src2, op)
        self.tb.connect(op, dst)
        self.tb.run()
        result_data = dst.data()

        self.assertFloatTuplesAlmostEqual(expected_result, result_data)
Example #3
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()

        # Modified by Yong (12.06.27)
        #movingsum2_taps = [1.0 for i in range(fft_length//2)]
        movingsum2_taps = [0.5 for i in range(fft_length)]

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))

        # Get the power of the input signal to normalize the output of the correlation
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
        self.connect(self.c2mag, (self.normalize,0))

        # Create a moving sum filter for the corr output
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
        
        self.connect(self.matched_filter, self.sub1, self.pk_detect)
        #self.connect(self.matched_filter, self.pk_detect)
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-nominator_f.dat"))
            self.connect(self.square, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-denominator_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #4
0
    def __init__(self, fft_length, cp_length, half_sync, logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char  # timing indicator
            ))

        if half_sync:
            period = fft_length / 2
            window = fft_length / 2
        else:  # full symbol
            period = fft_length + cp_length
            window = fft_length  # makes the plateau cp_length long

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = gr.multiply_cc()
        self.connect(self, gr.conjugate_cc(), (x_corr, 0))
        self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
        P_d = gr.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        P_d_angle = gr.complex_to_arg()
        self.connect(P_d, P_d_angle)

        # Get the power of the input signal to normalize the output of the correlation
        R_d = gr.moving_average_ff(window, 1.0)
        self.connect(self, gr.complex_to_mag_squared(), R_d)
        R_d_squared = gr.multiply_ff()  # this is retarded
        self.connect(R_d, (R_d_squared, 0))
        self.connect(R_d, (R_d_squared, 1))
        M_d = gr.divide_ff()
        self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
        self.connect(R_d_squared, (M_d, 1))

        # Now we need to detect peak of M_d

        # NOTE: replaced fir_filter with moving_average for clarity
        # the peak is up to cp_length long, but noisy, so average it out
        #matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        #matched_filter = gr.fir_filter_fff(1, matched_filter_taps)
        matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length)

        # NOTE: the look_ahead parameter doesn't do anything
        # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
        #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001)
        peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001)
        # NOTE: gr.peak_detector_fb is broken!
        #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001)
        #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001)
        #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001)

        # offset by -1
        self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)

        # peak_detect indicates the time M_d is highest, which is the end of the symbol.
        # We should try to sample in the middle of the plateau!!
        # FIXME until we figure out how to do this, just offset by cp_length/2
        offset = 6  #cp_length/2

        # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
        # modulate input(t - fft_length) by nco(t)
        # signal to sample input(t) at t-offset
        #
        # We can't delay by < 0 so instead:
        # input is delayed by fft_length
        # P_d_angle is delayed by offset
        # signal to sample is delayed by fft_length - offset
        #
        phi = gr.sample_and_hold_ff()
        self.connect(peak_detect, (phi, 1))
        self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0))
        #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!?

        # FIXME: we add fft_length delay so that the preamble is nco corrected too
        # BUT is this buffering worth it? consider implementing sync as a proper block

        # delay the input signal to follow the frequency offset signal
        self.connect(self, gr.delay(gr.sizeof_gr_complex,
                                    (fft_length + offset)), (self, 0))
        self.connect(phi, (self, 1))
        self.connect(peak_detect, (self, 2))

        if logging:
            self.connect(matched_filter,
                         gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
            self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
            self.connect(P_d_angle,
                         gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
            self.connect(peak_detect,
                         gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
            self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
    def __init__(self, fft_length, cp_length, kstime, logging=False):
        """
        OFDM synchronization using PN Correlation and initial cross-correlation:
        F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using
        PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207.

        This implementation is meant to be a more robust version of the Schmidl and Cox receiver design.
        By correlating against the preamble and using that as the input to the time-delayed correlation,
        this circuit produces a very clean timing signal at the end of the preamble. The timing is 
        more accurate and does not have the problem associated with determining the timing from the
        plateau structure in the Schmidl and Cox.

        This implementation appears to require that the signal is received with a normalized power or signal
        scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and
        the peak detection. A better peak detection block might fix this.

        Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails
        when an integer offset is introduced. Another thing to look at.
        """

	gr.hier_block2.__init__(self, "ofdm_sync_pnac",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

            
        self.input = gr.add_const_cc(0)

        symbol_length = fft_length + cp_length

        # PN Sync with cross-correlation input

        # cross-correlate with the known symbol
        kstime = [k.conjugate() for k in kstime[0:fft_length//2]]
        kstime.reverse()
        self.crosscorr_filter = filter.fir_filter_ccc(1, kstime)
        
        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the input
        self.mag = gr.complex_to_mag_squared()
        movingsum_taps = (fft_length//1)*[1.0,]
        self.power = filter.fir_filter_fff(1,movingsum_taps)
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()
        self.compare = gr.sub_ff()
        
        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.threshold = gr.threshold_ff(0,0,0)      # threshold detection might need to be tweaked
        self.peaks = gr.float_to_char()

        self.connect(self, self.input)

        # Cross-correlate input signal with known preamble
        self.connect(self.input, self.crosscorr_filter)

        # use the output of the cross-correlation as input time-shifted correlation
        self.connect(self.crosscorr_filter, self.delay)
        self.connect(self.crosscorr_filter, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.c2mag)
        self.connect(self.corr, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))
        
        # Get the power of the input signal to compare against the correlation
        self.connect(self.crosscorr_filter, self.mag, self.power)

        # Compare the power to the correlator output to determine timing peak
        # When the peak occurs, it peaks above zero, so the thresholder detects this
        self.connect(self.c2mag, (self.compare,0))
        self.connect(self.power, (self.compare,1))
        self.connect(self.compare, self.threshold)
        self.connect(self.threshold, self.peaks, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.peaks, (self,1))

        if logging:
            self.connect(self.compare, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat"))
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat"))
            self.connect(self.power, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-inputpower_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat"))
            self.connect(self.threshold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-threshold_f.dat"))
            self.connect(self.peaks, gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pnac-input_c.dat"))
    def __init__(self, fft_length, cp_length, snr, kstime, logging):
        ''' Maximum Likelihood OFDM synchronizer:
        J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation
        of Time and Frequency Offset in OFDM Systems," IEEE Trans.
        Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997.
        '''

	gr.hier_block2.__init__(self, "ofdm_sync_ml",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        SNR = 10.0**(snr/10.0)
        rho = SNR / (SNR + 1.0)
        symbol_length = fft_length + cp_length

        # ML Sync

        # Energy Detection from ML Sync

        self.connect(self, self.input)

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
        self.connect(self.input, self.delay)

        # magnitude squared blocks
        self.magsqrd1 = gr.complex_to_mag_squared()
        self.magsqrd2 = gr.complex_to_mag_squared()
        self.adder = gr.add_ff()

        moving_sum_taps = [rho/2 for i in range(cp_length)]
        self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
        
        self.connect(self.input,self.magsqrd1)
        self.connect(self.delay,self.magsqrd2)
        self.connect(self.magsqrd1,(self.adder,0))
        self.connect(self.magsqrd2,(self.adder,1))
        self.connect(self.adder,self.moving_sum_filter)
        

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.mixer = gr.multiply_cc();

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
        
        # Correlator data handler
        self.c2mag = gr.complex_to_mag()
        self.angle = gr.complex_to_arg()
        self.connect(self.input,(self.mixer,1))
        self.connect(self.delay,self.conjg,(self.mixer,0))
        self.connect(self.mixer,self.movingsum2,self.c2mag)
        self.connect(self.movingsum2,self.angle)

        # ML Sync output arg, need to find maximum point of this
        self.diff = gr.sub_ff()
        self.connect(self.c2mag,(self.diff,0))
        self.connect(self.moving_sum_filter,(self.diff,1))

        #ML measurements input to sampler block and detect
        self.f2c = gr.float_to_complex()
        self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
        self.sample_and_hold = gr.sample_and_hold_ff()

        # use the sync loop values to set the sampler and the NCO
        #     self.diff = theta
        #     self.angle = epsilon
                          
        self.connect(self.diff, self.pk_detect)

        # The DPLL corrects for timing differences between CP correlations
        use_dpll = 0
        if use_dpll:
            self.dpll = gr.dpll_bb(float(symbol_length),0.01)
            self.connect(self.pk_detect, self.dpll)
            self.connect(self.dpll, (self.sample_and_hold,1))
        else:
            self.connect(self.pk_detect, (self.sample_and_hold,1))
            
        self.connect(self.angle, (self.sample_and_hold,0))

        ################################
        # correlate against known symbol
        # This gives us the same timing signal as the PN sync block only on the preamble
        # we don't use the signal generated from the CP correlation because we don't want
        # to readjust the timing in the middle of the packet or we ruin the equalizer settings.
        kstime = [k.conjugate() for k in kstime]
        kstime.reverse()
        self.kscorr = gr.fir_filter_ccc(1, kstime)
        self.corrmag = gr.complex_to_mag_squared()
        self.div = gr.divide_ff()

        # The output signature of the correlation has a few spikes because the rest of the
        # system uses the repeated preamble symbol. It needs to work that generically if 
        # anyone wants to use this against a WiMAX-like signal since it, too, repeats.
        # The output theta of the correlator above is multiplied with this correlation to
        # identify the proper peak and remove other products in this cross-correlation
        self.threshold_factor = 0.1
        self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0)
        self.f2b = gr.float_to_char()
        self.b2f = gr.char_to_float()
        self.mul = gr.multiply_ff()
        
        # Normalize the power of the corr output by the energy. This is not really needed
        # and could be removed for performance, but it makes for a cleaner signal.
        # if this is removed, the threshold value needs adjustment.
        self.connect(self.input, self.kscorr, self.corrmag, (self.div,0))
        self.connect(self.moving_sum_filter, (self.div,1))
        
        self.connect(self.div, (self.mul,0))
        self.connect(self.pk_detect, self.b2f, (self.mul,1))
        self.connect(self.mul, self.slice)
        
        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.slice, self.f2b, (self,1))


        if logging:
            self.connect(self.moving_sum_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat"))
            self.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat"))
            self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat"))
            self.connect(self.kscorr, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat"))
            self.connect(self.div, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat"))
            self.connect(self.mul, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat"))
            self.connect(self.slice, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
            if use_dpll:
                self.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))

            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
Example #7
0
    def __init__(self, fft_length, cp_length, half_sync, kstime, ks1time, threshold, logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char,  # timing indicator
            ),
        )

        if half_sync:
            period = fft_length / 2
            window = fft_length / 2
        else:  # full symbol
            period = fft_length + cp_length
            window = fft_length  # makes the plateau cp_length long

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = gr.multiply_cc()
        self.connect(self, gr.conjugate_cc(), (x_corr, 0))
        self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
        P_d = gr.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        # offset by -1
        phi = gr.sample_and_hold_ff()
        self.corrmag = gr.complex_to_mag_squared()
        P_d_angle = gr.complex_to_arg()
        self.connect(P_d, P_d_angle, (phi, 0))

        cross_correlate = 1
        if cross_correlate == 1:
            # cross-correlate with the known symbol
            kstime = [k.conjugate() for k in kstime]
            kstime.reverse()
            self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

            """
        self.f2b = gr.float_to_char()
        self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length)
        #self.connect(self, self.crosscorr_filter, self.corrmag, self.slice, self.f2b)
	self.connect(self.f2b, (phi,1))
	self.connect(self.f2b, (self,2))
	self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))
	"""

            # new method starts here - only crosscorrelate and use peak_detect block #
            peak_detect = gr.peak_detector_fb(100, 100, 30, 0.001)
            self.corrmag1 = gr.complex_to_mag_squared()
            self.connect(self, self.crosscorr_filter, self.corrmag, peak_detect)

            self.connect(peak_detect, (phi, 1))
            self.connect(peak_detect, (self, 2))

            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat"))
            self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
            self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self, 0))

        else:
            # Get the power of the input signal to normalize the output of the correlation
            R_d = gr.moving_average_ff(window, 1.0)
            self.connect(self, gr.complex_to_mag_squared(), R_d)
            R_d_squared = gr.multiply_ff()  # this is retarded
            self.connect(R_d, (R_d_squared, 0))
            self.connect(R_d, (R_d_squared, 1))
            M_d = gr.divide_ff()
            self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
            self.connect(R_d_squared, (M_d, 1))

            # Now we need to detect peak of M_d
            matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length)
            peak_detect = gr.peak_detector_fb(0.25, 0.25, 30, 0.001)
            self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)
            offset = cp_length / 2  # cp_length/2
            self.connect(peak_detect, (phi, 1))
            self.connect(peak_detect, (self, 2))
            self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0))
            self.connect(
                self, gr.delay(gr.sizeof_gr_complex, (fft_length + offset)), (self, 0)
            )  # delay the input to follow the freq offset
            self.connect(peak_detect, gr.delay(gr.sizeof_char, (fft_length + offset)), (self, 2))
            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat"))
            self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))

        self.connect(phi, (self, 1))

        if logging:
            self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
            self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
            self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
            self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
Example #8
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length//2)]

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        #self.sub1 = gr.add_const_ff(-1)
        self.sub1 = gr.add_const_ff(0)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))

        # Get the power of the input signal to normalize the output of the correlation
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
        self.connect(self.c2mag, (self.normalize,0))

        # Create a moving sum filter for the corr output
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
        
        self.connect(self.matched_filter, self.sub1, self.pk_detect)
        #self.connect(self.matched_filter, self.pk_detect)
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #9
0
    def __init__(self, fft_length, cp_length, kstime, logging=False):
        """
        OFDM synchronization using PN Correlation and initial cross-correlation:
        F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using
        PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207.

        This implementation is meant to be a more robust version of the Schmidl and Cox receiver design.
        By correlating against the preamble and using that as the input to the time-delayed correlation,
        this circuit produces a very clean timing signal at the end of the preamble. The timing is 
        more accurate and does not have the problem associated with determining the timing from the
        plateau structure in the Schmidl and Cox.

        This implementation appears to require that the signal is received with a normalized power or signal
        scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and
        the peak detection. A better peak detection block might fix this.

        Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails
        when an integer offset is introduced. Another thing to look at.
        """

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pnac",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2, 2, gr.sizeof_float,
                             gr.sizeof_char))  # Output signature

        self.input = gr.add_const_cc(0)

        symbol_length = fft_length + cp_length

        # PN Sync with cross-correlation input

        # cross-correlate with the known symbol
        kstime = [k.conjugate() for k in kstime[0:fft_length // 2]]
        kstime.reverse()
        self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc()
        self.corr = gr.multiply_cc()

        # Create a moving sum filter for the input
        self.mag = gr.complex_to_mag_squared()
        movingsum_taps = (fft_length // 1) * [
            1.0,
        ]
        self.power = gr.fir_filter_fff(1, movingsum_taps)

        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()
        self.compare = gr.sub_ff()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.threshold = gr.threshold_ff(
            0, 0, 0)  # threshold detection might need to be tweaked
        self.peaks = gr.float_to_char()

        self.connect(self, self.input)

        # Cross-correlate input signal with known preamble
        self.connect(self.input, self.crosscorr_filter)

        # use the output of the cross-correlation as input time-shifted correlation
        self.connect(self.crosscorr_filter, self.delay)
        self.connect(self.crosscorr_filter, (self.corr, 0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr, 1))
        self.connect(self.corr, self.c2mag)
        self.connect(self.corr, self.angle)
        self.connect(self.angle, (self.sample_and_hold, 0))

        # Get the power of the input signal to compare against the correlation
        self.connect(self.crosscorr_filter, self.mag, self.power)

        # Compare the power to the correlator output to determine timing peak
        # When the peak occurs, it peaks above zero, so the thresholder detects this
        self.connect(self.c2mag, (self.compare, 0))
        self.connect(self.power, (self.compare, 1))
        self.connect(self.compare, self.threshold)
        self.connect(self.threshold, self.peaks, (self.sample_and_hold, 1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self, 0))
        self.connect(self.peaks, (self, 1))

        if logging:
            self.connect(
                self.compare,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat"))
            self.connect(
                self.c2mag,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat"))
            self.connect(
                self.power,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pnac-inputpower_f.dat"))
            self.connect(
                self.angle,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat"))
            self.connect(
                self.threshold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pnac-threshold_f.dat"))
            self.connect(
                self.peaks,
                gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pnac-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                gr.file_sink(gr.sizeof_gr_complex,
                             "ofdm_sync_pnac-input_c.dat"))
Example #10
0
  def __init__(self, fft_length, cp_length, half_sync, logging=False):
    gr.hier_block2.__init__(self, "ofdm_sync_pn",
      gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
      gr.io_signature3(3, 3,    # Output signature
        gr.sizeof_gr_complex,   # delayed input
        gr.sizeof_float,        # fine frequency offset
        gr.sizeof_char          # timing indicator
      ))

    if half_sync:
      period = fft_length/2
      window = fft_length/2
    else: # full symbol
      period = fft_length + cp_length
      window = fft_length       # makes the plateau cp_length long

    # Calculate the frequency offset from the correlation of the preamble
    x_corr = gr.multiply_cc()
    self.connect(self, gr.conjugate_cc(), (x_corr, 0))
    self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
    P_d = gr.moving_average_cc(window, 1.0)
    self.connect(x_corr, P_d)

    P_d_angle = gr.complex_to_arg()
    self.connect(P_d, P_d_angle)

    # Get the power of the input signal to normalize the output of the correlation
    R_d = gr.moving_average_ff(window, 1.0)
    self.connect(self, gr.complex_to_mag_squared(), R_d)
    R_d_squared = gr.multiply_ff() # this is retarded
    self.connect(R_d, (R_d_squared, 0))
    self.connect(R_d, (R_d_squared, 1))
    M_d = gr.divide_ff()
    self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
    self.connect(R_d_squared, (M_d, 1))

    # Now we need to detect peak of M_d

    # NOTE: replaced fir_filter with moving_average for clarity
    # the peak is up to cp_length long, but noisy, so average it out
    #matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
    #matched_filter = gr.fir_filter_fff(1, matched_filter_taps)
    matched_filter = gr.moving_average_ff(cp_length, 1.0/cp_length)

    # NOTE: the look_ahead parameter doesn't do anything
    # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
    #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001)
    peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001)
    # NOTE: gr.peak_detector_fb is broken!
    #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001)
    #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001)
    #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001)

    # offset by -1
    self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)

    # peak_detect indicates the time M_d is highest, which is the end of the symbol.
    # We should try to sample in the middle of the plateau!!
    # FIXME until we figure out how to do this, just offset by cp_length/2
    offset = 6 #cp_length/2

    # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
    # modulate input(t - fft_length) by nco(t)
    # signal to sample input(t) at t-offset
    #
    # We can't delay by < 0 so instead:
    # input is delayed by fft_length
    # P_d_angle is delayed by offset
    # signal to sample is delayed by fft_length - offset
    #
    phi = gr.sample_and_hold_ff()
    self.connect(peak_detect, (phi,1))
    self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi,0))
    #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!?

    # FIXME: we add fft_length delay so that the preamble is nco corrected too
    # BUT is this buffering worth it? consider implementing sync as a proper block

    # delay the input signal to follow the frequency offset signal
    self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length+offset)), (self,0))
    self.connect(phi, (self,1))
    self.connect(peak_detect, (self,2))

    if logging:
      self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
      self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
      self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
      self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
      self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
    def __init__(self, fft_length, cp_length, kstime, threshold, threshold_type, threshold_gap, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length//2)]
	#movingsum2_taps = [0.5 for i in range(fft_length*4)]		#apurv - implementing Veljo's suggestion, when pause b/w packets

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)	#apurv - implementing Veljo's suggestion, when pause b/w packets

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))


        self.connect(self.corr, self.moving_sum_filter)
        #self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))		# apurv--
	#self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0))	#apurv++

	cross_correlate = 1
	if cross_correlate==1:
	   # cross-correlate with the known symbol
	   kstime = [k.conjugate() for k in kstime]
           kstime.reverse()
           self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

	   # get the magnitude #
	   self.corrmag = gr.complex_to_mag_squared()

	   self.f2b = gr.float_to_char()
	   self.threshold_factor = threshold #0.0012 #0.012   #0.0015
	   if 0:
	      self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0, fft_length)
	   else:
	      #thresholds = [self.threshold_factor, 9e-5]
	      self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length, threshold_type, threshold_gap)

	   self.connect(self.input, self.crosscorr_filter, self.corrmag, self.slice, self.f2b)

	   # some debug dump #
	   self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
	   #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))
	   

	self.connect(self.f2b, (self.sample_and_hold,1))
	
        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
	#self.connect(self.pk_detect, (self,1))									#removed
	#self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1))
	self.connect(self.f2b, (self, 1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #12
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 kstime,
                 threshold,
                 threshold_type,
                 threshold_gap,
                 logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2, 2, gr.sizeof_float,
                             gr.sizeof_char))  # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc()
        self.corr = gr.multiply_cc()

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length // 2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1, moving_sum_taps)
        else:
            moving_sum_taps = [
                complex(1.0, 0.0) for i in range(fft_length // 2)
            ]
            self.moving_sum_filter = gr.fft_filter_ccc(1, moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length // 2)]
        #movingsum2_taps = [0.5 for i in range(fft_length*4)]		#apurv - implementing Veljo's suggestion, when pause b/w packets

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1, movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1, movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()

        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(
            0.20, 0.20, 30, 0.001
        )  #apurv - implementing Veljo's suggestion, when pause b/w packets

        self.connect(self, self.input)

        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr, 0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr, 1))

        self.connect(self.corr, self.moving_sum_filter)
        #self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold, 0))  # apurv--
        #self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0))	#apurv++

        cross_correlate = 1
        if cross_correlate == 1:
            # cross-correlate with the known symbol
            kstime = [k.conjugate() for k in kstime]
            kstime.reverse()
            self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

            # get the magnitude #
            self.corrmag = gr.complex_to_mag_squared()

            self.f2b = gr.float_to_char()
            self.threshold_factor = threshold  #0.0012 #0.012   #0.0015
            if 0:
                self.slice = gr.threshold_ff(self.threshold_factor,
                                             self.threshold_factor, 0,
                                             fft_length)
            else:
                #thresholds = [self.threshold_factor, 9e-5]
                self.slice = gr.threshold_ff(threshold, threshold, 0,
                                             fft_length, threshold_type,
                                             threshold_gap)

            self.connect(self.input, self.crosscorr_filter, self.corrmag,
                         self.slice, self.f2b)

            # some debug dump #
            self.connect(self.corrmag,
                         gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
            #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))

        self.connect(self.f2b, (self.sample_and_hold, 1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self, 0))
        #self.connect(self.pk_detect, (self,1))									#removed
        #self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1))
        self.connect(self.f2b, (self, 1))

        if logging:
            self.connect(
                self.matched_filter,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(
                self.normalize,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(
                self.angle,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(
                self.pk_detect,
                gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #13
0
    def __init__(self, mode, debug=False):
        """
		OFDM time and coarse frequency synchronisation for DAB

		@param mode DAB mode (1-4)
		@param debug if True: write data streams out to files
		"""

        if mode < 1 or mode > 4:
            raise ValueError, "Invalid DAB mode: " + str(
                mode) + " (modes 1-4 exist)"

        # get the correct DAB parameters
        dp = parameters.dab_parameters(mode)
        rp = parameters.receiver_parameters(mode)

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_dab",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # input signature
            gr.io_signature2(2, 2, gr.sizeof_gr_complex,
                             gr.sizeof_char))  # output signature

        # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
        self.input = gr.kludge_copy(gr.sizeof_gr_complex)
        self.connect(self, self.input)

        #
        # null-symbol detection
        #
        # (outsourced to detect_zero.py)

        self.ns_detect = detect_null.detect_null(dp.ns_length, debug)
        self.connect(self.input, self.ns_detect)

        #
        # fine frequency synchronisation
        #

        # the code for fine frequency synchronisation is adapted from
        # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine
        # frequency error, as suggested in "ML Estimation of Timing and
        # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek,
        # Magnus Sandell, Per Ola Börjesson, see
        # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html

        self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length)
        self.ffs_conj = gr.conjugate_cc()
        self.ffs_mult = gr.multiply_cc()
        # self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length)
        self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length)
        self.ffs_angle = gr.complex_to_arg()
        self.ffs_angle_scale = gr.multiply_const_ff(1. / dp.fft_length)
        self.ffs_delay_sample_and_hold = gr.delay(
            gr.sizeof_char,
            dp.symbol_length)  # sample the value at the end of the symbol ..
        self.ffs_sample_and_hold = gr.sample_and_hold_ff()
        self.ffs_delay_input_for_correction = gr.delay(
            gr.sizeof_gr_complex, dp.symbol_length
        )  # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself
        self.ffs_nco = gr.frequency_modulator_fc(
            1)  # ffs_sample_and_hold directly outputs phase error per sample
        self.ffs_mixer = gr.multiply_cc()

        # calculate fine frequency error
        self.connect(self.input, self.ffs_conj, self.ffs_mult)
        self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1))
        self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle)
        # only use the value from the first half of the first symbol
        self.connect(self.ffs_angle, self.ffs_angle_scale,
                     (self.ffs_sample_and_hold, 0))
        self.connect(self.ns_detect, self.ffs_delay_sample_and_hold,
                     (self.ffs_sample_and_hold, 1))
        # do the correction
        self.connect(self.ffs_sample_and_hold, self.ffs_nco,
                     (self.ffs_mixer, 0))
        self.connect(self.input, self.ffs_delay_input_for_correction,
                     (self.ffs_mixer, 1))

        # output - corrected signal and start of DAB frames
        self.connect(self.ffs_mixer, (self, 0))
        self.connect(self.ffs_delay_sample_and_hold, (self, 1))

        if debug:
            self.connect(
                self.ffs_angle,
                gr.file_sink(gr.sizeof_float,
                             "debug/ofdm_sync_dab_ffs_angle.dat"))
            self.connect(
                self.ffs_sample_and_hold,
                gr.multiply_const_ff(1. / (dp.T * 2 * pi)),
                gr.file_sink(gr.sizeof_float,
                             "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
            self.connect(
                self.ffs_mixer,
                gr.file_sink(gr.sizeof_gr_complex,
                             "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
Example #14
0
	def __init__(self, mode, debug=False):
		"""
		OFDM time and coarse frequency synchronisation for DAB

		@param mode DAB mode (1-4)
		@param debug if True: write data streams out to files
		"""

		if mode<1 or mode>4:
			raise ValueError, "Invalid DAB mode: "+str(mode)+" (modes 1-4 exist)"

		# get the correct DAB parameters
		dp = parameters.dab_parameters(mode)
		rp = parameters.receiver_parameters(mode)
		
		gr.hier_block2.__init__(self,"ofdm_sync_dab",
		                        gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature
					gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature

		# workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
		self.input = gr.kludge_copy(gr.sizeof_gr_complex)
		self.connect(self, self.input)

		#
		# null-symbol detection
		#
		# (outsourced to detect_zero.py)
		
		self.ns_detect = detect_null.detect_null(dp.ns_length, debug)
		self.connect(self.input, self.ns_detect)

		#
		# fine frequency synchronisation
		#

		# the code for fine frequency synchronisation is adapted from
		# ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine
		# frequency error, as suggested in "ML Estimation of Timing and
		# Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek,
		# Magnus Sandell, Per Ola Börjesson, see
		# http://www.sm.luth.se/csee/sp/research/report/bsb96r.html

		self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length)
		self.ffs_conj = gr.conjugate_cc()
		self.ffs_mult = gr.multiply_cc()
		# self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length)
		self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length)
		self.ffs_angle = gr.complex_to_arg()
		self.ffs_angle_scale = gr.multiply_const_ff(1./dp.fft_length)
		self.ffs_delay_sample_and_hold = gr.delay(gr.sizeof_char, dp.symbol_length) # sample the value at the end of the symbol ..
		self.ffs_sample_and_hold = gr.sample_and_hold_ff()
		self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself
		self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample
		self.ffs_mixer = gr.multiply_cc()

		# calculate fine frequency error
		self.connect(self.input, self.ffs_conj, self.ffs_mult)
		self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1))
		self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle)
		# only use the value from the first half of the first symbol
		self.connect(self.ffs_angle, self.ffs_angle_scale, (self.ffs_sample_and_hold, 0))
		self.connect(self.ns_detect, self.ffs_delay_sample_and_hold, (self.ffs_sample_and_hold, 1))
		# do the correction
		self.connect(self.ffs_sample_and_hold, self.ffs_nco, (self.ffs_mixer, 0))
		self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1))

		# output - corrected signal and start of DAB frames
		self.connect(self.ffs_mixer, (self, 0))
		self.connect(self.ffs_delay_sample_and_hold, (self, 1))

		if debug:
			self.connect(self.ffs_angle, gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_ffs_angle.dat"))
			self.connect(self.ffs_sample_and_hold, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
			self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))