mirror of
				https://github.com/RangeNetworks/openbts.git
				synced 2025-11-03 21:33:15 +00:00 
			
		
		
		
	Transceiver52M: Setup dual sample rate transceiver
This patch applies oversampling, when selected with 4 sps, to the downlink only, while running the receiver with minimal sampling at 1 sps. These split sample rates allow us to run a highly accurate downlink signal with minimal distortion, while keeping receive path channel filtering on the FPGA. Without this patch, we oversample the receive path and require a steep receive filter to get similar adjacent channel suppression as the FPGA halfband / CIC filter combination, which comes with a high computational cost. Signed-off-by: Thomas Tsou <tom@tsou.cc> git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@6747 19bc5d8c-e614-43d4-8b26-e1612bc8e597
This commit is contained in:
		@@ -53,7 +53,8 @@ Transceiver::Transceiver(int wBasePort,
 | 
			
		||||
			 RadioInterface *wRadioInterface)
 | 
			
		||||
	:mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
 | 
			
		||||
	 mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
 | 
			
		||||
	 mClockSocket(wBasePort,TRXAddress,wBasePort+100)
 | 
			
		||||
	 mClockSocket(wBasePort,TRXAddress,wBasePort+100),
 | 
			
		||||
	 mSPSTx(wSPS), mSPSRx(1)
 | 
			
		||||
{
 | 
			
		||||
  GSM::Time startTime(random() % gHyperframe,0);
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +63,6 @@ Transceiver::Transceiver(int wBasePort,
 | 
			
		||||
  mControlServiceLoopThread = new Thread(32768);       ///< thread to process control messages from GSM core
 | 
			
		||||
  mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core
 | 
			
		||||
 | 
			
		||||
  mSPS = wSPS;
 | 
			
		||||
  mRadioInterface = wRadioInterface;
 | 
			
		||||
  mTransmitLatency = wTransmitLatency;
 | 
			
		||||
  mTransmitDeadlineClock = startTime;
 | 
			
		||||
@@ -92,7 +92,7 @@ Transceiver::~Transceiver()
 | 
			
		||||
 | 
			
		||||
bool Transceiver::init()
 | 
			
		||||
{
 | 
			
		||||
  if (!sigProcLibSetup(mSPS)) {
 | 
			
		||||
  if (!sigProcLibSetup(mSPSTx)) {
 | 
			
		||||
    LOG(ALERT) << "Failed to initialize signal processing library";
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -101,7 +101,7 @@ bool Transceiver::init()
 | 
			
		||||
  for (int i = 0; i < 8; i++) {
 | 
			
		||||
    signalVector* modBurst = modulateBurst(gDummyBurst,
 | 
			
		||||
					   8 + (i % 4 == 0),
 | 
			
		||||
					   mSPS);
 | 
			
		||||
					   mSPSTx);
 | 
			
		||||
    if (!modBurst) {
 | 
			
		||||
      sigProcLibDestroy();
 | 
			
		||||
      LOG(ALERT) << "Failed to initialize filler table";
 | 
			
		||||
@@ -133,7 +133,7 @@ radioVector *Transceiver::fixRadioVector(BitVector &burst,
 | 
			
		||||
  // modulate and stick into queue 
 | 
			
		||||
  signalVector* modBurst = modulateBurst(burst,
 | 
			
		||||
					 8 + (wTime.TN() % 4 == 0),
 | 
			
		||||
					 mSPS);
 | 
			
		||||
					 mSPSTx);
 | 
			
		||||
  scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10));
 | 
			
		||||
 | 
			
		||||
  radioVector *newVec = new radioVector(*modBurst,wTime);
 | 
			
		||||
@@ -146,7 +146,7 @@ radioVector *Transceiver::fixRadioVector(BitVector &burst,
 | 
			
		||||
#ifdef TRANSMIT_LOGGING
 | 
			
		||||
void Transceiver::unModulateVector(signalVector wVector) 
 | 
			
		||||
{
 | 
			
		||||
  SoftVector *burst = demodulateBurst(wVector, mSPS, 1.0, 0.0);
 | 
			
		||||
  SoftVector *burst = demodulateBurst(wVector, mSPSTx, 1.0, 0.0);
 | 
			
		||||
  LOG(DEBUG) << "LOGGED BURST: " << *burst;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -352,7 +352,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
 | 
			
		||||
  float TOA = 0.0;
 | 
			
		||||
  float avgPwr = 0.0;
 | 
			
		||||
#ifdef ENERGY_DETECT
 | 
			
		||||
  if (!energyDetect(*vectorBurst, 20 * mSPS, mEnergyThreshold, &avgPwr)) {
 | 
			
		||||
  if (!energyDetect(*vectorBurst, 20 * mSPSRx, mEnergyThreshold, &avgPwr)) {
 | 
			
		||||
     LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
 | 
			
		||||
     double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
 | 
			
		||||
     if (framesElapsed > 50) {  // if we haven't had any false detections for a while, lower threshold
 | 
			
		||||
@@ -388,7 +388,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
 | 
			
		||||
    success = analyzeTrafficBurst(*vectorBurst,
 | 
			
		||||
				  mTSC,
 | 
			
		||||
				  5.0,
 | 
			
		||||
				  mSPS,
 | 
			
		||||
				  mSPSRx,
 | 
			
		||||
				  &litude,
 | 
			
		||||
				  &TOA,
 | 
			
		||||
				  mMaxExpectedDelay, 
 | 
			
		||||
@@ -421,11 +421,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    // RACH burst
 | 
			
		||||
    success = detectRACHBurst(*vectorBurst,
 | 
			
		||||
			      6.0,
 | 
			
		||||
			      mSPS,
 | 
			
		||||
			      &litude,
 | 
			
		||||
			      &TOA);
 | 
			
		||||
    success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &litude, &TOA);
 | 
			
		||||
    if (success) {
 | 
			
		||||
      LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
 | 
			
		||||
      mEnergyThreshold -= (1.0F/10.0F);
 | 
			
		||||
@@ -444,22 +440,19 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
 | 
			
		||||
  SoftVector *burst = NULL;
 | 
			
		||||
  if ((rxBurst) && (success)) {
 | 
			
		||||
    if ((corrType==RACH) || (!needDFE)) {
 | 
			
		||||
      burst = demodulateBurst(*vectorBurst,
 | 
			
		||||
			      mSPS,
 | 
			
		||||
			      amplitude,TOA);
 | 
			
		||||
    }
 | 
			
		||||
    else { // TSC
 | 
			
		||||
      burst = demodulateBurst(*vectorBurst, mSPSRx, amplitude, TOA);
 | 
			
		||||
    } else {
 | 
			
		||||
      scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude);
 | 
			
		||||
      burst = equalizeBurst(*vectorBurst,
 | 
			
		||||
			    TOA-chanRespOffset[timeslot],
 | 
			
		||||
			    mSPS,
 | 
			
		||||
			    mSPSRx,
 | 
			
		||||
			    *DFEForward[timeslot],
 | 
			
		||||
			    *DFEFeedback[timeslot]);
 | 
			
		||||
    }
 | 
			
		||||
    wTime = rxBurst->getTime();
 | 
			
		||||
    RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs()));
 | 
			
		||||
    LOG(DEBUG) << "RSSI: " << RSSI;
 | 
			
		||||
    timingOffset = (int) round(TOA * 256.0 / mSPS);
 | 
			
		||||
    timingOffset = (int) round(TOA * 256.0 / mSPSRx);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n';
 | 
			
		||||
@@ -618,7 +611,7 @@ void Transceiver::driveControl()
 | 
			
		||||
      sprintf(response,"RSP SETTSC 1 %d",TSC);
 | 
			
		||||
    else {
 | 
			
		||||
      mTSC = TSC;
 | 
			
		||||
      generateMidamble(mSPS, TSC);
 | 
			
		||||
      generateMidamble(mSPSRx, TSC);
 | 
			
		||||
      sprintf(response,"RSP SETTSC 0 %d", TSC);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,8 @@ private:
 | 
			
		||||
  /** send messages over the clock socket */
 | 
			
		||||
  void writeClockInterface(void);
 | 
			
		||||
 | 
			
		||||
  int mSPS;                            ///< number of samples per GSM symbol
 | 
			
		||||
  int mSPSTx;                          ///< number of samples per Tx symbol
 | 
			
		||||
  int mSPSRx;                          ///< number of samples per Rx symbol
 | 
			
		||||
 | 
			
		||||
  bool mOn;			       ///< flag to indicate that transceiver is powered on
 | 
			
		||||
  ChannelCombination mChanType[8];     ///< channel types for all timeslots
 | 
			
		||||
 
 | 
			
		||||
@@ -66,14 +66,14 @@ struct uhd_dev_offset {
 | 
			
		||||
static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 2] = {
 | 
			
		||||
	{ USRP1, 1, 0.0 },
 | 
			
		||||
	{ USRP1, 4, 0.0 },
 | 
			
		||||
	{ USRP2, 1, 5.4394e-5 },
 | 
			
		||||
	{ USRP2, 4, 0.0 },
 | 
			
		||||
	{ B100,  1, 9.4778e-5 },
 | 
			
		||||
	{ B100,  4, 2.9418e-5 },
 | 
			
		||||
	{ B200,  1, 0.0 },
 | 
			
		||||
	{ B200,  4, 9.8358e-5 },
 | 
			
		||||
	{ UMTRX, 1, 9.4778e-5 },
 | 
			
		||||
	{ UMTRX, 4, 0.0 },
 | 
			
		||||
	{ USRP2, 1, 1.1815e-4 },
 | 
			
		||||
	{ USRP2, 4, 7.7538e-5 },
 | 
			
		||||
	{ B100,  1, 9.9692e-5 },
 | 
			
		||||
	{ B100,  4, 6.5545e-5 },
 | 
			
		||||
	{ B200,  1, 9.6000e-5 },
 | 
			
		||||
	{ B200,  4, 6.4615e-5 },
 | 
			
		||||
	{ UMTRX, 1, 9.9692e-5 },
 | 
			
		||||
	{ UMTRX, 4, 7.3846e-5 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static double get_dev_offset(enum uhd_dev_type type, int sps)
 | 
			
		||||
@@ -248,7 +248,7 @@ public:
 | 
			
		||||
	double getTxFreq() { return tx_freq; }
 | 
			
		||||
	double getRxFreq() { return rx_freq; }
 | 
			
		||||
 | 
			
		||||
	inline double getSampleRate() { return actual_smpl_rt; }
 | 
			
		||||
	inline double getSampleRate() { return tx_rate; }
 | 
			
		||||
	inline double numberRead() { return rx_pkt_cnt; }
 | 
			
		||||
	inline double numberWritten() { return 0; }
 | 
			
		||||
 | 
			
		||||
@@ -271,7 +271,7 @@ private:
 | 
			
		||||
	enum uhd_dev_type dev_type;
 | 
			
		||||
 | 
			
		||||
	int sps;
 | 
			
		||||
	double desired_smpl_rt, actual_smpl_rt;
 | 
			
		||||
	double tx_rate, rx_rate;
 | 
			
		||||
 | 
			
		||||
	double tx_gain, tx_gain_min, tx_gain_max;
 | 
			
		||||
	double rx_gain, rx_gain_min, rx_gain_max;
 | 
			
		||||
@@ -293,7 +293,7 @@ private:
 | 
			
		||||
	void init_gains();
 | 
			
		||||
	void set_ref_clk(bool ext_clk);
 | 
			
		||||
	int set_master_clk(double rate);
 | 
			
		||||
	int set_rates(double rate);
 | 
			
		||||
	int set_rates(double tx_rate, double rx_rate);
 | 
			
		||||
	bool parse_dev_type();
 | 
			
		||||
	bool flush_recv(size_t num_pkts);
 | 
			
		||||
	int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls);
 | 
			
		||||
@@ -407,7 +407,7 @@ int uhd_device::set_master_clk(double clk_rate)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int uhd_device::set_rates(double rate)
 | 
			
		||||
int uhd_device::set_rates(double tx_rate, double rx_rate)
 | 
			
		||||
{
 | 
			
		||||
	double offset_limit = 1.0;
 | 
			
		||||
	double tx_offset, rx_offset;
 | 
			
		||||
@@ -420,21 +420,22 @@ int uhd_device::set_rates(double rate)
 | 
			
		||||
 | 
			
		||||
	// Set sample rates
 | 
			
		||||
	try {
 | 
			
		||||
		usrp_dev->set_tx_rate(rate);
 | 
			
		||||
		usrp_dev->set_rx_rate(rate);
 | 
			
		||||
		usrp_dev->set_tx_rate(tx_rate);
 | 
			
		||||
		usrp_dev->set_rx_rate(rx_rate);
 | 
			
		||||
	} catch (const std::exception &ex) {
 | 
			
		||||
		LOG(ALERT) << "UHD rate setting failed: " << rate;
 | 
			
		||||
		LOG(ALERT) << "UHD rate setting failed";
 | 
			
		||||
		LOG(ALERT) << ex.what();
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	actual_smpl_rt = usrp_dev->get_tx_rate();
 | 
			
		||||
	this->tx_rate = usrp_dev->get_tx_rate();
 | 
			
		||||
	this->rx_rate = usrp_dev->get_rx_rate();
 | 
			
		||||
 | 
			
		||||
	tx_offset = fabs(usrp_dev->get_tx_rate() - rate);
 | 
			
		||||
	rx_offset = fabs(usrp_dev->get_rx_rate() - rate);
 | 
			
		||||
	tx_offset = fabs(this->tx_rate - tx_rate);
 | 
			
		||||
	rx_offset = fabs(this->rx_rate - rx_rate);
 | 
			
		||||
	if ((tx_offset > offset_limit) || (rx_offset > offset_limit)) {
 | 
			
		||||
		LOG(ALERT) << "Actual sample rate differs from desired rate";
 | 
			
		||||
		LOG(ALERT) << "Tx/Rx (" << usrp_dev->get_rx_rate() << "/"
 | 
			
		||||
			   << usrp_dev->get_rx_rate() << ")";
 | 
			
		||||
		LOG(ALERT) << "Tx/Rx (" << this->tx_rate << "/"
 | 
			
		||||
			   << this->rx_rate << ")";
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -552,13 +553,14 @@ int uhd_device::open(const std::string &args)
 | 
			
		||||
	rx_spp = rx_stream->get_max_num_samps();
 | 
			
		||||
 | 
			
		||||
	// Set rates
 | 
			
		||||
	desired_smpl_rt = select_rate(dev_type, sps);
 | 
			
		||||
	if ((desired_smpl_rt > 0.0) && (set_rates(desired_smpl_rt) < 0))
 | 
			
		||||
	double _tx_rate = select_rate(dev_type, sps);
 | 
			
		||||
	double _rx_rate = _tx_rate / sps;
 | 
			
		||||
	if ((_tx_rate > 0.0) && (set_rates(_tx_rate, _rx_rate) < 0))
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	// Create receive buffer
 | 
			
		||||
	size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t);
 | 
			
		||||
	rx_smpl_buf = new smpl_buf(buf_len, actual_smpl_rt);
 | 
			
		||||
	rx_smpl_buf = new smpl_buf(buf_len, rx_rate);
 | 
			
		||||
 | 
			
		||||
	// Set receive chain sample offset 
 | 
			
		||||
	double offset = get_dev_offset(dev_type, sps);
 | 
			
		||||
@@ -566,7 +568,7 @@ int uhd_device::open(const std::string &args)
 | 
			
		||||
		LOG(ERR) << "Unsupported configuration, no correction applied";
 | 
			
		||||
		ts_offset = 0;
 | 
			
		||||
	} else  {
 | 
			
		||||
		ts_offset = (TIMESTAMP) (offset * actual_smpl_rt);
 | 
			
		||||
		ts_offset = (TIMESTAMP) (offset * rx_rate);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize and shadow gain values 
 | 
			
		||||
@@ -719,7 +721,7 @@ int uhd_device::readSamples(short *buf, int len, bool *overrun,
 | 
			
		||||
	// Shift read time with respect to transmit clock
 | 
			
		||||
	timestamp += ts_offset;
 | 
			
		||||
 | 
			
		||||
	ts = convert_time(timestamp, actual_smpl_rt);
 | 
			
		||||
	ts = convert_time(timestamp, rx_rate);
 | 
			
		||||
	LOG(DEBUG) << "Requested timestamp = " << ts.get_real_secs();
 | 
			
		||||
 | 
			
		||||
	// Check that timestamp is valid
 | 
			
		||||
@@ -788,7 +790,7 @@ int uhd_device::writeSamples(short *buf, int len, bool *underrun,
 | 
			
		||||
	metadata.has_time_spec = true;
 | 
			
		||||
	metadata.start_of_burst = false;
 | 
			
		||||
	metadata.end_of_burst = false;
 | 
			
		||||
	metadata.time_spec = convert_time(timestamp, actual_smpl_rt);
 | 
			
		||||
	metadata.time_spec = convert_time(timestamp, tx_rate);
 | 
			
		||||
 | 
			
		||||
	// No control packets
 | 
			
		||||
	if (isControl) {
 | 
			
		||||
 
 | 
			
		||||
@@ -63,10 +63,25 @@ USRPDevice::USRPDevice(int sps, bool skipRx)
 | 
			
		||||
  : skipRx(skipRx)
 | 
			
		||||
{
 | 
			
		||||
  LOG(INFO) << "creating USRP device...";
 | 
			
		||||
 | 
			
		||||
  this->sps = sps;
 | 
			
		||||
  decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) sps));
 | 
			
		||||
  actualSampleRate = masterClockRate/decimRate;
 | 
			
		||||
  rxGain = 0;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Undetermined delay b/w ping response timestamp and true
 | 
			
		||||
   * receive timestamp. Values are empirically measured. With
 | 
			
		||||
   * split sample rate Tx/Rx - 4/1 sps we need to need to
 | 
			
		||||
   * compensate for advance rather than delay.
 | 
			
		||||
   */
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
    pingOffset = 272;
 | 
			
		||||
  else if (sps == 4)
 | 
			
		||||
    pingOffset = 269 - 7500;
 | 
			
		||||
  else
 | 
			
		||||
    pingOffset = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef SWLOOPBACK 
 | 
			
		||||
  samplePeriod = 1.0e6/actualSampleRate;
 | 
			
		||||
  loopbackBufferSize = 0;
 | 
			
		||||
@@ -86,9 +101,10 @@ int USRPDevice::open(const std::string &)
 | 
			
		||||
  m_uRx.reset();
 | 
			
		||||
  if (!skipRx) {
 | 
			
		||||
  try {
 | 
			
		||||
    m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(0,decimRate,1,-1,
 | 
			
		||||
                                                         usrp_standard_rx::FPGA_MODE_NORMAL,
 | 
			
		||||
                                                         1024,16*8,rbf));
 | 
			
		||||
    m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(
 | 
			
		||||
                                        0, decimRate * sps, 1, -1,
 | 
			
		||||
                                        usrp_standard_rx::FPGA_MODE_NORMAL,
 | 
			
		||||
                                        1024, 16 * 8, rbf));
 | 
			
		||||
#ifdef HAVE_LIBUSRP_3_2
 | 
			
		||||
    m_uRx->set_fpga_master_clock_freq(masterClockRate);
 | 
			
		||||
#endif
 | 
			
		||||
@@ -110,8 +126,9 @@ int USRPDevice::open(const std::string &)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make(0,decimRate*2,1,-1,
 | 
			
		||||
                                                         1024,16*8,rbf));
 | 
			
		||||
    m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make(
 | 
			
		||||
                                        0, decimRate * 2, 1, -1,
 | 
			
		||||
                                        1024, 16 * 8, rbf));
 | 
			
		||||
#ifdef HAVE_LIBUSRP_3_2
 | 
			
		||||
    m_uTx->set_fpga_master_clock_freq(masterClockRate);
 | 
			
		||||
#endif
 | 
			
		||||
@@ -341,7 +358,7 @@ int USRPDevice::readSamples(short *buf, int len, bool *overrun,
 | 
			
		||||
        uint32_t word2 = usrp_to_host_u32(tmpBuf[2]);
 | 
			
		||||
	if ((word2 >> 16) == ((0x01 << 8) | 0x02)) {
 | 
			
		||||
          timestamp -= timestampOffset;
 | 
			
		||||
	  timestampOffset = pktTimestamp - pingTimestamp + PINGOFFSET;
 | 
			
		||||
	  timestampOffset = pktTimestamp - pingTimestamp + pingOffset;
 | 
			
		||||
	  LOG(DEBUG) << "updating timestamp offset to: " << timestampOffset;
 | 
			
		||||
          timestamp += timestampOffset;
 | 
			
		||||
	  isAligned = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,7 @@ private:
 | 
			
		||||
  usrp_subdev_spec rxSubdevSpec;
 | 
			
		||||
  usrp_subdev_spec txSubdevSpec;
 | 
			
		||||
 | 
			
		||||
  int sps;
 | 
			
		||||
  double actualSampleRate;	///< the actual USRP sampling rate
 | 
			
		||||
  unsigned int decimRate;	///< the USRP decimation rate
 | 
			
		||||
 | 
			
		||||
@@ -87,7 +88,8 @@ private:
 | 
			
		||||
  TIMESTAMP timestampOffset;       ///< timestamp offset b/w Tx and Rx blocks
 | 
			
		||||
  TIMESTAMP latestWriteTimestamp;  ///< timestamp of most recent ping command
 | 
			
		||||
  TIMESTAMP pingTimestamp;	   ///< timestamp of most recent ping response
 | 
			
		||||
  static const TIMESTAMP PINGOFFSET = 272;  ///< undetermined delay b/w ping response timestamp and true receive timestamp
 | 
			
		||||
 | 
			
		||||
  long long  pingOffset;
 | 
			
		||||
  unsigned long hi32Timestamp;
 | 
			
		||||
  unsigned long lastPktTimestamp;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,13 +23,15 @@
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "radioInterface.h"
 | 
			
		||||
#include "Resampler.h"
 | 
			
		||||
#include <Logger.h>
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
#include "convert.h"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool started = false;
 | 
			
		||||
#define INCHUNK		(625 * SAMPSPERSYM)
 | 
			
		||||
#define OUTCHUNK	(625 * SAMPSPERSYM)
 | 
			
		||||
 | 
			
		||||
RadioInterface::RadioInterface(RadioDevice *wRadio,
 | 
			
		||||
			       int wReceiveOffset,
 | 
			
		||||
@@ -37,7 +39,7 @@ RadioInterface::RadioInterface(RadioDevice *wRadio,
 | 
			
		||||
			       GSM::Time wStartTime)
 | 
			
		||||
  : underrun(false), sendCursor(0), recvCursor(0), mOn(false),
 | 
			
		||||
    mRadio(wRadio), receiveOffset(wReceiveOffset),
 | 
			
		||||
    sps(wSPS), powerScaling(1.0),
 | 
			
		||||
    mSPSTx(wSPS), mSPSRx(1), powerScaling(1.0),
 | 
			
		||||
    loadTest(false), sendBuffer(NULL), recvBuffer(NULL),
 | 
			
		||||
    convertRecvBuffer(NULL), convertSendBuffer(NULL)
 | 
			
		||||
{
 | 
			
		||||
@@ -209,8 +211,8 @@ void RadioInterface::driveReceiveRadio() {
 | 
			
		||||
  // while there's enough data in receive buffer, form received 
 | 
			
		||||
  //    GSM bursts and pass up to Transceiver
 | 
			
		||||
  // Using the 157-156-156-156 symbols per timeslot format.
 | 
			
		||||
  while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * sps) {
 | 
			
		||||
    signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * sps);
 | 
			
		||||
  while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx) {
 | 
			
		||||
    signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * mSPSRx);
 | 
			
		||||
    unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector);
 | 
			
		||||
    GSM::Time tmpTime = rcvClock;
 | 
			
		||||
    if (rcvClock.FN() >= 0) {
 | 
			
		||||
@@ -228,8 +230,8 @@ void RadioInterface::driveReceiveRadio() {
 | 
			
		||||
    }
 | 
			
		||||
    mClock.incTN(); 
 | 
			
		||||
    rcvClock.incTN();
 | 
			
		||||
    readSz += (symbolsPerSlot+(tN % 4 == 0)) * sps;
 | 
			
		||||
    rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * sps;
 | 
			
		||||
    readSz += (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx;
 | 
			
		||||
    rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx;
 | 
			
		||||
 | 
			
		||||
    tN = rcvClock.TN();
 | 
			
		||||
  }
 | 
			
		||||
@@ -267,33 +269,35 @@ double RadioInterface::getRxGain()
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Receive a timestamped chunk from the device */ 
 | 
			
		||||
/* Receive a timestamped chunk from the device */
 | 
			
		||||
void RadioInterface::pullBuffer()
 | 
			
		||||
{
 | 
			
		||||
  bool local_underrun;
 | 
			
		||||
  int num_recv;
 | 
			
		||||
  int num_recv, len = OUTCHUNK / mSPSTx;
 | 
			
		||||
  float *output;
 | 
			
		||||
 | 
			
		||||
  /* Outer buffer access size is fixed */ 
 | 
			
		||||
  /* Outer buffer access size is fixed */
 | 
			
		||||
  num_recv = mRadio->readSamples(convertRecvBuffer,
 | 
			
		||||
                                 OUTCHUNK,
 | 
			
		||||
                                 len,
 | 
			
		||||
                                 &overrun,
 | 
			
		||||
                                 readTimestamp,
 | 
			
		||||
                                 &local_underrun);
 | 
			
		||||
  if (num_recv != OUTCHUNK) {
 | 
			
		||||
  if (num_recv != len) {
 | 
			
		||||
          LOG(ALERT) << "Receive error " << num_recv;
 | 
			
		||||
          return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  convert_short_float((float *) (recvBuffer->begin() + recvCursor),
 | 
			
		||||
                      convertRecvBuffer, 2 * OUTCHUNK);
 | 
			
		||||
  output = (float *) (recvBuffer->begin() + recvCursor);
 | 
			
		||||
 | 
			
		||||
  convert_short_float(output, convertRecvBuffer, 2 * len);
 | 
			
		||||
 | 
			
		||||
  underrun |= local_underrun;
 | 
			
		||||
  readTimestamp += num_recv;
 | 
			
		||||
 | 
			
		||||
  readTimestamp += num_recv;
 | 
			
		||||
  recvCursor += num_recv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Send timestamped chunk to the device with arbitrary size */ 
 | 
			
		||||
/* Send timestamped chunk to the device with arbitrary size */
 | 
			
		||||
void RadioInterface::pushBuffer()
 | 
			
		||||
{
 | 
			
		||||
  int num_sent;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,6 @@
 | 
			
		||||
 | 
			
		||||
/** samples per GSM symbol */
 | 
			
		||||
#define SAMPSPERSYM 4
 | 
			
		||||
#define INCHUNK    (625)
 | 
			
		||||
#define OUTCHUNK   (625)
 | 
			
		||||
 | 
			
		||||
/** class to interface the transceiver with the USRP */
 | 
			
		||||
class RadioInterface {
 | 
			
		||||
@@ -36,7 +34,9 @@ protected:
 | 
			
		||||
  VectorFIFO  mReceiveFIFO;		      ///< FIFO that holds receive  bursts
 | 
			
		||||
 | 
			
		||||
  RadioDevice *mRadio;			      ///< the USRP object
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
  int mSPSTx;
 | 
			
		||||
  int mSPSRx;
 | 
			
		||||
  signalVector *sendBuffer;
 | 
			
		||||
  signalVector *recvBuffer;
 | 
			
		||||
  unsigned sendCursor;
 | 
			
		||||
@@ -52,7 +52,6 @@ protected:
 | 
			
		||||
 | 
			
		||||
  RadioClock mClock;                          ///< the basestation clock!
 | 
			
		||||
 | 
			
		||||
  int sps;                                    ///< samples per GSM symbol
 | 
			
		||||
  int receiveOffset;                          ///< offset b/w transmit and receive GSM timestamps, in timeslots
 | 
			
		||||
 | 
			
		||||
  bool mOn;				      ///< indicates radio is on
 | 
			
		||||
 
 | 
			
		||||
@@ -28,14 +28,6 @@ extern "C" {
 | 
			
		||||
#include "convert.h"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* New chunk sizes for resampled rate */
 | 
			
		||||
#ifdef INCHUNK
 | 
			
		||||
  #undef INCHUNK
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef OUTCHUNK
 | 
			
		||||
  #undef OUTCHUNK
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Resampling parameters for 100 MHz clocking */
 | 
			
		||||
#define RESAMP_INRATE			52
 | 
			
		||||
#define RESAMP_OUTRATE			75
 | 
			
		||||
@@ -104,7 +96,7 @@ bool RadioInterfaceResamp::init()
 | 
			
		||||
		cutoff = RESAMP_TX4_FILTER;
 | 
			
		||||
 | 
			
		||||
	dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE);
 | 
			
		||||
	if (!dnsampler->init(cutoff)) {
 | 
			
		||||
	if (!dnsampler->init()) {
 | 
			
		||||
		LOG(ALERT) << "Rx resampler failed to initialize";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
@@ -121,10 +113,10 @@ bool RadioInterfaceResamp::init()
 | 
			
		||||
	 * and requires headroom equivalent to the filter length. Low
 | 
			
		||||
	 * rate buffers are allocated in the main radio interface code.
 | 
			
		||||
	 */
 | 
			
		||||
	innerSendBuffer = new signalVector(INCHUNK * 20, RESAMP_FILT_LEN);
 | 
			
		||||
	innerSendBuffer = new signalVector(INCHUNK * 20, upsampler->len());
 | 
			
		||||
	outerSendBuffer = new signalVector(OUTCHUNK * 20);
 | 
			
		||||
 | 
			
		||||
	outerRecvBuffer = new signalVector(OUTCHUNK * 2, RESAMP_FILT_LEN);
 | 
			
		||||
	outerRecvBuffer = new signalVector(OUTCHUNK * 2, dnsampler->len());
 | 
			
		||||
	innerRecvBuffer = new signalVector(INCHUNK * 20);
 | 
			
		||||
 | 
			
		||||
	convertSendBuffer = new short[OUTCHUNK * 2 * 20];
 | 
			
		||||
 
 | 
			
		||||
@@ -42,9 +42,11 @@ static const float M_PI_F = (float)M_PI;
 | 
			
		||||
static const float M_2PI_F = (float)(2.0*M_PI);
 | 
			
		||||
static const float M_1_2PI_F = 1/M_2PI_F;
 | 
			
		||||
 | 
			
		||||
/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */ 
 | 
			
		||||
signalVector *GMSKRotation = NULL;
 | 
			
		||||
signalVector *GMSKReverseRotation = NULL;
 | 
			
		||||
/* Precomputed rotation vectors */
 | 
			
		||||
static signalVector *GMSKRotationN = NULL;
 | 
			
		||||
static signalVector *GMSKReverseRotationN = NULL;
 | 
			
		||||
static signalVector *GMSKRotation1 = NULL;
 | 
			
		||||
static signalVector *GMSKReverseRotation1 = NULL;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * RACH and midamble correlation waveforms. Store the buffer separately
 | 
			
		||||
@@ -65,7 +67,7 @@ struct CorrelationSequence {
 | 
			
		||||
 | 
			
		||||
  signalVector *sequence;
 | 
			
		||||
  void         *buffer;
 | 
			
		||||
  float        TOA;
 | 
			
		||||
  float        toa;
 | 
			
		||||
  complex      gain;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -99,6 +101,7 @@ struct PulseSequence {
 | 
			
		||||
CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
 | 
			
		||||
CorrelationSequence *gRACHSequence = NULL;
 | 
			
		||||
PulseSequence *GSMPulse = NULL;
 | 
			
		||||
PulseSequence *GSMPulse1 = NULL;
 | 
			
		||||
 | 
			
		||||
void sigProcLibDestroy()
 | 
			
		||||
{
 | 
			
		||||
@@ -107,15 +110,21 @@ void sigProcLibDestroy()
 | 
			
		||||
    gMidambles[i] = NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  delete GMSKRotation;
 | 
			
		||||
  delete GMSKReverseRotation;
 | 
			
		||||
  delete GMSKRotationN;
 | 
			
		||||
  delete GMSKReverseRotationN;
 | 
			
		||||
  delete GMSKRotation1;
 | 
			
		||||
  delete GMSKReverseRotation1;
 | 
			
		||||
  delete gRACHSequence;
 | 
			
		||||
  delete GSMPulse;
 | 
			
		||||
  delete GSMPulse1;
 | 
			
		||||
 | 
			
		||||
  GMSKRotation = NULL;
 | 
			
		||||
  GMSKReverseRotation = NULL;
 | 
			
		||||
  GMSKRotationN = NULL;
 | 
			
		||||
  GMSKRotation1 = NULL;
 | 
			
		||||
  GMSKReverseRotationN = NULL;
 | 
			
		||||
  GMSKReverseRotation1 = NULL;
 | 
			
		||||
  gRACHSequence = NULL;
 | 
			
		||||
  GSMPulse = NULL;
 | 
			
		||||
  GSMPulse1 = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dB relative to 1.0.
 | 
			
		||||
@@ -248,38 +257,38 @@ void initTrigTables() {
 | 
			
		||||
 | 
			
		||||
void initGMSKRotationTables(int sps)
 | 
			
		||||
{
 | 
			
		||||
  GMSKRotation = new signalVector(157 * sps);
 | 
			
		||||
  GMSKReverseRotation = new signalVector(157 * sps);
 | 
			
		||||
  signalVector::iterator rotPtr = GMSKRotation->begin();
 | 
			
		||||
  signalVector::iterator revPtr = GMSKReverseRotation->begin();
 | 
			
		||||
  GMSKRotationN = new signalVector(157 * sps);
 | 
			
		||||
  GMSKReverseRotationN = new signalVector(157 * sps);
 | 
			
		||||
  signalVector::iterator rotPtr = GMSKRotationN->begin();
 | 
			
		||||
  signalVector::iterator revPtr = GMSKReverseRotationN->begin();
 | 
			
		||||
  float phase = 0.0;
 | 
			
		||||
  while (rotPtr != GMSKRotation->end()) {
 | 
			
		||||
  while (rotPtr != GMSKRotationN->end()) {
 | 
			
		||||
    *rotPtr++ = expjLookup(phase);
 | 
			
		||||
    *revPtr++ = expjLookup(-phase);
 | 
			
		||||
    phase += M_PI_F / 2.0F / (float) sps;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool sigProcLibSetup(int sps)
 | 
			
		||||
{
 | 
			
		||||
  if ((sps != 1) && (sps != 4))
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  initTrigTables();
 | 
			
		||||
  initGMSKRotationTables(sps);
 | 
			
		||||
  generateGSMPulse(sps, 2);
 | 
			
		||||
 | 
			
		||||
  if (!generateRACHSequence(sps)) {
 | 
			
		||||
    sigProcLibDestroy();
 | 
			
		||||
    return false;
 | 
			
		||||
  GMSKRotation1 = new signalVector(157);
 | 
			
		||||
  GMSKReverseRotation1 = new signalVector(157);
 | 
			
		||||
  rotPtr = GMSKRotation1->begin();
 | 
			
		||||
  revPtr = GMSKReverseRotation1->begin();
 | 
			
		||||
  phase = 0.0;
 | 
			
		||||
  while (rotPtr != GMSKRotation1->end()) {
 | 
			
		||||
    *rotPtr++ = expjLookup(phase);
 | 
			
		||||
    *revPtr++ = expjLookup(-phase);
 | 
			
		||||
    phase += M_PI_F / 2.0F;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMSKRotate(signalVector &x) {
 | 
			
		||||
  signalVector::iterator xPtr = x.begin();
 | 
			
		||||
  signalVector::iterator rotPtr = GMSKRotation->begin();
 | 
			
		||||
static void GMSKRotate(signalVector &x, int sps)
 | 
			
		||||
{
 | 
			
		||||
  signalVector::iterator rotPtr, xPtr = x.begin();
 | 
			
		||||
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
    rotPtr = GMSKRotation1->begin();
 | 
			
		||||
  else
 | 
			
		||||
    rotPtr = GMSKRotationN->begin();
 | 
			
		||||
 | 
			
		||||
  if (x.isRealOnly()) {
 | 
			
		||||
    while (xPtr < x.end()) {
 | 
			
		||||
      *xPtr = *rotPtr++ * (xPtr->real());
 | 
			
		||||
@@ -294,9 +303,15 @@ void GMSKRotate(signalVector &x) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMSKReverseRotate(signalVector &x) {
 | 
			
		||||
  signalVector::iterator xPtr= x.begin();
 | 
			
		||||
  signalVector::iterator rotPtr = GMSKReverseRotation->begin();
 | 
			
		||||
static void GMSKReverseRotate(signalVector &x, int sps)
 | 
			
		||||
{
 | 
			
		||||
  signalVector::iterator rotPtr, xPtr= x.begin();
 | 
			
		||||
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
    rotPtr = GMSKReverseRotation1->begin();
 | 
			
		||||
  else
 | 
			
		||||
    rotPtr = GMSKReverseRotationN->begin();
 | 
			
		||||
 | 
			
		||||
  if (x.isRealOnly()) {
 | 
			
		||||
    while (xPtr < x.end()) {
 | 
			
		||||
      *xPtr = *rotPtr++ * (xPtr->real());
 | 
			
		||||
@@ -412,10 +427,13 @@ signalVector *convolve(const signalVector *x,
 | 
			
		||||
  return y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool generateC1Pulse(int sps)
 | 
			
		||||
static bool generateC1Pulse(int sps, PulseSequence *pulse)
 | 
			
		||||
{
 | 
			
		||||
  int len;
 | 
			
		||||
 | 
			
		||||
  if (!pulse)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  switch (sps) {
 | 
			
		||||
  case 4:
 | 
			
		||||
    len = 8;
 | 
			
		||||
@@ -424,20 +442,20 @@ bool generateC1Pulse(int sps)
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GSMPulse->c1_buffer = convolve_h_alloc(len);
 | 
			
		||||
  GSMPulse->c1 = new signalVector((complex *)
 | 
			
		||||
                                  GSMPulse->c1_buffer, 0, len);
 | 
			
		||||
  GSMPulse->c1->isRealOnly(true);
 | 
			
		||||
  pulse->c1_buffer = convolve_h_alloc(len);
 | 
			
		||||
  pulse->c1 = new signalVector((complex *)
 | 
			
		||||
                                  pulse->c1_buffer, 0, len);
 | 
			
		||||
  pulse->c1->isRealOnly(true);
 | 
			
		||||
 | 
			
		||||
  /* Enable alignment for SSE usage */
 | 
			
		||||
  GSMPulse->c1->setAligned(true);
 | 
			
		||||
  pulse->c1->setAligned(true);
 | 
			
		||||
 | 
			
		||||
  signalVector::iterator xP = GSMPulse->c1->begin();
 | 
			
		||||
  signalVector::iterator xP = pulse->c1->begin();
 | 
			
		||||
 | 
			
		||||
  switch (sps) {
 | 
			
		||||
  case 4:
 | 
			
		||||
    /* BT = 0.30 */
 | 
			
		||||
    *xP++ = 0.0; 
 | 
			
		||||
    *xP++ = 0.0;
 | 
			
		||||
    *xP++ = 8.16373112e-03;
 | 
			
		||||
    *xP++ = 2.84385729e-02;
 | 
			
		||||
    *xP++ = 5.64158904e-02;
 | 
			
		||||
@@ -450,18 +468,17 @@ bool generateC1Pulse(int sps)
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void generateGSMPulse(int sps, int symbolLength)
 | 
			
		||||
static PulseSequence *generateGSMPulse(int sps, int symbolLength)
 | 
			
		||||
{
 | 
			
		||||
  int len;
 | 
			
		||||
  float arg, avg, center;
 | 
			
		||||
 | 
			
		||||
  delete GSMPulse;
 | 
			
		||||
  PulseSequence *pulse;
 | 
			
		||||
 | 
			
		||||
  /* Store a single tap filter used for correlation sequence generation */
 | 
			
		||||
  GSMPulse = new PulseSequence();
 | 
			
		||||
  GSMPulse->empty = new signalVector(1);
 | 
			
		||||
  GSMPulse->empty->isRealOnly(true);
 | 
			
		||||
  *(GSMPulse->empty->begin()) = 1.0f;
 | 
			
		||||
  pulse = new PulseSequence();
 | 
			
		||||
  pulse->empty = new signalVector(1);
 | 
			
		||||
  pulse->empty->isRealOnly(true);
 | 
			
		||||
  *(pulse->empty->begin()) = 1.0f;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * For 4 samples-per-symbol use a precomputed single pulse Laurent
 | 
			
		||||
@@ -479,15 +496,14 @@ void generateGSMPulse(int sps, int symbolLength)
 | 
			
		||||
      len = 4;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GSMPulse->c0_buffer = convolve_h_alloc(len);
 | 
			
		||||
  GSMPulse->c0 = new signalVector((complex *)
 | 
			
		||||
                                  GSMPulse->c0_buffer, 0, len);
 | 
			
		||||
  GSMPulse->c0->isRealOnly(true);
 | 
			
		||||
  pulse->c0_buffer = convolve_h_alloc(len);
 | 
			
		||||
  pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
 | 
			
		||||
  pulse->c0->isRealOnly(true);
 | 
			
		||||
 | 
			
		||||
  /* Enable alingnment for SSE usage */
 | 
			
		||||
  GSMPulse->c0->setAligned(true);
 | 
			
		||||
  pulse->c0->setAligned(true);
 | 
			
		||||
 | 
			
		||||
  signalVector::iterator xP = GSMPulse->c0->begin();
 | 
			
		||||
  signalVector::iterator xP = pulse->c0->begin();
 | 
			
		||||
 | 
			
		||||
  if (sps == 4) {
 | 
			
		||||
    *xP++ = 0.0;
 | 
			
		||||
@@ -506,7 +522,7 @@ void generateGSMPulse(int sps, int symbolLength)
 | 
			
		||||
    *xP++ = 1.03184855e-01;
 | 
			
		||||
    *xP++ = 2.84385729e-02;
 | 
			
		||||
    *xP++ = 4.46348606e-03;
 | 
			
		||||
    generateC1Pulse(sps);
 | 
			
		||||
    generateC1Pulse(sps, pulse);
 | 
			
		||||
  } else {
 | 
			
		||||
    center = (float) (len - 1.0) / 2.0;
 | 
			
		||||
 | 
			
		||||
@@ -517,11 +533,13 @@ void generateGSMPulse(int sps, int symbolLength)
 | 
			
		||||
			 0.527 * arg * arg * arg * arg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    avg = sqrtf(vectorNorm2(*GSMPulse->c0) / sps);
 | 
			
		||||
    xP = GSMPulse->c0->begin();
 | 
			
		||||
    for (int i = 0; i < len; i++) 
 | 
			
		||||
    avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
 | 
			
		||||
    xP = pulse->c0->begin();
 | 
			
		||||
    for (int i = 0; i < len; i++)
 | 
			
		||||
      *xP++ /= avg;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return pulse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
signalVector* frequencyShift(signalVector *y,
 | 
			
		||||
@@ -610,7 +628,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
 | 
			
		||||
  signalVector *pulse, rotated, *shaped;
 | 
			
		||||
  signalVector::iterator itr;
 | 
			
		||||
 | 
			
		||||
  pulse = GSMPulse->empty;
 | 
			
		||||
  pulse = GSMPulse1->empty;
 | 
			
		||||
  burst_len = sps * (wBurst.size() + guardPeriodLength);
 | 
			
		||||
  rotated = signalVector(burst_len);
 | 
			
		||||
  itr = rotated.begin();
 | 
			
		||||
@@ -620,7 +638,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
 | 
			
		||||
    itr += sps;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GMSKRotate(rotated);
 | 
			
		||||
  GMSKRotate(rotated, sps);
 | 
			
		||||
  rotated.isRealOnly(false);
 | 
			
		||||
 | 
			
		||||
  /* Dummy filter operation */
 | 
			
		||||
@@ -673,7 +691,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits,
 | 
			
		||||
  *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
 | 
			
		||||
 | 
			
		||||
  /* Generate C0 phase coefficients */
 | 
			
		||||
  GMSKRotate(c0_burst);
 | 
			
		||||
  GMSKRotate(c0_burst, sps);
 | 
			
		||||
  c0_burst.isRealOnly(false);
 | 
			
		||||
 | 
			
		||||
  c0_itr = c0_burst.begin();
 | 
			
		||||
@@ -722,7 +740,11 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
 | 
			
		||||
  signalVector *pulse, burst, *shaped;
 | 
			
		||||
  signalVector::iterator burst_itr;
 | 
			
		||||
 | 
			
		||||
  pulse = GSMPulse->c0;
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
    pulse = GSMPulse1->c0;
 | 
			
		||||
  else
 | 
			
		||||
    pulse = GSMPulse->c0;
 | 
			
		||||
 | 
			
		||||
  burst_len = sps * (bits.size() + guard_len);
 | 
			
		||||
 | 
			
		||||
  burst = signalVector(burst_len);
 | 
			
		||||
@@ -735,7 +757,7 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
 | 
			
		||||
    burst_itr += sps;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GMSKRotate(burst);
 | 
			
		||||
  GMSKRotate(burst, sps);
 | 
			
		||||
  burst.isRealOnly(false);
 | 
			
		||||
 | 
			
		||||
  /* Single Gaussian pulse approximation shaping */
 | 
			
		||||
@@ -1018,6 +1040,7 @@ void offsetVector(signalVector &x,
 | 
			
		||||
bool generateMidamble(int sps, int tsc)
 | 
			
		||||
{
 | 
			
		||||
  bool status = true;
 | 
			
		||||
  float toa;
 | 
			
		||||
  complex *data = NULL;
 | 
			
		||||
  signalVector *autocorr = NULL, *midamble = NULL;
 | 
			
		||||
  signalVector *midMidamble = NULL, *_midMidamble = NULL;
 | 
			
		||||
@@ -1065,7 +1088,16 @@ bool generateMidamble(int sps, int tsc)
 | 
			
		||||
  gMidambles[tsc] = new CorrelationSequence;
 | 
			
		||||
  gMidambles[tsc]->buffer = data;
 | 
			
		||||
  gMidambles[tsc]->sequence = _midMidamble;
 | 
			
		||||
  gMidambles[tsc]->gain = peakDetect(*autocorr,&gMidambles[tsc]->TOA, NULL);
 | 
			
		||||
  gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
 | 
			
		||||
 | 
			
		||||
  /* For 1 sps only
 | 
			
		||||
   *     (Half of correlation length - 1) + midpoint of pulse shape + remainder
 | 
			
		||||
   *     13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
 | 
			
		||||
   */
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
    gMidambles[tsc]->toa = toa - 13.5;
 | 
			
		||||
  else
 | 
			
		||||
    gMidambles[tsc]->toa = 0;
 | 
			
		||||
 | 
			
		||||
release:
 | 
			
		||||
  delete autocorr;
 | 
			
		||||
@@ -1084,6 +1116,7 @@ release:
 | 
			
		||||
bool generateRACHSequence(int sps)
 | 
			
		||||
{
 | 
			
		||||
  bool status = true;
 | 
			
		||||
  float toa;
 | 
			
		||||
  complex *data = NULL;
 | 
			
		||||
  signalVector *autocorr = NULL;
 | 
			
		||||
  signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
 | 
			
		||||
@@ -1117,7 +1150,16 @@ bool generateRACHSequence(int sps)
 | 
			
		||||
  gRACHSequence = new CorrelationSequence;
 | 
			
		||||
  gRACHSequence->sequence = _seq1;
 | 
			
		||||
  gRACHSequence->buffer = data;
 | 
			
		||||
  gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA, NULL);
 | 
			
		||||
  gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
 | 
			
		||||
 | 
			
		||||
  /* For 1 sps only
 | 
			
		||||
   *     (Half of correlation length - 1) + midpoint of pulse shaping filer
 | 
			
		||||
   *     20.5 = (40 / 2 - 1) + 1.5
 | 
			
		||||
   */
 | 
			
		||||
  if (sps == 1)
 | 
			
		||||
    gRACHSequence->toa = toa - 20.5;
 | 
			
		||||
  else
 | 
			
		||||
    gRACHSequence->toa = 0.0;
 | 
			
		||||
 | 
			
		||||
release:
 | 
			
		||||
  delete autocorr;
 | 
			
		||||
@@ -1222,6 +1264,9 @@ static int detectBurst(signalVector &burst,
 | 
			
		||||
  if (sps == 4)
 | 
			
		||||
    *amp = *amp * complex(0.0, 1.0);
 | 
			
		||||
 | 
			
		||||
  /* Compensate for residuate time lag */
 | 
			
		||||
  *toa = *toa - sync->toa;
 | 
			
		||||
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1365,7 +1410,7 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
 | 
			
		||||
 | 
			
		||||
  // shift up by a quarter of a frequency
 | 
			
		||||
  // ignore starting phase, since spec allows for discontinuous phase
 | 
			
		||||
  GMSKReverseRotate(*shapedBurst);
 | 
			
		||||
  GMSKReverseRotate(*shapedBurst, sps);
 | 
			
		||||
 | 
			
		||||
  // run through slicer
 | 
			
		||||
  if (sps > 1) {
 | 
			
		||||
@@ -1508,8 +1553,8 @@ SoftVector *equalizeBurst(signalVector &rxBurst,
 | 
			
		||||
 | 
			
		||||
  signalVector::iterator dPtr = postForward->begin();
 | 
			
		||||
  signalVector::iterator dBackPtr;
 | 
			
		||||
  signalVector::iterator rotPtr = GMSKRotation->begin();
 | 
			
		||||
  signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
 | 
			
		||||
  signalVector::iterator rotPtr = GMSKRotationN->begin();
 | 
			
		||||
  signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
 | 
			
		||||
 | 
			
		||||
  signalVector *DFEoutput = new signalVector(postForward->size());
 | 
			
		||||
  signalVector::iterator DFEItr = DFEoutput->begin();
 | 
			
		||||
@@ -1548,3 +1593,23 @@ SoftVector *equalizeBurst(signalVector &rxBurst,
 | 
			
		||||
 | 
			
		||||
  return burstBits;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool sigProcLibSetup(int sps)
 | 
			
		||||
{
 | 
			
		||||
  if ((sps != 1) && (sps != 4))
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  initTrigTables();
 | 
			
		||||
  initGMSKRotationTables(sps);
 | 
			
		||||
 | 
			
		||||
  GSMPulse1 = generateGSMPulse(1, 2);
 | 
			
		||||
  if (sps > 1)
 | 
			
		||||
    GSMPulse = generateGSMPulse(sps, 2);
 | 
			
		||||
 | 
			
		||||
  if (!generateRACHSequence(1)) {
 | 
			
		||||
    sigProcLibDestroy();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -144,14 +144,6 @@ signalVector *convolve(const signalVector *a,
 | 
			
		||||
                       unsigned len = 0,
 | 
			
		||||
                       unsigned step = 1, int offset = 0);
 | 
			
		||||
 | 
			
		||||
/** 
 | 
			
		||||
	Generate the GSM pulse. 
 | 
			
		||||
	@param sps The number of samples per GSM symbol.
 | 
			
		||||
	@param symbolLength The size of the pulse.
 | 
			
		||||
	@return The GSM pulse.
 | 
			
		||||
*/
 | 
			
		||||
void generateGSMPulse(int sps, int symbolLength);
 | 
			
		||||
 | 
			
		||||
/** 
 | 
			
		||||
        Frequency shift a vector.
 | 
			
		||||
	@param y The frequency shifted vector.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user