aboutsummaryrefslogtreecommitdiffstats
path: root/Transceiver52M/fbsb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Transceiver52M/fbsb.cpp')
-rw-r--r--Transceiver52M/fbsb.cpp148
1 files changed, 148 insertions, 0 deletions
diff --git a/Transceiver52M/fbsb.cpp b/Transceiver52M/fbsb.cpp
new file mode 100644
index 0000000..870b28c
--- /dev/null
+++ b/Transceiver52M/fbsb.cpp
@@ -0,0 +1,148 @@
+#include <atomic>
+#include "radioInterface.h"
+#include "Interthread.h"
+#include "GSMCommon.h"
+//#include "Sockets.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+static const auto tssize = 156.25;
+static const auto framee_to_read = 12;
+static const auto ts_to_read = framee_to_read * 8;
+static const int fbsb_chunk_len = ts_to_read * 2 * tssize; // contiguous fcch+sch guaranteed
+static const auto corr_offset = 0;
+
+struct fbsb_par {
+
+ enum class fbsb_state {
+ IDLE,
+ INIT,
+ ACQ,
+ WAIT,
+ ACQ_COMPL,
+ DONE
+ };
+
+ int pos;
+ int time_idx;
+ std::atomic<fbsb_state> s;
+ GSM::Time rcvClock[ts_to_read];
+ complex fbsb_buf[fbsb_chunk_len+corr_offset];
+ complex conjbuf[fbsb_chunk_len+corr_offset];
+ complex avgbuf[fbsb_chunk_len+corr_offset];
+ void addclk(GSM::Time c) { rcvClock[time_idx] = c; time_idx++; return;}
+public:
+ fbsb_par() : s(fbsb_state::IDLE) {
+ reset();
+ };
+ bool done() {return !(time_idx < ts_to_read);}
+ void take(void* addr, int num_cplx_sps, GSM::Time c) {
+ memcpy(fbsb_buf+pos+corr_offset,addr, num_cplx_sps * sizeof(complex));
+ pos += num_cplx_sps;
+ assert(pos < fbsb_chunk_len);
+ rcvClock[time_idx] = c;
+ time_idx++;
+ }
+ void reset() {pos = 0;
+ time_idx = 0;
+// s = fbsb_state::IDLE;
+ memset(fbsb_buf, 0, sizeof(fbsb_buf));
+ memset(conjbuf, 0, sizeof(conjbuf));
+ memset(avgbuf, 0, sizeof(avgbuf));
+ }
+ int sz () {return fbsb_chunk_len;}
+ int off () {return corr_offset;}
+
+ // from osmotrx sigproc
+ complex fastPeakDetect(complex* rxBurst, float* index, int N)
+ {
+ float val, max = 0.0f;
+ complex amp;
+ int _index = -1;
+
+ for (size_t i = 0; i < N; i++) {
+ val = rxBurst[i].abs();
+ if (val > max) {
+ max = val;
+ _index = i;
+ amp = rxBurst[i];
+ }
+ }
+
+ if (index)
+ *index = (float)_index;
+
+ return amp;
+ }
+
+ void conj_with_lag(complex* in, complex* out, int lag, int offset, int N) {
+ int total_offset = offset + lag;
+ for (int s = 0; s < N; s++)
+ out[s] = in[s + total_offset] * in[s + total_offset - lag].conj();
+ }
+
+ auto ac_sum_with_lag(complex* in, int lag, int offset, int N) {
+ complex v(0,0);
+ auto total_offset = offset + lag;
+ for (auto s = 0; s < N; s++)
+ v += in[s + total_offset] * in[s + total_offset - lag].conj();
+ return atan2(v.imag(), v.real());
+ }
+
+
+ bool running_avg_opt(complex* in, complex* out, int avg_window, int val_to_find, int* idx, int N) {
+ bool found = false;
+ complex avg0 = 0;
+ complex scale(avg_window, avg_window);
+ for (auto i = 0; i < avg_window; i++)
+ avg0 += in[i];
+ out[0] = avg0 / scale;
+
+ //skip first
+ for (auto i = 1; i < N - avg_window; i++) {
+ avg0 += in[i-1] - in[i+avg_window];
+ auto tmp = avg0 / scale;
+ out[i] = tmp;
+ if (!found && tmp.abs() > val_to_find) {
+ found = !found;
+ *idx = i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int fcch(complex* amp, int* found_idx, bool dump) {
+ conj_with_lag(fbsb_buf, conjbuf, 3, off(), sz());
+
+ running_avg_opt(conjbuf, avgbuf, 48, 1.5e6, found_idx, sz()-off());
+ float pos;
+ auto r = fastPeakDetect(avgbuf, &pos, sz()-off());
+ *found_idx = *found_idx+off();
+ std::cerr << "fcch found at " << pos << " amp: " << r.abs() << std::endl;
+ *amp = r;
+
+ if(dump) {
+ {
+ auto f = fopen("inbuf.cfile", "wb");
+ fwrite(fbsb_buf, sz(), 1, f);
+ fclose(f);
+ }
+ {
+ auto f = fopen("conjbuf.cfile", "wb");
+ fwrite(conjbuf, sz(), 1, f);
+ fclose(f);
+ }
+ {
+ auto f = fopen("schfcch.cfile", "wb");
+ fwrite(avgbuf, sz(), 1, f);
+ fclose(f);
+ }
+ exit(0);
+ }
+ return pos;
+ }
+};
+