aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wild <ewild@sysmocom.de>2024-02-21 19:33:09 +0100
committerEric Wild <ewild@sysmocom.de>2024-02-22 12:39:33 +0100
commitd8a1dee2c9d2ecdce7cb8d8763f3084ed80c1d0a (patch)
tree725e758338d42eb3b923eb0600cf6e373736c04a
parent56c7b777f3b897fe0d5157db4cfdaa74f5223a58 (diff)
ms: add sigproclib demod
This is basically a fixed version of ttsous ancient branch that can be used instead of the VA. Required config option part of a future patchset. Change-Id: I6558992bd69f18526be5ebe7d424ca00ceb67772
-rw-r--r--GSM/GSMCommon.cpp3
-rw-r--r--GSM/GSMCommon.h5
-rw-r--r--Transceiver52M/Resampler.cpp2
-rw-r--r--Transceiver52M/ms/ms_rx_lower.cpp112
-rw-r--r--Transceiver52M/ms/ms_upper.cpp37
-rw-r--r--Transceiver52M/sigProcLib.cpp244
-rw-r--r--Transceiver52M/sigProcLib.h14
7 files changed, 406 insertions, 11 deletions
diff --git a/GSM/GSMCommon.cpp b/GSM/GSMCommon.cpp
index 5e9e4ae..a9e2bb1 100644
--- a/GSM/GSMCommon.cpp
+++ b/GSM/GSMCommon.cpp
@@ -55,12 +55,15 @@ const BitVector GSM::gEdgeTrainingSequence[] = {
};
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
+const BitVector GSM::gDummyBurstTSC("01110001011100010111000101");
/* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
const BitVector GSM::gRACHSynchSequenceTS0("01001011011111111001100110101010001111000"); /* GSM, GMSK (default) */
const BitVector GSM::gRACHSynchSequenceTS1("01010100111110001000011000101111001001101"); /* EGPRS, 8-PSK */
const BitVector GSM::gRACHSynchSequenceTS2("11101111001001110101011000001101101110111"); /* EGPRS, GMSK */
+const BitVector GSM::gSCHSynchSequence("1011100101100010000001000000111100101101010001010111011000011011");
+
// |-head-||---------midamble----------------------||--------------data----------------||t|
const BitVector GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");
diff --git a/GSM/GSMCommon.h b/GSM/GSMCommon.h
index 48723b4..aa059c2 100644
--- a/GSM/GSMCommon.h
+++ b/GSM/GSMCommon.h
@@ -52,11 +52,16 @@ extern const BitVector gEdgeTrainingSequence[];
/** C0T0 filler burst, GSM 05.02, 5.2.6 */
extern const BitVector gDummyBurst;
+extern const BitVector gDummyBurstTSC;
/** Random access burst synch. sequence */
extern const BitVector gRACHSynchSequenceTS0;
extern const BitVector gRACHSynchSequenceTS1;
extern const BitVector gRACHSynchSequenceTS2;
+
+/** Synchronization burst sync sequence */
+extern const BitVector gSCHSynchSequence;
+
/** Random access burst synch. sequence, GSM 05.02 5.2.7 */
extern const BitVector gRACHBurst;
diff --git a/Transceiver52M/Resampler.cpp b/Transceiver52M/Resampler.cpp
index 910c7ff..841c3a9 100644
--- a/Transceiver52M/Resampler.cpp
+++ b/Transceiver52M/Resampler.cpp
@@ -32,7 +32,7 @@ extern "C" {
#define M_PI 3.14159265358979323846264338327f
#endif
-#define MAX_OUTPUT_LEN 4096
+#define MAX_OUTPUT_LEN 4096*4
using namespace std;
diff --git a/Transceiver52M/ms/ms_rx_lower.cpp b/Transceiver52M/ms/ms_rx_lower.cpp
index c2adda3..d894e96 100644
--- a/Transceiver52M/ms/ms_rx_lower.cpp
+++ b/Transceiver52M/ms/ms_rx_lower.cpp
@@ -19,6 +19,8 @@
*
*/
+#include "sigProcLib.h"
+#include "signalVector.h"
#include <atomic>
#include <cassert>
#include <complex>
@@ -155,12 +157,12 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
auto current_gsm_time = timekeeper.gsmtime();
const auto buf_len = is_first_sch_acq ? SCH_LEN_SPS : ONE_TS_BURST_LEN;
const auto which_in_buffer = is_first_sch_acq ? first_sch_buf : burst_copy_buffer;
+ memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
+#if 1
const auto which_out_buffer = is_first_sch_acq ? sch_acq_buffer : &sch_acq_buffer[40 * 2];
const auto ss = reinterpret_cast<std::complex<float> *>(which_out_buffer);
std::complex<float> channel_imp_resp[CHAN_IMP_RESP_LENGTH * d_OSR];
-
int start;
- memset((void *)&sch_acq_buffer[0], 0, sizeof(sch_acq_buffer));
convert_and_scale(which_out_buffer, which_in_buffer, buf_len * 2, 1.f / float(rxFullScale));
if (is_first_sch_acq) {
float max_corr = 0;
@@ -173,9 +175,22 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
detect_burst_nb(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
auto sch_decode_success = decode_sch(sch_demod_bits, is_first_sch_acq);
+#if 0
+ auto burst = new signalVector(buf_len, 50);
+ const auto corr_type = is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
+ struct estim_burst_params ebp;
+ // scale like uhd, +-2k -> +-32k
+ convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
+
+ auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
+
+ int howmuchdelay = ebp.toa * 4;
+ std::cerr << "ooffs: " << howmuchdelay << " " << std::endl;
+ std::cerr << "voffs: " << start << " " << sch_decode_success << std::endl;
+#endif
if (sch_decode_success) {
- const auto ts_offset_symb = 0;
+ const auto ts_offset_symb = 4;
if (is_first_sch_acq) {
// update ts to first sample in sch buffer, to allow delay calc for current ts
first_sch_ts_start = first_sch_buf_rcv_ts + start - (ts_offset_symb * 4) - 1;
@@ -190,6 +205,97 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << start << " " << current_gsm_time.FN()
<< ":" << current_gsm_time.TN() << std::endl;
}
+#else
+ const auto ts_offset_symb = 4;
+ auto burst = new signalVector(buf_len, 50);
+ const auto corr_type = is_first_sch_acq ? sch_detect_type::SCH_DETECT_BUFFER : sch_detect_type::SCH_DETECT_FULL;
+ struct estim_burst_params ebp;
+
+ // scale like uhd, +-2k -> +-32k
+ convert_and_scale(burst->begin(), which_in_buffer, buf_len * 2, SAMPLE_SCALE_FACTOR);
+
+ auto rv = detectSCHBurst(*burst, 4, 4, corr_type, &ebp);
+
+ int howmuchdelay = ebp.toa * 4;
+
+ if (!rv) {
+ delete burst;
+ DBGLG() << "SCH : \x1B[31m detect fail \033[0m NOOOOOOOOOOOOOOOOOO toa:" << ebp.toa << " "
+ << current_gsm_time.FN() << ":" << current_gsm_time.TN() << std::endl;
+ return false;
+ }
+
+ SoftVector *bits;
+ if (is_first_sch_acq) {
+ // can't be legit with a buf size spanning _at least_ one SCH but delay that implies partial sch burst
+ if (howmuchdelay < 0 || (buf_len - howmuchdelay) < ONE_TS_BURST_LEN) {
+ delete burst;
+ return false;
+ }
+
+ struct estim_burst_params ebp2;
+ // auto sch_chunk = new signalVector(ONE_TS_BURST_LEN, 50);
+ // auto sch_chunk_start = sch_chunk->begin();
+ // memcpy(sch_chunk_start, sch_buf_f.data() + howmuchdelay, sizeof(std::complex<float>) * ONE_TS_BURST_LEN);
+
+ auto delay = delayVector(burst, NULL, -howmuchdelay);
+
+ scaleVector(*delay, (complex)1.0 / ebp.amp);
+
+ auto rv2 = detectSCHBurst(*delay, 4, 4, sch_detect_type::SCH_DETECT_FULL, &ebp2);
+ DBGLG() << "FIRST SCH : " << (rv2 ? "yes " : " ") << "Timing offset " << ebp2.toa << " symbols"
+ << std::endl;
+
+ bits = demodAnyBurst(*delay, SCH, 4, &ebp2);
+ delete delay;
+ } else {
+ bits = demodAnyBurst(*burst, SCH, 4, &ebp);
+ }
+
+ delete burst;
+
+ // clamp to +-1.5 because +-127 softbits scaled by 64 after -0.5 can be at most +-1.5
+ clamp_array(bits->begin(), 148, 1.5f);
+
+ float_to_sbit(&bits->begin()[0], (signed char *)&sch_demod_bits[0], 62, 148);
+ // float_to_sbit(&bits->begin()[106], &data[39], 62, 39);
+
+ if (decode_sch((char *)sch_demod_bits, is_first_sch_acq)) {
+ auto current_gsm_time_updated = timekeeper.gsmtime();
+ if (is_first_sch_acq) {
+ // update ts to first sample in sch buffer, to allow delay calc for current ts
+ first_sch_ts_start = first_sch_buf_rcv_ts + howmuchdelay - (ts_offset_symb * 4);
+ } else {
+ // continuous sch tracking, only update if off too much
+ auto diff = [](float x, float y) { return x > y ? x - y : y - x; };
+
+ auto d = diff(ebp.toa, ts_offset_symb);
+ if (abs(d) > 0.3) {
+ if (ebp.toa < ts_offset_symb)
+ ebp.toa = d;
+ else
+ ebp.toa = -d;
+ temp_ts_corr_offset += ebp.toa * 4;
+
+ DBGLG() << "offs: " << ebp.toa << " " << temp_ts_corr_offset << std::endl;
+ }
+ }
+
+ auto a = gsm_sch_check_fn(current_gsm_time_updated.FN() - 1);
+ auto b = gsm_sch_check_fn(current_gsm_time_updated.FN());
+ auto c = gsm_sch_check_fn(current_gsm_time_updated.FN() + 1);
+ DBGLG() << "L SCH : Timing offset " << rv << " " << ebp.toa << " " << a << b << c << "fn "
+ << current_gsm_time_updated.FN() << ":" << current_gsm_time_updated.TN() << std::endl;
+
+ delete bits;
+ return true;
+ } else {
+ DBGLG2() << "L SCH : \x1B[31m decode fail \033[0m @ toa:" << ebp.toa << " " << current_gsm_time.FN()
+ << ":" << current_gsm_time.TN() << std::endl;
+ }
+
+ delete bits;
+#endif
return false;
}
diff --git a/Transceiver52M/ms/ms_upper.cpp b/Transceiver52M/ms/ms_upper.cpp
index c5664cd..2e8bc11 100644
--- a/Transceiver52M/ms/ms_upper.cpp
+++ b/Transceiver52M/ms/ms_upper.cpp
@@ -199,6 +199,7 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
return true;
}
+#if 1
convert_and_scale(ss, e.burst, ONE_TS_BURST_LEN * 2, 1.f / float(rxFullScale));
pow = energyDetect(sv, 20 * 4 /*sps*/);
@@ -232,6 +233,42 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
// detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);
#endif
}
+#else
+
+ // lower layer sch detection offset, easy to verify by just printing the detected value using both the va+sigproc code.
+ convert_and_scale(ss + 16, e.burst, ONE_TS_BURST_LEN * 2, 15);
+
+ pow = energyDetect(sv, 20 * 4 /*sps*/);
+ if (pow < -1) {
+ LOG(ALERT) << "Received empty burst";
+ return false;
+ }
+
+ avg = sqrt(pow);
+
+ /* Detect normal or RACH bursts */
+ CorrType type = CorrType::TSC;
+ struct estim_burst_params ebp;
+ auto rc = detectAnyBurst(sv, mTSC, 3, 4, type, 48, &ebp);
+ if (rc > 0) {
+ type = (CorrType)rc;
+ }
+
+ if (rc < 0) {
+ std::cerr << "UR : \x1B[31m rx fail \033[0m @ toa:" << ebp.toa << " " << e.gsmts.FN() << ":"
+ << e.gsmts.TN() << std::endl;
+ return false;
+ }
+ SoftVector *bits = demodAnyBurst(sv, type, 4, &ebp);
+
+ SoftVector::const_iterator burstItr = bits->begin();
+ // invert and fix to +-127 sbits
+ for (int ii = 0; ii < 148; ii++) {
+ demodded_softbits[ii] = *burstItr++ > 0.0f ? -127 : 127;
+ }
+ delete bits;
+
+#endif
RSSI = (int)floor(20.0 * log10(rxFullScale / avg));
// FIXME: properly handle offset, sch/nb alignment diff? handled by lower anyway...
timingOffset = (int)round(0);
diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp
index df87f94..5fac365 100644
--- a/Transceiver52M/sigProcLib.cpp
+++ b/Transceiver52M/sigProcLib.cpp
@@ -129,6 +129,8 @@ struct PulseSequence {
static CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
static CorrelationSequence *gEdgeMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
static CorrelationSequence *gRACHSequences[] = {NULL,NULL,NULL};
+static CorrelationSequence *gSCHSequence = NULL;
+static CorrelationSequence *gDummySequence = NULL;
static PulseSequence *GSMPulse1 = NULL;
static PulseSequence *GSMPulse4 = NULL;
@@ -151,6 +153,12 @@ void sigProcLibDestroy()
gRACHSequences[i] = NULL;
}
+ delete gSCHSequence;
+ gSCHSequence = NULL;
+
+ delete gDummySequence;
+ gDummySequence = NULL;
+
delete GMSKRotation1;
delete GMSKReverseRotation1;
delete GMSKRotation4;
@@ -315,6 +323,7 @@ static signalVector *convolve(const signalVector *x, const signalVector *h,
append = true;
break;
case CUSTOM:
+ // FIXME: x->getstart?
if (start < h->size() - 1) {
head = h->size() - start;
append = true;
@@ -1289,6 +1298,77 @@ release:
return status;
}
+static bool generateDummyMidamble(int sps)
+{
+ bool status = true;
+ float toa;
+ complex *data = NULL;
+ signalVector *autocorr = NULL, *midamble = NULL;
+ signalVector *midMidamble = NULL, *_midMidamble = NULL;
+
+ delete gDummySequence;
+
+ /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
+ midMidamble = modulateBurst(gDummyBurstTSC.segment(5,16), 0, sps, true);
+ if (!midMidamble)
+ return false;
+
+ /* Simulated receive sequence is pulse shaped */
+ midamble = modulateBurst(gDummyBurstTSC, 0, sps, false);
+ if (!midamble) {
+ status = false;
+ goto release;
+ }
+
+ // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
+ // the ideal TSC has an + 180 degree phase shift,
+ // due to the pi/2 frequency shift, that
+ // needs to be accounted for.
+ // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
+ scaleVector(*midMidamble, complex(-1.0, 0.0));
+ scaleVector(*midamble, complex(0.0, 1.0));
+
+ conjugateVector(*midMidamble);
+
+ /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
+ data = (complex *) convolve_h_alloc(midMidamble->size());
+ _midMidamble = new signalVector(data, 0, midMidamble->size(), convolve_h_alloc, free);
+ _midMidamble->setAligned(true);
+ midMidamble->copyTo(*_midMidamble);
+
+ autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
+ if (!autocorr) {
+ status = false;
+ goto release;
+ }
+
+ gDummySequence = new CorrelationSequence;
+ gDummySequence->sequence = _midMidamble;
+ gDummySequence->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)
+ gDummySequence->toa = toa - 13.5;
+ else
+ gDummySequence->toa = 0;
+
+release:
+ delete autocorr;
+ delete midamble;
+ delete midMidamble;
+
+ if (!status) {
+ delete _midMidamble;
+ free(data);
+ gDummySequence = NULL;
+ }
+
+ return status;
+}
+
static CorrelationSequence *generateEdgeMidamble(int tsc)
{
complex *data = NULL;
@@ -1384,6 +1464,69 @@ release:
return status;
}
+bool generateSCHSequence(int sps)
+{
+ bool status = true;
+ float toa;
+ complex *data = NULL;
+ signalVector *autocorr = NULL;
+ signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
+
+ delete gSCHSequence;
+
+ seq0 = modulateBurst(gSCHSynchSequence, 0, sps, false);
+ if (!seq0)
+ return false;
+
+ seq1 = modulateBurst(gSCHSynchSequence, 0, sps, true);
+ if (!seq1) {
+ status = false;
+ goto release;
+ }
+
+ conjugateVector(*seq1);
+
+ /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
+ data = (complex *) convolve_h_alloc(seq1->size());
+ _seq1 = new signalVector(data, 0, seq1->size(), convolve_h_alloc, free);
+ _seq1->setAligned(true);
+ seq1->copyTo(*_seq1);
+
+ autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
+ if (!autocorr) {
+ status = false;
+ goto release;
+ }
+
+ gSCHSequence = new CorrelationSequence;
+ gSCHSequence->sequence = _seq1;
+ gSCHSequence->buffer = data;
+ gSCHSequence->gain = peakDetect(*autocorr, &toa, NULL);
+
+ /* For 1 sps only
+ * (Half of correlation length - 1) + midpoint of pulse shaping filer
+ * 20.5 = (64 / 2 - 1) + 1.5
+ */
+ if (sps == 1)
+ gSCHSequence->toa = toa - 32.5;
+ else
+ gSCHSequence->toa = 0.0;
+
+release:
+ delete autocorr;
+ delete seq0;
+ delete seq1;
+
+ if (!status) {
+ delete _seq1;
+ free(data);
+ gSCHSequence = NULL;
+ }
+
+ return status;
+}
+
+
/*
* Peak-to-average computation +/- range from peak in symbols
*/
@@ -1441,14 +1584,15 @@ float energyDetect(const signalVector &rxBurst, unsigned windowLength)
return energy/windowLength;
}
-static signalVector *downsampleBurst(const signalVector &burst)
+static signalVector *downsampleBurst(const signalVector &burst, int in_len = DOWNSAMPLE_IN_LEN,
+ int out_len = DOWNSAMPLE_OUT_LEN)
{
- signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
- signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
- burst.copyToSegment(in, 0, DOWNSAMPLE_IN_LEN);
+ signalVector in(in_len, dnsampler->len());
+ // gSCHSequence->sequence->size(), ensure next conv has no realloc
+ signalVector *out = new signalVector(out_len, 64);
+ burst.copyToSegment(in, 0, in_len);
- if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
- (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
+ if (dnsampler->rotate((float *)in.begin(), in_len, (float *)out->begin(), out_len) < 0) {
delete out;
out = NULL;
}
@@ -1469,6 +1613,12 @@ static float computeCI(const signalVector *burst, const CorrelationSequence *syn
/* Integer position where the sequence starts */
const int ps = start + 1 - N + (int)roundf(toa);
+ if(ps < 0) // might be -22 for toa 40 with N=64, if off by a lot during sch ms sync
+ return 0;
+
+ if (ps + N > (int)burst->size())
+ return 0;
+
/* Estimate Signal power */
S = 0.0f;
for (int i=0, j=ps; i<(int)N; i++,j++)
@@ -1652,6 +1802,80 @@ static int detectRACHBurst(const signalVector &burst, float threshold, int sps,
return rc;
}
+int detectSCHBurst(signalVector &burst,
+ float thresh,
+ int sps,
+ sch_detect_type state, struct estim_burst_params *ebp)
+{
+ int rc, start, target, head, tail, len;
+ complex _amp;
+ CorrelationSequence *sync;
+
+ if ((sps != 1) && (sps != 4))
+ return -1;
+
+ target = 3 + 39 + 64;
+
+ switch (state) {
+ case sch_detect_type::SCH_DETECT_NARROW:
+ head = 4;
+ tail = 4;
+ break;
+ case sch_detect_type::SCH_DETECT_BUFFER:
+ target = 1;
+ head = 0;
+ tail = (12 * 8 * 625) / 4; // 12 frames, downsampled /4 to 1 sps
+ break;
+ case sch_detect_type::SCH_DETECT_FULL:
+ default:
+ head = target - 1;
+ tail = 39 + 3 + 9;
+ break;
+ }
+
+ start = (target - head) * 1 - 1;
+ len = (head + tail) * 1;
+ sync = gSCHSequence;
+ signalVector corr(len);
+
+ signalVector *dec = downsampleBurst(burst, len * 4, len);
+ rc = detectBurst(*dec, corr, sync, thresh, 1, start, len, ebp);
+ delete dec;
+
+ if (rc < 0) {
+ return -1;
+ } else if (!rc) {
+ ebp->amp = 0.0f;
+ ebp->toa = 0.0f;
+ return 0;
+ }
+
+ if (state == sch_detect_type::SCH_DETECT_BUFFER)
+ ebp->toa = ebp->toa - (3 + 39 + 64);
+ else {
+ /* Subtract forward search bits from delay */
+ ebp->toa = ebp->toa - head;
+ }
+
+ return rc;
+}
+
+static int detectDummyBurst(const signalVector &burst, float threshold,
+ int sps, unsigned max_toa, struct estim_burst_params *ebp)
+{
+ int rc, target, head, tail;
+ CorrelationSequence *sync;
+
+ target = 3 + 58 + 16 + 5;
+ head = 10;
+ tail = 6 + max_toa;
+ sync = gDummySequence;
+
+ ebp->tsc = 0;
+ rc = detectGeneralBurst(burst, threshold, sps, target, head, tail, sync, ebp);
+ return rc;
+}
+
/*
* Normal burst detection
*
@@ -1670,7 +1894,7 @@ static int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float th
return -SIGERR_UNSUPPORTED;
target = 3 + 58 + 16 + 5;
- head = 6;
+ head = 10;
tail = 6 + max_toa;
sync = gMidambles[tsc];
@@ -1719,6 +1943,9 @@ int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
case RACH:
rc = detectRACHBurst(burst, threshold, sps, max_toa, type == EXT_RACH, ebp);
break;
+ case IDLE:
+ rc = detectDummyBurst(burst, threshold, sps, max_toa, ebp);
+ break;
default:
LOG(ERR) << "Invalid correlation type";
}
@@ -1921,6 +2148,9 @@ bool sigProcLibSetup()
generateRACHSequence(&gRACHSequences[1], gRACHSynchSequenceTS1, 1);
generateRACHSequence(&gRACHSequences[2], gRACHSynchSequenceTS2, 1);
+ generateSCHSequence(1);
+ generateDummyMidamble(1);
+
for (int tsc = 0; tsc < 8; tsc++) {
generateMidamble(1, tsc);
gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
diff --git a/Transceiver52M/sigProcLib.h b/Transceiver52M/sigProcLib.h
index 0c3c7c6..39c8ddd 100644
--- a/Transceiver52M/sigProcLib.h
+++ b/Transceiver52M/sigProcLib.h
@@ -31,6 +31,7 @@ enum CorrType{
TSC, ///< timeslot should contain a normal burst
EXT_RACH, ///< timeslot should contain an extended access burst
RACH, ///< timeslot should contain an access burst
+ SCH,
EDGE, ///< timeslot should contain an EDGE burst
IDLE ///< timeslot is an idle (or dummy) burst
};
@@ -93,6 +94,8 @@ signalVector *generateDummyBurst(int sps, int tn);
void scaleVector(signalVector &x,
complex scale);
+signalVector *delayVector(const signalVector *in, signalVector *out, float delay);
+
/**
Rough energy estimator.
@param rxBurst A GSM burst.
@@ -133,6 +136,17 @@ int detectAnyBurst(const signalVector &burst,
unsigned max_toa,
struct estim_burst_params *ebp);
+enum class sch_detect_type {
+ SCH_DETECT_FULL,
+ SCH_DETECT_NARROW,
+ SCH_DETECT_BUFFER,
+};
+
+int detectSCHBurst(signalVector &rxBurst,
+ float detectThreshold,
+ int sps,
+ sch_detect_type state, struct estim_burst_params *ebp);
+
/** Demodulate burst basde on type and output soft bits */
SoftVector *demodAnyBurst(const signalVector &burst, CorrType type,
int sps, struct estim_burst_params *ebp);