From dd795612f0ca0d84e0a17075f8e56d783937bf10 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 18 Nov 2021 16:11:24 +0100 Subject: Begin frame sync block --- src/gr-fadingui/python/xor_frame_sync.py | 58 ++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'src/gr-fadingui/python/xor_frame_sync.py') diff --git a/src/gr-fadingui/python/xor_frame_sync.py b/src/gr-fadingui/python/xor_frame_sync.py index 9d9064f..735a031 100644 --- a/src/gr-fadingui/python/xor_frame_sync.py +++ b/src/gr-fadingui/python/xor_frame_sync.py @@ -4,24 +4,76 @@ # Copyright 2021 Naoki Pross. -import numpy +import numpy as np +from numpy_ringbuffer import RingBuffer + from gnuradio import gr + class xor_frame_sync(gr.sync_block): """ docstring for block xor_frame_sync """ - def __init__(self, sync_pattern): + def __init__(self, sync_pattern, buffer_size): gr.sync_block.__init__(self, name="xor_frame_sync", in_sig=[np.byte], out_sig=[np.byte]) + # binary pattern to match + self.pattern = np.array(sync_pattern, dtype=np.dtype("uint8")) + self.nbits = len(sync_pattern) + + # buffer to delay the data + self.delay_fifo = RingBuffer(buffer_size, dtype=np.byte) + + # buffers to store cross correlation data + self.xcorr = RingBuffer(buffer_size, dtype=np.dtype("uint8")) + + # synchronization state + self.synchronized = False + self.delay = 0 + + def xcorrelation(self): + """ + Compute the binary correlation between the stream and the stored + pattern. Binary correlation between two bit vectors is just size of the + vector(s) minus the number of bits that differ. + """ + unpacked = np.unpackbits(self.delay_fifo[0]) + return self.nbits - sum(np.logical_xor(unpacked, self.pattern)) + def work(self, input_items, output_items): + """ + Process the inputs, that means: + + - Check that the buffer is synchronized, i.e. there is the sync + pattern appears every k bits, where k is the size of the packet. + + - If the buffer is not synchronized, compute a binary cross + correlation to find how by much the stream should be delayed. + """ inp = input_items[0] out = output_items[0] - out[:] = inp + # Add data to delay buffer + self.delay_fifo.appendleft(inp) + + # TODO: check for synchronization, else compute + + # Compute correlation + if not self.synchronized: + self.xcorr.append(self.xcorrelation()) + + peak = np.argmax(self.xcorr) + if self.xcorr[peak] != self.nbits: + print(f"Warning! XOR correlation is not perfect (peak value = {self.xcorr[peak]})") + + self.delay = peak + self.synchronized = True + + # return data with delay + out[:] = self.delay_fifo[self.delay] return len(output_items[0]) -- cgit v1.2.1 From d00bb6d29ceae9d2ee958b57549af335e977edc6 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 18 Nov 2021 19:07:03 +0100 Subject: Partially implement xor correlator (untested) --- src/gr-fadingui/python/xor_frame_sync.py | 70 ++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 25 deletions(-) (limited to 'src/gr-fadingui/python/xor_frame_sync.py') diff --git a/src/gr-fadingui/python/xor_frame_sync.py b/src/gr-fadingui/python/xor_frame_sync.py index 735a031..af7aa85 100644 --- a/src/gr-fadingui/python/xor_frame_sync.py +++ b/src/gr-fadingui/python/xor_frame_sync.py @@ -12,36 +12,48 @@ from gnuradio import gr class xor_frame_sync(gr.sync_block): """ - docstring for block xor_frame_sync + Performs a frame synchronization by XOR matching a preamble bit sequence """ def __init__(self, sync_pattern, buffer_size): + # TODO: buffer size should be in packets gr.sync_block.__init__(self, name="xor_frame_sync", in_sig=[np.byte], out_sig=[np.byte]) # binary pattern to match - self.pattern = np.array(sync_pattern, dtype=np.dtype("uint8")) - self.nbits = len(sync_pattern) + self.pattern = np.unpackbits(np.array(sync_pattern, dtype=np.uint8))[::-1] + self.nbytes = len(sync_pattern) + self.nbits = len(self.pattern) - # buffer to delay the data - self.delay_fifo = RingBuffer(buffer_size, dtype=np.byte) + assert(self.nbits % 8 == 0) - # buffers to store cross correlation data - self.xcorr = RingBuffer(buffer_size, dtype=np.dtype("uint8")) + # packed buffer to delay the data + self.delaybuf = RingBuffer(buffer_size, dtype=np.uint8) + self.delay = 0 + + # unpacked buffer to compute correlation values, initially filled with zeros + self.corrbuf = RingBuffer(self.nbits) + self.corrbuf.extend(np.zeros(self.nbits)) + + # buffer to store correlation values + self.xcorrs = RingBuffer(buffer_size) # synchronization state self.synchronized = False - self.delay = 0 - def xcorrelation(self): + def xcorrelation(self, v): """ - Compute the binary correlation between the stream and the stored - pattern. Binary correlation between two bit vectors is just size of the + Compute the binary correlations between the stored pattern and + correlation buffer, while shifting v into the buffer. + + Binary correlation between two bit vectors is just size of the vector(s) minus the number of bits that differ. """ - unpacked = np.unpackbits(self.delay_fifo[0]) - return self.nbits - sum(np.logical_xor(unpacked, self.pattern)) + v_arr = np.array(v, dtype=np.uint8) + for b in np.unpackbits(v_arr): + self.corrbuf.appendleft(b) + yield self.nbits - np.sum(np.logical_xor(self.corrbuf, self.pattern)) def work(self, input_items, output_items): """ @@ -51,29 +63,37 @@ class xor_frame_sync(gr.sync_block): pattern appears every k bits, where k is the size of the packet. - If the buffer is not synchronized, compute a binary cross - correlation to find how by much the stream should be delayed. + correlation to find how much the stream should be delayed. + + Notes: + + - Even though the block input is of type np.byte, inp is an array + of 255 bytes, probably for performance reasons. + TODO: block processing """ inp = input_items[0] out = output_items[0] - # Add data to delay buffer - self.delay_fifo.appendleft(inp) - - # TODO: check for synchronization, else compute - - # Compute correlation if not self.synchronized: - self.xcorr.append(self.xcorrelation()) + for v in inp: + # compute the cross correlation + xcs = self.xcorrelation(v) - peak = np.argmax(self.xcorr) - if self.xcorr[peak] != self.nbits: - print(f"Warning! XOR correlation is not perfect (peak value = {self.xcorr[peak]})") + # add cross correlations to buffer and save value + self.xcorrs.extend(list(xcs)) + self.delaybuf.appendleft(v) + peak = np.argmax(self.xcorrs) self.delay = peak self.synchronized = True + if self.xcorrs[peak] != self.nbits: + self.synchronized = False + print(f"Warning! XOR correlation is not perfect (peak value = {self.xcorrs[peak]})") + + # return data with delay - out[:] = self.delay_fifo[self.delay] + out[:] = self.delaybuf[self.delay] return len(output_items[0]) -- cgit v1.2.1 From ac8ef5f69a69f11fd202470da68709cd3006d547 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 19 Nov 2021 21:29:45 +0100 Subject: Frames --- src/gr-fadingui/python/xor_frame_sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gr-fadingui/python/xor_frame_sync.py') diff --git a/src/gr-fadingui/python/xor_frame_sync.py b/src/gr-fadingui/python/xor_frame_sync.py index af7aa85..e8d202c 100644 --- a/src/gr-fadingui/python/xor_frame_sync.py +++ b/src/gr-fadingui/python/xor_frame_sync.py @@ -89,7 +89,7 @@ class xor_frame_sync(gr.sync_block): if self.xcorrs[peak] != self.nbits: self.synchronized = False - print(f"Warning! XOR correlation is not perfect (peak value = {self.xcorrs[peak]})") + print(f"Warning! XOR correlation did not find a peak (max = {self.xcorrs[peak]} should be {self.nbits})") # return data with delay -- cgit v1.2.1 From 2bb4a947d4d55e605e6912dec3ff95fbe541615a Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Sat, 20 Nov 2021 17:05:04 +0100 Subject: Implement Frame Object --- src/gr-fadingui/python/xor_frame_sync.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/gr-fadingui/python/xor_frame_sync.py') diff --git a/src/gr-fadingui/python/xor_frame_sync.py b/src/gr-fadingui/python/xor_frame_sync.py index e8d202c..51af35a 100644 --- a/src/gr-fadingui/python/xor_frame_sync.py +++ b/src/gr-fadingui/python/xor_frame_sync.py @@ -9,6 +9,9 @@ from numpy_ringbuffer import RingBuffer from gnuradio import gr +from fadingui.logger import get_logger +log = get_logger("xor_frame_sync") + class xor_frame_sync(gr.sync_block): """ @@ -26,6 +29,7 @@ class xor_frame_sync(gr.sync_block): self.nbytes = len(sync_pattern) self.nbits = len(self.pattern) + log.debug(f"Loaded pattern {self.pattern} length={self.nbits}") assert(self.nbits % 8 == 0) # packed buffer to delay the data @@ -84,12 +88,14 @@ class xor_frame_sync(gr.sync_block): self.delaybuf.appendleft(v) peak = np.argmax(self.xcorrs) - self.delay = peak - self.synchronized = True + if self.xcorrs[peak] == self.nbits: + self.delay = peak + self.synchronized = True + log.debug(f"Synchronized with delay={peak}") - if self.xcorrs[peak] != self.nbits: + else: self.synchronized = False - print(f"Warning! XOR correlation did not find a peak (max = {self.xcorrs[peak]} should be {self.nbits})") + log.warning(f"Did not find a peak (max={self.xcorrs[peak]}, should be {self.nbits})") # return data with delay -- cgit v1.2.1