Transceiver52M: Setup dual Laurent pulse filter

Provides improved transmit phase error performance below
1 degree RMS on certain devices. Requires use of 4
samples-per-symbol.

Signed-off-by: Thomas Tsou <tom@tsou.cc>
This commit is contained in:
Thomas Tsou 2013-09-05 05:08:09 -04:00
parent ef7c258cbf
commit 3e24f791dd
3 changed files with 173 additions and 44 deletions

View File

@ -78,7 +78,7 @@ static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 3] = {
{ B100, 4, 2.9418e-5 },
{ UMTRX, 1, 9.1738e-5 },
{ UMTRX, 2, 0.0 },
{ UMTRX, 4, 0.0 },
{ UMTRX, 4, 4.1813e-5 },
};
static double get_dev_offset(enum uhd_dev_type type, int sps)

View File

@ -23,7 +23,7 @@
#include "radioClock.h"
/** samples per GSM symbol */
#define SAMPSPERSYM 1
#define SAMPSPERSYM 4
#define INCHUNK (625)
#define OUTCHUNK (625)
#define CHAN_MAX 2

View File

@ -77,20 +77,25 @@ struct CorrelationSequence {
* for SSE instructions.
*/
struct PulseSequence {
PulseSequence() : gaussian(NULL), empty(NULL), buffer(NULL)
PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
c0_buffer(NULL), c1_buffer(NULL)
{
}
~PulseSequence()
{
delete gaussian;
delete c0;
delete c1;
delete empty;
free(buffer);
free(c0_buffer);
free(c1_buffer);
}
signalVector *gaussian;
signalVector *c0;
signalVector *c1;
signalVector *empty;
void *buffer;
void *c0_buffer;
void *c1_buffer;
};
CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
@ -259,7 +264,7 @@ void initGMSKRotationTables(int sps)
bool sigProcLibSetup(int sps)
{
if ((sps != 1) && (sps != 2) && (sps != 4))
if (sps != 4)
return false;
initTrigTables();
@ -409,10 +414,48 @@ signalVector *convolve(const signalVector *x,
return y;
}
bool generateC1Pulse(int sps)
{
int len;
switch (sps) {
case 4:
len = 8;
break;
default:
return false;
}
GSMPulse->c1_buffer = convolve_h_alloc(len);
GSMPulse->c1 = new signalVector((complex *)
GSMPulse->c1_buffer, 0, len);
GSMPulse->c1->isRealOnly(true);
/* Enable alignment for SSE usage */
GSMPulse->c1->setAligned(true);
signalVector::iterator xP = GSMPulse->c1->begin();
switch (sps) {
case 4:
/* BT = 0.30 */
*xP++ = 0.0;
*xP++ = 8.16373112e-03;
*xP++ = 2.84385729e-02;
*xP++ = 5.64158904e-02;
*xP++ = 7.05463553e-02;
*xP++ = 5.64158904e-02;
*xP++ = 2.84385729e-02;
*xP++ = 8.16373112e-03;
}
return true;
}
void generateGSMPulse(int sps, int symbolLength)
{
int len;
float arg, center;
float arg, avg, center;
delete GSMPulse;
@ -438,15 +481,18 @@ void generateGSMPulse(int sps, int symbolLength)
len = 4;
}
GSMPulse->buffer = convolve_h_alloc(len);
GSMPulse->gaussian = new signalVector((complex *)
GSMPulse->buffer, 0, len);
GSMPulse->gaussian->setAligned(true);
GSMPulse->gaussian->isRealOnly(true);
GSMPulse->c0_buffer = convolve_h_alloc(len);
GSMPulse->c0 = new signalVector((complex *)
GSMPulse->c0_buffer, 0, len);
GSMPulse->c0->isRealOnly(true);
signalVector::iterator xP = GSMPulse->gaussian->begin();
/* Enable alingnment for SSE usage */
GSMPulse->c0->setAligned(true);
signalVector::iterator xP = GSMPulse->c0->begin();
if (sps == 4) {
*xP++ = 0.0;
*xP++ = 4.46348606e-03;
*xP++ = 2.84385729e-02;
*xP++ = 1.03184855e-01;
@ -462,7 +508,7 @@ void generateGSMPulse(int sps, int symbolLength)
*xP++ = 1.03184855e-01;
*xP++ = 2.84385729e-02;
*xP++ = 4.46348606e-03;
*xP++ = 0.0;
generateC1Pulse(sps);
} else {
center = (float) (len - 1.0) / 2.0;
@ -472,12 +518,12 @@ void generateGSMPulse(int sps, int symbolLength)
*xP++ = 0.96 * exp(-1.1380 * arg * arg -
0.527 * arg * arg * arg * arg);
}
}
float avgAbsval = sqrtf(vectorNorm2(*GSMPulse->gaussian)/sps);
xP = GSMPulse->gaussian->begin();
for (int i = 0; i < len; i++)
*xP++ /= avgAbsval;
avg = sqrtf(vectorNorm2(*GSMPulse->c0) / sps);
xP = GSMPulse->c0->begin();
for (int i = 0; i < len; i++)
*xP++ /= avg;
}
}
signalVector* frequencyShift(signalVector *y,
@ -559,40 +605,119 @@ bool vectorSlicer(signalVector *x)
return true;
}
static signalVector *rotateBurst(const BitVector &wBurst,
int guardPeriodLength, int sps)
{
int burst_len;
signalVector *pulse, rotated, *shaped;
signalVector::iterator itr;
pulse = GSMPulse->empty;
burst_len = sps * (wBurst.size() + guardPeriodLength);
rotated = signalVector(burst_len);
itr = rotated.begin();
for (unsigned i = 0; i < wBurst.size(); i++) {
*itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
itr += sps;
}
GMSKRotate(rotated);
rotated.isRealOnly(false);
/* Dummy filter operation */
shaped = convolve(&rotated, pulse, NULL, START_ONLY);
if (!shaped)
return NULL;
return shaped;
}
/* Assume input bits are not differentially encoded */
signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
int sps, bool emptyPulse)
{
int burstLen;
signalVector *pulse, *shapedBurst, modBurst;
signalVector::iterator modBurstItr;
int burst_len;
float phase;
signalVector *c0_pulse, *c1_pulse, c0_burst, c1_burst, *c0_shaped, *c1_shaped;
signalVector::iterator c0_itr, c1_itr;
if (emptyPulse)
pulse = GSMPulse->empty;
else
pulse = GSMPulse->gaussian;
return rotateBurst(wBurst, guardPeriodLength, sps);
burstLen = sps * (wBurst.size() + guardPeriodLength);
modBurst = signalVector(burstLen);
modBurstItr = modBurst.begin();
/*
* Apply before and after bits to reduce phase error at burst edges.
* Make sure there is enough room in the burst to accodmodate the bits.
*/
if (guardPeriodLength < 4)
guardPeriodLength = 4;
for (unsigned int i = 0; i < wBurst.size(); i++) {
*modBurstItr = 2.0*(wBurst[i] & 0x01)-1.0;
modBurstItr += sps;
c0_pulse = GSMPulse->c0;
c1_pulse = GSMPulse->c1;
burst_len = sps * (wBurst.size() + guardPeriodLength);
c0_burst = signalVector(burst_len);
c0_burst.isRealOnly(true);
c0_itr = c0_burst.begin();
c1_burst = signalVector(burst_len);
c1_burst.isRealOnly(true);
c1_itr = c1_burst.begin();
/* Padded differential start bits */
*c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
c0_itr += sps;
/* Main burst bits */
for (unsigned i = 0; i < wBurst.size(); i++) {
*c0_itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
c0_itr += sps;
}
// shift up pi/2
// ignore starting phase, since spec allows for discontinuous phase
GMSKRotate(modBurst);
/* Padded differential end bits */
*c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
modBurst.isRealOnly(false);
GMSKRotate(c0_burst);
c0_burst.isRealOnly(false);
// filter w/ pulse shape
shapedBurst = convolve(&modBurst, pulse, NULL, START_ONLY);
if (!shapedBurst)
return NULL;
c0_itr = c0_burst.begin();
c0_itr += sps * 2;
c1_itr += sps * 2;
return shapedBurst;
/* Start magic */
phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
*c1_itr = *c0_itr * Complex<float>(0, phase);
c0_itr += sps;
c1_itr += sps;
/* Generate C1 phase coefficients */
for (unsigned i = 2; i < wBurst.size(); i++) {
phase = 2.0 * ((wBurst[i - 1] & 0x01) ^ (wBurst[i - 2] & 0x01)) - 1.0;
*c1_itr = *c0_itr * Complex<float>(0, phase);
c0_itr += sps;
c1_itr += sps;
}
/* End magic */
int i = wBurst.size();
phase = 2.0 * ((wBurst[i-1] & 0x01) ^ (wBurst[i-2] & 0x01)) - 1.0;
*c1_itr = *c0_itr * Complex<float>(0, phase);
/* Primary (C0) and secondary (C1) pulse shaping */
c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
/* Sum pulse shaped outputs */
c0_itr = c0_shaped->begin();
c1_itr = c1_shaped->begin();
for (unsigned i = 0; i < c0_shaped->size(); i++ )
*c0_itr++ += *c1_itr++;
delete c1_shaped;
return c0_shaped;
}
float sinc(float x)
@ -1087,8 +1212,10 @@ int detectRACHBurst(signalVector &rxBurst,
/* Subtract forward search bits from delay */
if (toa)
*toa = _toa - head * sps;
/* Compensate for unknown rotation */
if (amp)
*amp = _amp;
*amp = _amp * complex(0.0, 1.0);
return 1;
}
@ -1139,8 +1266,10 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
_toa -= head * sps;
if (toa)
*toa = _toa;
/* Compensate for unknown rotation */
if (amp)
*amp = _amp;
*amp = _amp * complex(0, 1.0);
/* Equalization not currently supported */
if (chan_req) {