From 8e6e1d62ef9beb978879bfd156b3ff51940c8725 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 12:50:55 +0100 Subject: Implement phase correction in test file with embedded python block --- tests/correlator/epy_block_0.py | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/correlator/epy_block_0.py (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py new file mode 100644 index 0000000..1fa4794 --- /dev/null +++ b/tests/correlator/epy_block_0.py @@ -0,0 +1,75 @@ +import pmt + +import numpy as np +from gnuradio import gr + + +class blk(gr.sync_block): + def __init__(self): + gr.sync_block.__init__( + self, + name='Phase Lock', + in_sig=[np.complex64], + out_sig=[np.complex64] + ) + + # keep track of how many samples were processed, + # because tags have an absolute offset + self.sampnr: np.complex64 = 0 + + # because of block processing a tagged block could + # be split in half so we need to keep track of the + # "previous" values + self.last_phase = 0 + + def work(self, input_items, output_items): + # TODO: interpolate phase values for frequency correction + + out = output_items[0] + inp = input_items[0] + + # create a phase correction vector + phase = np.zeros(len(inp), dtype=np.float64) + + # read tags + tags = self.get_tags_in_window(0, 0, len(inp)) + + # get only phase tags + is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" + phase_tags = list(filter(is_phase, tags)) + + print(f"Processing {len(inp)} samples, with {len(phase_tags)} tags") + + # compute correction from previous block + first_tag = phase_tags[0] + first_idx = first_tag.offset - self.sampnr + phase[:first_idx] = self.last_phase + + # iterate phase tags "in the middle" + for prev_tag, next_tag in zip(phase_tags, phase_tags[1:]): + # unpack pmt values + pval = pmt.to_python(prev_tag.value) + + # compute indexes in phase vector + pidx = prev_tag.offset - self.sampnr + idx = next_tag.offset - self.sampnr + + # compute phase correction for block + phase[pidx:idx] = pval + print(f"Correction for block {pidx} to {idx} is {pval}") + + # compute the remaining part of the block + last_tag = phase_tags[-1] + last_val = pmt.to_python(last_tag.value) + last_idx = last_tag.offset - self.sampnr + + phase[last_idx:] = last_val + + # save values for next call + self.last_phase = last_val + + # mark samples as processed and compute to output + self.sampnr += len(inp) + out[:] = inp * np.exp(-1j * phase) + + return len(out) -- cgit v1.2.1 From de7b4dac4af5ff592258f48eee72d191201826d7 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Thu, 2 Dec 2021 21:24:33 +0100 Subject: Begin frequency correction (incomplete) --- tests/correlator/epy_block_0.py | 75 +++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 25 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 1fa4794..90ad75e 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -20,56 +20,81 @@ class blk(gr.sync_block): # because of block processing a tagged block could # be split in half so we need to keep track of the # "previous" values - self.last_phase = 0 + self.last_tag = None def work(self, input_items, output_items): - # TODO: interpolate phase values for frequency correction - + # nicer aliases out = output_items[0] inp = input_items[0] - # create a phase correction vector - phase = np.zeros(len(inp), dtype=np.float64) + def print_phase_correction(start, end, phase, freq): + print(f"Correction for block {start:3d} to {end:3d} is phase = {phase: 2.4f} rad, freq = {freq * 1e3: 2.4f} milli rad/samp") - # read tags + # read only phase tags tags = self.get_tags_in_window(0, 0, len(inp)) - # get only phase tags is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" phase_tags = list(filter(is_phase, tags)) + # FIXME: what if there are no tags? check that! + print(f"Processing {len(inp)} samples, with {len(phase_tags)} tags") - # compute correction from previous block - first_tag = phase_tags[0] - first_idx = first_tag.offset - self.sampnr - phase[:first_idx] = self.last_phase + # create a phase correction vector + phase = np.zeros(len(inp), dtype=np.float64) + + # compute correction from previous block (if present) + if self.last_tag: + # variables for first and last phase values + lval = pmt.to_python(self.last_tag.value) + fval = pmt.to_python(phase_tags[0].value) + + # compute index for phase vector + fidx = phase_tags[0].offset - self.sampnr + + # compute frequency offset + nsamples = phase_tags[0].offset - self.last_tag.offset + freq = (fval - lval) / nsamples + + # total phase correction is: phase + freq * time + phase[:fidx] = lval * np.ones(fidx) + freq * np.arange(0, fidx) + + # compute correction + print_phase_correction(0, fidx, lval, freq) # iterate phase tags "in the middle" + # FIXME: what if there are less than 2 tags? + # the code below will probably crash for prev_tag, next_tag in zip(phase_tags, phase_tags[1:]): # unpack pmt values pval = pmt.to_python(prev_tag.value) + nval = pmt.to_python(next_tag.value) # compute indexes in phase vector pidx = prev_tag.offset - self.sampnr - idx = next_tag.offset - self.sampnr + nidx = next_tag.offset - self.sampnr - # compute phase correction for block - phase[pidx:idx] = pval - print(f"Correction for block {pidx} to {idx} is {pval}") + # compute frquency correction for block by linearly interpolating + # frame values + nsamples = nidx - pidx + freq = (nval - pval) / nsamples - # compute the remaining part of the block - last_tag = phase_tags[-1] - last_val = pmt.to_python(last_tag.value) - last_idx = last_tag.offset - self.sampnr + # total correction is: phase + freq * time + phase[pidx:nidx] = pval * np.ones(nsamples) + freq * np.arange(0, nsamples) + print_phase_correction(pidx, nidx, pval, freq) - phase[last_idx:] = last_val + # for the last block because the next tag is unknown (in the future) we + # cannot predict the frequency offset. Thus we save the last tag for + # the next call. + self.last_tag = phase_tags[-1] + val = pmt.to_python(self.last_tag.value) + idx = self.last_tag.offset - self.sampnr - # save values for next call - self.last_phase = last_val + phase[idx:] = val - # mark samples as processed and compute to output - self.sampnr += len(inp) + # compute correction out[:] = inp * np.exp(-1j * phase) - return len(out) + # increment processed samples counter + self.sampnr += len(inp) + return len(phase) -- cgit v1.2.1 From 3718e92fe6418e33a7e8d53192383d021d20c524 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 00:18:55 +0100 Subject: Refractor frequency correction --- tests/correlator/epy_block_0.py | 124 ++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 68 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 90ad75e..9cb25bb 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -13,88 +13,76 @@ class blk(gr.sync_block): out_sig=[np.complex64] ) - # keep track of how many samples were processed, - # because tags have an absolute offset - self.sampnr: np.complex64 = 0 + # we need to keep track of the aboslute number of samples that have + # been processed, because tags have an absolute offset + self.counter: np.uint64 = 0 - # because of block processing a tagged block could - # be split in half so we need to keep track of the - # "previous" values - self.last_tag = None + # because we do block processing, we need to keep track of the last tag + # of the previous block to correct the first values of the next block + self.last = None - def work(self, input_items, output_items): - # nicer aliases - out = output_items[0] - inp = input_items[0] - - def print_phase_correction(start, end, phase, freq): - print(f"Correction for block {start:3d} to {end:3d} is phase = {phase: 2.4f} rad, freq = {freq * 1e3: 2.4f} milli rad/samp") - - # read only phase tags - tags = self.get_tags_in_window(0, 0, len(inp)) - - is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" - phase_tags = list(filter(is_phase, tags)) + def block_phase(self, start, end): + # compute number of samples in block + nsamples = end.offset - start.offset - # FIXME: what if there are no tags? check that! + # unpack pmt values into start and end phase + sphase = pmt.to_python(start.value) + ephase = pmt.to_python(end.value) - print(f"Processing {len(inp)} samples, with {len(phase_tags)} tags") + # compute frequency offset between start and end + freq = (sphase - ephase) / nsamples - # create a phase correction vector - phase = np.zeros(len(inp), dtype=np.float64) + # debugging + print(f"Correction for block of {nsamples:2d} samples is " \ + f"phase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") - # compute correction from previous block (if present) - if self.last_tag: - # variables for first and last phase values - lval = pmt.to_python(self.last_tag.value) - fval = pmt.to_python(phase_tags[0].value) + # compute block values + return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) - # compute index for phase vector - fidx = phase_tags[0].offset - self.sampnr - - # compute frequency offset - nsamples = phase_tags[0].offset - self.last_tag.offset - freq = (fval - lval) / nsamples + def work(self, input_items, output_items): + # FIXME: replace class counter with local variable + # self.counter = self.nitems_written(0) - # total phase correction is: phase + freq * time - phase[:fidx] = lval * np.ones(fidx) + freq * np.arange(0, fidx) + # nicer aliases + inp = input_items[0] + out = output_items[0] - # compute correction - print_phase_correction(0, fidx, lval, freq) + # read phase tags + is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" + tags = list(filter(is_phase, self.get_tags_in_window(0, 0, len(inp)))) - # iterate phase tags "in the middle" - # FIXME: what if there are less than 2 tags? - # the code below will probably crash - for prev_tag, next_tag in zip(phase_tags, phase_tags[1:]): - # unpack pmt values - pval = pmt.to_python(prev_tag.value) - nval = pmt.to_python(next_tag.value) + # debugging + print(f"Processing {len(tags)} tags = {tags[-1].offset - tags[0].offset} " \ + f"samples out of {len(inp)} input samples") - # compute indexes in phase vector - pidx = prev_tag.offset - self.sampnr - nidx = next_tag.offset - self.sampnr + # compute "the middle" + enough_samples = lambda pair: ((pair[1].offset - pair[0].offset) > 0) + pairs = list(filter(enough_samples, zip(tags, tags[1:]))) + blocks = [ self.block_phase(start, end) for (start, end) in pairs ] + middle = np.concatenate(blocks) if blocks else [] - # compute frquency correction for block by linearly interpolating - # frame values - nsamples = nidx - pidx - freq = (nval - pval) / nsamples + # compute the remainder from the previous call + nfront = tags[0].offset - self.counter + print(f"Processing {nfront} samples at the front of the buffer") + start = self.block_phase(self.last, tags[0])[-nfront:] \ + if self.last else np.zeros(nfront) - # total correction is: phase + freq * time - phase[pidx:nidx] = pval * np.ones(nsamples) + freq * np.arange(0, nsamples) - print_phase_correction(pidx, nidx, pval, freq) + # compute values at the end + nback = len(inp) - (tags[-1].offset - self.counter) + print(f"Processing {nback} samples at the back of the buffer") + end = np.ones(nback) * pmt.to_python(tags[-1].value) - # for the last block because the next tag is unknown (in the future) we - # cannot predict the frequency offset. Thus we save the last tag for - # the next call. - self.last_tag = phase_tags[-1] - val = pmt.to_python(self.last_tag.value) - idx = self.last_tag.offset - self.sampnr + # compute correction + correction = np.exp(-1j * np.concatenate([start, middle, end])) + length = len(correction) - phase[idx:] = val + # write outputs + out[:length] = inp[:length] * correction + self.counter += len(inp) - # compute correction - out[:] = inp * np.exp(-1j * phase) + # save last tag for next call + self.last = tags[-1] - # increment processed samples counter - self.sampnr += len(inp) - return len(phase) + # FIXME: should return `length' but then the last sample is not + # included and self.last does something weird + return len(out) -- cgit v1.2.1 From 5d2f01fe71b736f2f5bb8a57bb2f4cd383290e9f Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 00:29:03 +0100 Subject: Fix bug when tag is aligned with inp block --- tests/correlator/epy_block_0.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 9cb25bb..abf4486 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -41,7 +41,7 @@ class blk(gr.sync_block): def work(self, input_items, output_items): # FIXME: replace class counter with local variable - # self.counter = self.nitems_written(0) + self.counter = self.nitems_written(0) # nicer aliases inp = input_items[0] @@ -65,7 +65,7 @@ class blk(gr.sync_block): nfront = tags[0].offset - self.counter print(f"Processing {nfront} samples at the front of the buffer") start = self.block_phase(self.last, tags[0])[-nfront:] \ - if self.last else np.zeros(nfront) + if self.last and nfront else np.zeros(nfront) # compute values at the end nback = len(inp) - (tags[-1].offset - self.counter) -- cgit v1.2.1 From edf08d1815772fc985a89c976a190b3fcd6fb087 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 00:45:23 +0100 Subject: Add a LPF on the frequency --- tests/correlator/epy_block_0.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index abf4486..6b47e80 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -21,6 +21,10 @@ class blk(gr.sync_block): # of the previous block to correct the first values of the next block self.last = None + # to compute the values that are at the end we need to know the frequency + # of the last block + self.freq = 1 + def block_phase(self, start, end): # compute number of samples in block nsamples = end.offset - start.offset @@ -32,6 +36,15 @@ class blk(gr.sync_block): # compute frequency offset between start and end freq = (sphase - ephase) / nsamples + # save this frequency values to compute the end block, unless frequency + # has changed too fast, in that case replace the current values with + # the previous one . This is effectively like a low pass filter. + if abs(freq / self.freq) > 4: + freq = self.freq + else: + self.freq = freq + + # debugging print(f"Correction for block of {nsamples:2d} samples is " \ f"phase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") @@ -61,17 +74,18 @@ class blk(gr.sync_block): blocks = [ self.block_phase(start, end) for (start, end) in pairs ] middle = np.concatenate(blocks) if blocks else [] - # compute the remainder from the previous call + # compute values at the end, we do not have informations about the future + # but we can use the frequency of the last block to approximate + nback = len(inp) - (tags[-1].offset - self.counter) + print(f"Processing {nback} samples at the back of the buffer") + end = np.ones(nback) * pmt.to_python(tags[-1].value) + self.freq * np.arange(0, nback) + + # compute the "start", using the last tag from the previous call nfront = tags[0].offset - self.counter print(f"Processing {nfront} samples at the front of the buffer") start = self.block_phase(self.last, tags[0])[-nfront:] \ if self.last and nfront else np.zeros(nfront) - # compute values at the end - nback = len(inp) - (tags[-1].offset - self.counter) - print(f"Processing {nback} samples at the back of the buffer") - end = np.ones(nback) * pmt.to_python(tags[-1].value) - # compute correction correction = np.exp(-1j * np.concatenate([start, middle, end])) length = len(correction) -- cgit v1.2.1 From b389c8d00064d224a534d3c4a37bd4ee700a5022 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 13:01:42 +0100 Subject: Improve frequency LPF --- tests/correlator/epy_block_0.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index 6b47e80..e7599c9 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -21,9 +21,20 @@ class blk(gr.sync_block): # of the previous block to correct the first values of the next block self.last = None - # to compute the values that are at the end we need to know the frequency - # of the last block - self.freq = 1 + # both the phase and frequency corrections should go through a low pass + # filter to avoid werid jumps in the correction. to do that, there are + # two buffers with an index + self.index = 0 + self.length = 7 + self.freq = np.zeros(self.length) + + def lpf_freq(self, new_sample): + # save new sample + self.freq[self.index] = new_sample + # increment index + self.index = (self.index + 1) % self.length + + return np.sum(self.freq) / self.length def block_phase(self, start, end): # compute number of samples in block @@ -34,16 +45,9 @@ class blk(gr.sync_block): ephase = pmt.to_python(end.value) # compute frequency offset between start and end + # and run it through a low pass filter (mean) freq = (sphase - ephase) / nsamples - - # save this frequency values to compute the end block, unless frequency - # has changed too fast, in that case replace the current values with - # the previous one . This is effectively like a low pass filter. - if abs(freq / self.freq) > 4: - freq = self.freq - else: - self.freq = freq - + freq = self.lpf_freq(freq) # debugging print(f"Correction for block of {nsamples:2d} samples is " \ @@ -64,6 +68,11 @@ class blk(gr.sync_block): is_phase = lambda tag: pmt.to_python(tag.key) == "phase_est" tags = list(filter(is_phase, self.get_tags_in_window(0, 0, len(inp)))) + if not tags: + print(f"There were no tags in {len(inp)} samples!") + out[:] = inp + return len(out) + # debugging print(f"Processing {len(tags)} tags = {tags[-1].offset - tags[0].offset} " \ f"samples out of {len(inp)} input samples") @@ -78,7 +87,8 @@ class blk(gr.sync_block): # but we can use the frequency of the last block to approximate nback = len(inp) - (tags[-1].offset - self.counter) print(f"Processing {nback} samples at the back of the buffer") - end = np.ones(nback) * pmt.to_python(tags[-1].value) + self.freq * np.arange(0, nback) + endfreq = self.lpf_freq(self.freq[-1]) + end = np.ones(nback) * pmt.to_python(tags[-1].value) + endfreq * np.arange(0, nback) # compute the "start", using the last tag from the previous call nfront = tags[0].offset - self.counter -- cgit v1.2.1 From 0cb8ac7bd0e88d6d26c1fda3abcf0977c2e8150b Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 17:54:07 +0100 Subject: Fix bug that makes jump estimated frequency to unreasonably high values --- tests/correlator/epy_block_0.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index e7599c9..a581a3a 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -25,7 +25,7 @@ class blk(gr.sync_block): # filter to avoid werid jumps in the correction. to do that, there are # two buffers with an index self.index = 0 - self.length = 7 + self.length = 5 self.freq = np.zeros(self.length) def lpf_freq(self, new_sample): @@ -46,12 +46,20 @@ class blk(gr.sync_block): # compute frequency offset between start and end # and run it through a low pass filter (mean) - freq = (sphase - ephase) / nsamples - freq = self.lpf_freq(freq) + phasediff = ephase - sphase + + if phasediff > np.pi: + phasediff -= 2*np.pi + + elif phasediff < -np.pi: + phasediff += 2*np.pi + + freq = phasediff / nsamples + # freq = self.lpf_freq(freq) # debugging print(f"Correction for block of {nsamples:2d} samples is " \ - f"phase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") + f"sphase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") # compute block values return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) -- cgit v1.2.1 From eb385ffb0c3c41d7097fb74260f3a39c2aaeb926 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 21:55:18 +0100 Subject: Remove frequency LPF and clean up --- tests/correlator/epy_block_0.py | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index a581a3a..ddae02a 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -8,33 +8,18 @@ class blk(gr.sync_block): def __init__(self): gr.sync_block.__init__( self, - name='Phase Lock', + name='Phase and Frequency Correction', in_sig=[np.complex64], out_sig=[np.complex64] ) - # we need to keep track of the aboslute number of samples that have - # been processed, because tags have an absolute offset - self.counter: np.uint64 = 0 + # tags should not be propagated, we then output our own tags + self.set_tag_propagation_policy(gr.TPP_DONT) # because we do block processing, we need to keep track of the last tag # of the previous block to correct the first values of the next block self.last = None - - # both the phase and frequency corrections should go through a low pass - # filter to avoid werid jumps in the correction. to do that, there are - # two buffers with an index - self.index = 0 - self.length = 5 - self.freq = np.zeros(self.length) - - def lpf_freq(self, new_sample): - # save new sample - self.freq[self.index] = new_sample - # increment index - self.index = (self.index + 1) % self.length - - return np.sum(self.freq) / self.length + self.lastfreq = 0 def block_phase(self, start, end): # compute number of samples in block @@ -45,7 +30,6 @@ class blk(gr.sync_block): ephase = pmt.to_python(end.value) # compute frequency offset between start and end - # and run it through a low pass filter (mean) phasediff = ephase - sphase if phasediff > np.pi: @@ -55,7 +39,9 @@ class blk(gr.sync_block): phasediff += 2*np.pi freq = phasediff / nsamples - # freq = self.lpf_freq(freq) + + # save this one for the last block (see variable `end' in self.work) + self.lastfreq = freq # debugging print(f"Correction for block of {nsamples:2d} samples is " \ @@ -65,8 +51,7 @@ class blk(gr.sync_block): return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) def work(self, input_items, output_items): - # FIXME: replace class counter with local variable - self.counter = self.nitems_written(0) + counter = self.nitems_written(0) # nicer aliases inp = input_items[0] @@ -93,13 +78,13 @@ class blk(gr.sync_block): # compute values at the end, we do not have informations about the future # but we can use the frequency of the last block to approximate - nback = len(inp) - (tags[-1].offset - self.counter) + nback = len(inp) - (tags[-1].offset - counter) print(f"Processing {nback} samples at the back of the buffer") - endfreq = self.lpf_freq(self.freq[-1]) - end = np.ones(nback) * pmt.to_python(tags[-1].value) + endfreq * np.arange(0, nback) + end = np.ones(nback) * pmt.to_python(tags[-1].value) \ + + self.lastfreq * np.arange(0, nback) # compute the "start", using the last tag from the previous call - nfront = tags[0].offset - self.counter + nfront = tags[0].offset - counter print(f"Processing {nfront} samples at the front of the buffer") start = self.block_phase(self.last, tags[0])[-nfront:] \ if self.last and nfront else np.zeros(nfront) @@ -110,7 +95,6 @@ class blk(gr.sync_block): # write outputs out[:length] = inp[:length] * correction - self.counter += len(inp) # save last tag for next call self.last = tags[-1] -- cgit v1.2.1 From 13a2fda61a5cb1e6d3f807d0acda42c45e128434 Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Fri, 3 Dec 2021 23:46:33 +0100 Subject: Fix correlation peak detector and add frame_start tags --- tests/correlator/epy_block_0.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'tests/correlator/epy_block_0.py') diff --git a/tests/correlator/epy_block_0.py b/tests/correlator/epy_block_0.py index ddae02a..dbdadd1 100644 --- a/tests/correlator/epy_block_0.py +++ b/tests/correlator/epy_block_0.py @@ -5,6 +5,12 @@ from gnuradio import gr class blk(gr.sync_block): + """ + Apply phase and frequency correction where there is a correlation peak tag. + + The correlation peak tags are NOT propagated, and instead replaced with a + frame_start tag. + """ def __init__(self): gr.sync_block.__init__( self, @@ -22,7 +28,17 @@ class blk(gr.sync_block): self.lastfreq = 0 def block_phase(self, start, end): - # compute number of samples in block + """ + Compute a vector for the phase and frequency correction for the samples + between two tags (start and end). + + @param start Tag where the samples should start to be corrected + @param end Tag where to stop correcting + + @return A vector of phase values for each sample. To correct the samples + the data should be multiplied with np.exp(-1j * phase) + """ + # compute number of samples between tags nsamples = end.offset - start.offset # unpack pmt values into start and end phase @@ -44,10 +60,10 @@ class blk(gr.sync_block): self.lastfreq = freq # debugging - print(f"Correction for block of {nsamples:2d} samples is " \ + print(f"Correction for chunk of {nsamples:2d} samples is " \ f"sphase={sphase: .4f} rad and freq={freq*1e3: .4f} milli rad / sample") - # compute block values + # compute chunk values return sphase * np.ones(nsamples) + freq * np.arange(0, nsamples) def work(self, input_items, output_items): @@ -73,11 +89,11 @@ class blk(gr.sync_block): # compute "the middle" enough_samples = lambda pair: ((pair[1].offset - pair[0].offset) > 0) pairs = list(filter(enough_samples, zip(tags, tags[1:]))) - blocks = [ self.block_phase(start, end) for (start, end) in pairs ] - middle = np.concatenate(blocks) if blocks else [] + chunks = [ self.block_phase(start, end) for (start, end) in pairs ] + middle = np.concatenate(chunks) if chunks else [] # compute values at the end, we do not have informations about the future - # but we can use the frequency of the last block to approximate + # but we can use the frequency of the last tag to approximate nback = len(inp) - (tags[-1].offset - counter) print(f"Processing {nback} samples at the back of the buffer") end = np.ones(nback) * pmt.to_python(tags[-1].value) \ @@ -99,6 +115,10 @@ class blk(gr.sync_block): # save last tag for next call self.last = tags[-1] + # add tags + for tag in tags: + self.add_item_tag(0, tag.offset, pmt.intern("frame_start"), pmt.PMT_T) + # FIXME: should return `length' but then the last sample is not # included and self.last does something weird return len(out) -- cgit v1.2.1