diff options
author | Johnathan Corgan <johnathan@corganlabs.com> | 2014-07-21 14:38:14 -0700 |
---|---|---|
committer | Johnathan Corgan <johnathan@corganlabs.com> | 2014-07-21 14:38:14 -0700 |
commit | 2ece28b3fea5b27baa6a6858e7645467d75cbd11 (patch) | |
tree | b551a463d785aa4346442cd45ea7aaca73feaaa6 /gr-dtv/lib/atsc/atsc_sync_impl.cc | |
parent | dbbc0687b7323c86eb2b1c2d7524ff212bbd64d8 (diff) |
dtv: move ATSC blocks into lib/atsc
Diffstat (limited to 'gr-dtv/lib/atsc/atsc_sync_impl.cc')
-rw-r--r-- | gr-dtv/lib/atsc/atsc_sync_impl.cc | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/gr-dtv/lib/atsc/atsc_sync_impl.cc b/gr-dtv/lib/atsc/atsc_sync_impl.cc new file mode 100644 index 0000000000..ec46d6b8d1 --- /dev/null +++ b/gr-dtv/lib/atsc/atsc_sync_impl.cc @@ -0,0 +1,196 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "atsc_sync_impl.h" +#include "atsc_types.h" +#include <gnuradio/io_signature.h> + +namespace gr { + namespace dtv { + + atsc_sync::sptr + atsc_sync::make(float rate) + { + return gnuradio::get_initial_sptr + (new atsc_sync_impl(rate)); + } + + atsc_sync_impl::atsc_sync_impl(float rate) + : gr::block("dtv_atsc_sync", + io_signature::make(1, 1, sizeof(float)), + io_signature::make(1, 1, sizeof(atsc_soft_data_segment))), + d_next_input(0), d_rx_clock_to_symbol_freq(rate/ATSC_SYMBOL_RATE), + d_si(0) + { + d_loop.set_taps(LOOP_FILTER_TAP); + reset(); + } + + void + atsc_sync_impl::reset() + { + d_w = d_rx_clock_to_symbol_freq; + d_mu = 0.5; + + for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++) + sample_mem[i] = 0; + + d_timing_adjust = 0; + d_counter = 0; + d_symbol_index = 0; + d_seg_locked = false; + + d_sr = 0; + + for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++) + d_integrator[i] = SSI_MIN; + } + + atsc_sync_impl::~atsc_sync_impl() + { + } + + void + atsc_sync_impl::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = static_cast<int>(noutput_items * d_rx_clock_to_symbol_freq * ATSC_DATA_SEGMENT_LENGTH) + 1500 - 1; + } + + int + atsc_sync_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float *) input_items[0]; + atsc_soft_data_segment *soft_data_segment_out = (atsc_soft_data_segment *) output_items[0]; + + float interp_sample; + + // amount actually consumed + d_si = 0; + + for (output_produced = 0; output_produced < noutput_items && (d_si + (int)d_interp.ntaps()) < ninput_items[0];) { + // First we interpolate a sample from input to work with + interp_sample = d_interp.interpolate(&in[d_si], d_mu); + + // Apply our timing adjustment slowly over several samples + d_mu += ADJUSTMENT_GAIN * 1e3 * d_timing_adjust; + + double s = d_mu + d_w; + double float_incr = floor(s); + d_mu = s - float_incr; + d_incr = (int)float_incr; + + assert (d_incr >= 1 && d_incr <= 3); + d_si += d_incr; + + // Remember the sample at this count position + sample_mem[d_counter] = interp_sample; + + // Is the sample positive or negative? + int bit = (interp_sample < 0 ? 0 : 1); + + // Put the sign bit into our shift register + d_sr = ((bit & 1) << 3) | (d_sr >> 1); + + // When +,-,-,+ (0x9, 1001) samples show up we have likely found a segment + // sync, it is more likely the segment sync will show up at about the same + // spot every ATSC_DATA_SEGMENT_LENGTH samples so we add some weight + // to this spot every pass to prevent random +,-,-,+ symbols from + // confusing our synchronizer + d_integrator[d_counter] += ((d_sr == 0x9) ? +2 : -1); + if(d_integrator[d_counter] < SSI_MIN) d_integrator[d_counter] = SSI_MIN; + if(d_integrator[d_counter] > SSI_MAX) d_integrator[d_counter] = SSI_MAX; + + d_symbol_index++; + if( d_symbol_index >= ATSC_DATA_SEGMENT_LENGTH ) + d_symbol_index = 0; + + d_counter++; + if( d_counter >= ATSC_DATA_SEGMENT_LENGTH ) { // counter just wrapped... + int best_correlation_value = d_integrator[0]; + int best_correlation_index = 0; + + for(int i = 1; i < ATSC_DATA_SEGMENT_LENGTH; i++) + if (d_integrator[i] > best_correlation_value) { + best_correlation_value = d_integrator[i]; + best_correlation_index = i; + } + + d_seg_locked = best_correlation_value >= MIN_SEG_LOCK_CORRELATION_VALUE; + + // the coefficients are -1,-1,+1,+1 + //d_timing_adjust = sample_mem[best_correlation_index - 3] + + // sample_mem[best_correlation_index - 2] - + // sample_mem[best_correlation_index - 1] - + // sample_mem[best_correlation_index]; + + //printf( "d_timing_adjust = %f\n", d_timing_adjust ); + + int corr_count = best_correlation_index; + + d_timing_adjust = -sample_mem[corr_count--]; + if( corr_count < 0 ) corr_count = ATSC_DATA_SEGMENT_LENGTH - 1; + d_timing_adjust -= sample_mem[corr_count--]; + if( corr_count < 0 ) corr_count = ATSC_DATA_SEGMENT_LENGTH - 1; + d_timing_adjust += sample_mem[corr_count--]; + if( corr_count < 0 ) corr_count = ATSC_DATA_SEGMENT_LENGTH - 1; + d_timing_adjust += sample_mem[corr_count--]; + + d_symbol_index = SYMBOL_INDEX_OFFSET - 1 - best_correlation_index; + if (d_symbol_index < 0) + d_symbol_index += ATSC_DATA_SEGMENT_LENGTH; + + d_counter = 0; + } + + // If we are locked we can start filling and producing data packets + // Due to the way we lock the first data packet will almost always be + // half full, this is OK becouse the fs_checker will not let packets though + // untill a non-corrupted field packet is found + if( d_seg_locked ) { + data_mem[d_symbol_index] = interp_sample; + + if( d_symbol_index >= (ATSC_DATA_SEGMENT_LENGTH - 1) ) + { + for( int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++ ) + soft_data_segment_out[output_produced].data[i] = data_mem[i]; + output_produced++; + } + } + } + + consume_each(d_si); + return output_produced; + + } + + } /* namespace dtv */ +} /* namespace gr */ |