aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric <ewild@sysmocom.de>2023-01-09 22:46:41 +0100
committerlaforge <laforge@osmocom.org>2023-08-25 13:17:56 +0000
commita5a2275a085b55dd8391e0e5bb21190579145a7b (patch)
tree40449dee9f990c0d9ecd065966706a5599878321
parent1499f0343a78521c43c1656221abd1944b1ab5e7 (diff)
ms: restructure the va code to add rach support
This commit adds support for rach bursts to the viterbi equalizer, which is currently only being used by the ms side, so the equalizer can be used by the osmo-trx network side, too. The difference is that rach bursts are shorter than any other burst type (due to unknown TA) and start with diffrent tail bits. This drops the multiversioning which was only working for x86 anyway because it can't be combined with no_ubsan. Change-Id: I4a5cedc8c9a3289c75ce7b914eac286e601ebed0
-rw-r--r--Transceiver52M/grgsm_vitac/constants.h7
-rw-r--r--Transceiver52M/grgsm_vitac/grgsm_vitac.cpp190
-rw-r--r--Transceiver52M/grgsm_vitac/grgsm_vitac.h8
-rw-r--r--Transceiver52M/ms/ms_rx_lower.cpp2
-rw-r--r--Transceiver52M/ms/ms_upper.cpp2
5 files changed, 113 insertions, 96 deletions
diff --git a/Transceiver52M/grgsm_vitac/constants.h b/Transceiver52M/grgsm_vitac/constants.h
index 07f2290..27bf6f4 100644
--- a/Transceiver52M/grgsm_vitac/constants.h
+++ b/Transceiver52M/grgsm_vitac/constants.h
@@ -38,6 +38,7 @@
#define STEALING_BIT 1
#define N_TRAIN_BITS 26
#define N_SYNC_BITS 64
+#define N_ACCESS_BITS 41
#define USEFUL_BITS 142 //(2*(DATA_BITS+STEALING_BIT) + N_TRAIN_BITS )
#define FCCH_BITS USEFUL_BITS
#define BURST_SIZE (USEFUL_BITS+2*TAIL_BITS)
@@ -73,6 +74,12 @@ static const unsigned char SYNC_BITS[] = {
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1
};
+static const unsigned char ACCESS_BITS [] = {
+ 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0
+};
+
const unsigned FCCH_FRAMES[] = { 0, 10, 20, 30, 40 };
const unsigned SCH_FRAMES[] = { 1, 11, 21, 31, 41 };
diff --git a/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp b/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp
index 836c555..5779d9d 100644
--- a/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp
+++ b/Transceiver52M/grgsm_vitac/grgsm_vitac.cpp
@@ -39,13 +39,13 @@
#include "viterbi_detector.h"
#include "grgsm_vitac.h"
-//signalVector mChanResp;
+gr_complex d_acc_training_seq[N_ACCESS_BITS]; ///<encoded training sequence of a RACH burst
gr_complex d_sch_training_seq[N_SYNC_BITS]; ///<encoded training sequence of a SCH burst
gr_complex d_norm_training_seq[TRAIN_SEQ_NUM][N_TRAIN_BITS]; ///<encoded training sequences of a normal and dummy burst
const int d_chan_imp_length = CHAN_IMP_RESP_LENGTH;
-void initvita() {
-
+void initvita()
+{
/**
* Prepare SCH sequence bits
*
@@ -53,59 +53,72 @@ void initvita() {
* Burst and two guard periods
* (one guard period is an arbitrary overlap)
*/
- gmsk_mapper(SYNC_BITS, N_SYNC_BITS,
- d_sch_training_seq, gr_complex(0.0, -1.0));
+ gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0));
for (auto &i : d_sch_training_seq)
i = conj(i);
+ /* ab */
+ gmsk_mapper(ACCESS_BITS, N_ACCESS_BITS, d_acc_training_seq, gr_complex(0.0, -1.0));
+ for (auto &i : d_acc_training_seq)
+ i = conj(i);
+
/* Prepare bits of training sequences */
for (int i = 0; i < TRAIN_SEQ_NUM; i++) {
/**
* If first bit of the sequence is 0
* => first symbol is 1, else -1
*/
- gr_complex startpoint = train_seq[i][0] == 0 ?
- gr_complex(1.0, 0.0) : gr_complex(-1.0, 0.0);
- gmsk_mapper(train_seq[i], N_TRAIN_BITS,
- d_norm_training_seq[i], startpoint);
+ gr_complex startpoint = train_seq[i][0] == 0 ? gr_complex(1.0, 0.0) : gr_complex(-1.0, 0.0);
+ gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint);
for (auto &i : d_norm_training_seq[i])
i = conj(i);
}
-
}
-MULTI_VER_TARGET_ATTR NO_UBSAN
-void detect_burst(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary)
+template <unsigned int burst_size>
+NO_UBSAN static void detect_burst_generic(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start,
+ char *output_binary, int ss)
{
std::vector<gr_complex> rhh_temp(CHAN_IMP_RESP_LENGTH * d_OSR);
unsigned int stop_states[2] = { 4, 12 };
- gr_complex filtered_burst[BURST_SIZE];
+ gr_complex filtered_burst[burst_size];
gr_complex rhh[CHAN_IMP_RESP_LENGTH];
- float output[BURST_SIZE];
- int start_state = 3;
-
- // if(burst_start < 0 ||burst_start > 10)
- // fprintf(stderr, "bo %d\n", burst_start);
-
- // burst_start = burst_start >= 0 ? burst_start : 0;
+ float output[burst_size];
+ int start_state = ss;
autocorrelation(chan_imp_resp, &rhh_temp[0], d_chan_imp_length * d_OSR);
for (int ii = 0; ii < d_chan_imp_length; ii++)
rhh[ii] = conj(rhh_temp[ii * d_OSR]);
- mafi(&input[burst_start], BURST_SIZE, chan_imp_resp,
- d_chan_imp_length * d_OSR, filtered_burst);
+ mafi(&input[burst_start], burst_size, chan_imp_resp, d_chan_imp_length * d_OSR, filtered_burst);
+
+ viterbi_detector(filtered_burst, burst_size, rhh, start_state, stop_states, 2, output);
+
+ for (unsigned int i = 0; i < burst_size; i++)
+ output_binary[i] = (char)(output[i] * -127); // pre flip bits!
+}
- viterbi_detector(filtered_burst, BURST_SIZE, rhh,
- start_state, stop_states, 2, output);
+NO_UBSAN void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary,
+ int ss)
+{
+ return detect_burst_generic<BURST_SIZE>(input, chan_imp_resp, burst_start, output_binary, ss);
+}
+NO_UBSAN void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary,
+ int ss)
+{
+ return detect_burst_generic<8 + 41 + 36 + 3>(input, chan_imp_resp, burst_start, output_binary, ss);
+}
- for (int i = 0; i < BURST_SIZE; i++)
- output_binary[i] = output[i] * -127; // pre flip bits!
+NO_UBSAN void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary)
+{
+ return detect_burst_nb(input, chan_imp_resp, burst_start, output_binary, 3);
+}
+NO_UBSAN void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary)
+{
+ return detect_burst_ab(input, chan_imp_resp, burst_start, output_binary, 3);
}
-void
-gmsk_mapper(const unsigned char* input,
- int nitems, gr_complex* gmsk_output, gr_complex start_point)
+void gmsk_mapper(const unsigned char *input, int nitems, gr_complex *gmsk_output, gr_complex start_point)
{
gr_complex j = gr_complex(0.0, 1.0);
gmsk_output[0] = start_point;
@@ -122,16 +135,13 @@ gmsk_mapper(const unsigned char* input,
encoded_symbol = current_symbol * previous_symbol;
/* And do GMSK mapping */
- gmsk_output[i] = j * gr_complex(encoded_symbol, 0.0)
- * gmsk_output[i - 1];
+ gmsk_output[i] = j * gr_complex(encoded_symbol, 0.0) * gmsk_output[i - 1];
previous_symbol = current_symbol;
}
}
-gr_complex
-correlate_sequence(const gr_complex* sequence,
- int length, const gr_complex* input)
+gr_complex correlate_sequence(const gr_complex *sequence, int length, const gr_complex *input)
{
gr_complex result(0.0, 0.0);
@@ -142,9 +152,7 @@ correlate_sequence(const gr_complex* sequence,
}
/* Computes autocorrelation for positive arguments */
-inline void
-autocorrelation(const gr_complex* input,
- gr_complex* out, int nitems)
+inline void autocorrelation(const gr_complex *input, gr_complex *out, int nitems)
{
for (int k = nitems - 1; k >= 0; k--) {
out[k] = gr_complex(0, 0);
@@ -153,9 +161,7 @@ autocorrelation(const gr_complex* input,
}
}
-inline void
-mafi(const gr_complex* input, int nitems,
- gr_complex* filter, int filter_length, gr_complex* output)
+inline void mafi(const gr_complex *input, int nitems, gr_complex *filter, int filter_length, gr_complex *output)
{
for (int n = 0; n < nitems; n++) {
int a = n * d_OSR;
@@ -170,66 +176,45 @@ mafi(const gr_complex* input, int nitems,
}
}
-int get_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, int search_center, int search_start_pos,
- int search_stop_pos, gr_complex *tseq, int tseqlen, float *corr_max)
+int get_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, int search_start_pos, int search_stop_pos,
+ gr_complex *tseq, int tseqlen, float *corr_max)
{
- std::vector<gr_complex> correlation_buffer;
+ const int num_search_windows = search_stop_pos - search_start_pos;
+ const int power_search_window_len = d_chan_imp_length * d_OSR;
std::vector<float> window_energy_buffer;
std::vector<float> power_buffer;
+ std::vector<gr_complex> correlation_buffer;
+
+ power_buffer.reserve(num_search_windows);
+ correlation_buffer.reserve(num_search_windows);
+ window_energy_buffer.reserve(num_search_windows);
- for (int ii = search_start_pos; ii < search_stop_pos; ii++) {
- gr_complex correlation = correlate_sequence(tseq, tseqlen, &input[ii]);
+ for (int ii = 0; ii < num_search_windows; ii++) {
+ gr_complex correlation = correlate_sequence(tseq, tseqlen, &input[search_start_pos + ii]);
correlation_buffer.push_back(correlation);
power_buffer.push_back(std::pow(abs(correlation), 2));
}
- int strongest_corr_nr = max_element(power_buffer.begin(), power_buffer.end()) - power_buffer.begin();
-
/* Compute window energies */
- auto window_energy_start_offset = strongest_corr_nr - 6 * d_OSR;
- window_energy_start_offset = window_energy_start_offset < 0 ? 0 : window_energy_start_offset; //can end up out of range..
- auto window_energy_end_offset = strongest_corr_nr + 6 * d_OSR + d_chan_imp_length * d_OSR;
- auto iter = power_buffer.begin() + window_energy_start_offset;
- auto iter_end = power_buffer.begin() + window_energy_end_offset;
- while (iter != iter_end) {
- std::vector<float>::iterator iter_ii = iter;
- bool loop_end = false;
- float energy = 0;
-
- int len = d_chan_imp_length * d_OSR;
- for (int ii = 0; ii < len; ii++, iter_ii++) {
- if (iter_ii == power_buffer.end()) {
- loop_end = true;
- break;
- }
+ float windowSum = 0;
- energy += (*iter_ii);
- }
-
- if (loop_end)
- break;
+ // first window
+ for (int i = 0; i < power_search_window_len; i++) {
+ windowSum += power_buffer[i];
+ }
+ window_energy_buffer.push_back(windowSum);
- window_energy_buffer.push_back(energy);
- iter++;
+ // slide windows
+ for (int i = power_search_window_len; i < num_search_windows; i++) {
+ windowSum += power_buffer[i] - power_buffer[i - power_search_window_len];
+ window_energy_buffer.push_back(windowSum);
}
- /* Calculate the strongest window number */
- int strongest_window_nr = window_energy_start_offset +
- max_element(window_energy_buffer.begin(), window_energy_buffer.end()) -
+ int strongest_window_nr = std::max_element(window_energy_buffer.begin(), window_energy_buffer.end()) -
window_energy_buffer.begin();
- // auto window_search_start = window_energy_buffer.begin() + strongest_corr_nr - 5* d_OSR;
- // auto window_search_end = window_energy_buffer.begin() + strongest_corr_nr + 10* d_OSR;
- // window_search_end = window_search_end >= window_energy_buffer.end() ? window_energy_buffer.end() : window_search_end;
-
- // /* Calculate the strongest window number */
- // int strongest_window_nr = max_element(window_search_start, window_search_end /* - d_chan_imp_length * d_OSR*/) - window_energy_buffer.begin();
-
- // if (strongest_window_nr < 0)
- // strongest_window_nr = 0;
-
float max_correlation = 0;
- for (int ii = 0; ii < d_chan_imp_length * d_OSR; ii++) {
+ for (int ii = 0; ii < power_search_window_len; ii++) {
gr_complex correlation = correlation_buffer[strongest_window_nr + ii];
if (abs(correlation) > max_correlation)
max_correlation = abs(correlation);
@@ -242,7 +227,27 @@ int get_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, int se
* Compute first sample position, which corresponds
* to the first sample of the impulse response
*/
- return search_start_pos + strongest_window_nr - search_center * d_OSR;
+ return search_start_pos + strongest_window_nr;
+}
+
+/*
+8 ext tail bits
+41 sync seq
+36 encrypted bits
+3 tail bits
+68.25 extended tail bits (!)
+
+center at 8+5 (actually known tb -> known isi, start at 8?) FIXME
+*/
+int get_access_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, float *corr_max, int max_delay)
+{
+ const int search_center = 8 + 5;
+ const int search_start_pos = (search_center - 5) * d_OSR + 1;
+ const int search_stop_pos = (search_center + 5 + d_chan_imp_length + max_delay) * d_OSR;
+ const auto tseq = &d_acc_training_seq[TRAIN_BEGINNING];
+ const auto tseqlen = N_ACCESS_BITS - (2 * TRAIN_BEGINNING);
+ return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, corr_max) -
+ search_center * d_OSR;
}
/*
@@ -260,8 +265,8 @@ int get_norm_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, f
const int search_stop_pos = (search_center + 5 + d_chan_imp_length) * d_OSR;
const auto tseq = &d_norm_training_seq[bcc][TRAIN_BEGINNING];
const auto tseqlen = N_TRAIN_BITS - (2 * TRAIN_BEGINNING);
- return get_chan_imp_resp(input, chan_imp_resp, search_center, search_start_pos, search_stop_pos, tseq, tseqlen,
- corr_max);
+ return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, corr_max) -
+ search_center * d_OSR;
}
/*
@@ -281,8 +286,9 @@ int get_sch_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp)
// strongest_window_nr + chan_imp_resp_center + SYNC_POS *d_OSR - 48 * d_OSR - 2 * d_OSR + 2 ;
float corr_max;
- return get_chan_imp_resp(input, chan_imp_resp, search_center, search_start_pos, search_stop_pos, tseq, tseqlen,
- &corr_max);
+ return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, &corr_max) -
+ search_center * d_OSR;
+ ;
}
int get_sch_buffer_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, unsigned int len, float *corr_max)
@@ -291,9 +297,9 @@ int get_sch_buffer_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_r
const int search_center = SYNC_POS + TRAIN_BEGINNING;
const int search_start_pos = 0;
// FIXME: proper end offset
- const int search_stop_pos = len - (N_SYNC_BITS*8);
+ const int search_stop_pos = len - (N_SYNC_BITS * 8);
auto tseq = &d_sch_training_seq[TRAIN_BEGINNING];
- return get_chan_imp_resp(input, chan_imp_resp, search_center, search_start_pos, search_stop_pos, tseq, tseqlen,
- corr_max);
+ return get_chan_imp_resp(input, chan_imp_resp, search_start_pos, search_stop_pos, tseq, tseqlen, corr_max) -
+ search_center * d_OSR;
} \ No newline at end of file
diff --git a/Transceiver52M/grgsm_vitac/grgsm_vitac.h b/Transceiver52M/grgsm_vitac/grgsm_vitac.h
index 2c89d8c..d00c3ad 100644
--- a/Transceiver52M/grgsm_vitac/grgsm_vitac.h
+++ b/Transceiver52M/grgsm_vitac/grgsm_vitac.h
@@ -58,8 +58,11 @@ void initvita();
int process_vita_burst(gr_complex *input, int tsc, unsigned char *output_binary);
int process_vita_sc_burst(gr_complex *input, int tsc, unsigned char *output_binary, int *offset);
-MULTI_VER_TARGET_ATTR_CLANGONLY
-void detect_burst(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary);
+void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary, int ss);
+void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary, int ss);
+void detect_burst_nb(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary);
+void detect_burst_ab(const gr_complex *input, gr_complex *chan_imp_resp, int burst_start, char *output_binary);
+
void gmsk_mapper(const unsigned char *input, int nitems, gr_complex *gmsk_output, gr_complex start_point);
gr_complex correlate_sequence(const gr_complex *sequence, int length, const gr_complex *input);
inline void autocorrelation(const gr_complex *input, gr_complex *out, int nitems);
@@ -67,6 +70,7 @@ inline void mafi(const gr_complex *input, int nitems, gr_complex *filter, int fi
int get_sch_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp);
int get_norm_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, float *corr_max, int bcc);
int get_sch_buffer_chan_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, unsigned int len, float *corr_max);
+int get_access_imp_resp(const gr_complex *input, gr_complex *chan_imp_resp, float *corr_max, int max_delay);
enum class btype { NB, SCH };
struct fdata {
diff --git a/Transceiver52M/ms/ms_rx_lower.cpp b/Transceiver52M/ms/ms_rx_lower.cpp
index 5a07df5..c2adda3 100644
--- a/Transceiver52M/ms/ms_rx_lower.cpp
+++ b/Transceiver52M/ms/ms_rx_lower.cpp
@@ -170,7 +170,7 @@ bool ms_trx::handle_sch(bool is_first_sch_acq)
start = start < 39 ? start : 39;
start = start > -39 ? start : -39;
}
- detect_burst(&ss[start], &channel_imp_resp[0], 0, sch_demod_bits);
+ 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);
diff --git a/Transceiver52M/ms/ms_upper.cpp b/Transceiver52M/ms/ms_upper.cpp
index 0a2c333..3c34efe 100644
--- a/Transceiver52M/ms/ms_upper.cpp
+++ b/Transceiver52M/ms/ms_upper.cpp
@@ -196,7 +196,7 @@ bool upper_trx::pullRadioVector(GSM::Time &wTime, int &RSSI, int &timingOffset)
// fprintf(stderr, "%s %d\n", (is_nb ? "N":"D"), burst_time.FN());
// if (is_nb)
#endif
- detect_burst(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
+ detect_burst_nb(ss, &chan_imp_resp[0], normal_burst_start, demodded_softbits);
#ifdef DBGXX
// else
// detect_burst(ss, &chan_imp_resp2[0], dummy_burst_start, outbin);