def calculate_error(self): errors = 0 N1, N2 = len(self.sent_data), len(self.received_data) if N1 != N2: log.warning(f'Did not receive correct number of bits, expected {N1}, received {N2}') for b1, b2 in zip(self.sent_data, self.received_data): if b1 != b2: errors += 1 log.special(f'No of errors: {errors}') log.special(f'Percent error: {100*errors/max(N1, N2):3}%')
def listen_for_text(self, threshold=0.5): self.record() output_queue = named_deque() self.listen(output_queue, threshold) while True: try: received_bits = np.concatenate(list(output_queue)) output_queue.clear() received_bytes = np.packbits(received_bits) text = bytes(received_bytes) log.special(text) except: time.sleep(5)
def peak_finder(self, input_queue: deque, threshold, search_width: int, output_queue=None): N = search_width data_old = np.zeros(N) # buffer = named_deque(maxlen=10) while self.recording_flag: try: # Get next chunk from queue data_new, block_num = input_queue.popleft() except IndexError: time.sleep(0.25) continue # Extend with previous data for convolution data = np.concatenate((data_old, data_new)) data_old = data[-N:] # Find the index of the peak n = np.argmax(data) # Make sure that the peak is in the valid convolution region if n < (len(data) - N) and data[n] > threshold: log.info('Sync pulse detected') else: # If peak in in right hand invalid region, get next chunk of data continue # Get block number and sample index of star of signal (at n-search_width) for i in range(10): if n - search_width + self.audio_block_size * i >= 0: transmission_start = (block_num - i, n - search_width + self.audio_block_size * i) log.special(f'Peak detected at {transmission_start}') break else: log.error('Failed to send peak location') continue if type(output_queue) == named_deque: output_queue.append(transmission_start)
def test_transmission(self, bit_count=100, threshold=0.5): random.seed(100) test_packet = Packet([(random.getrandbits(1)) for i in range(bit_count)]) log.info(f'Sending test transmission - length={len(test_packet.unpack())}') self.sent_data = test_packet.unpack() self.r.record() data_bits_output_queue = named_deque() self.r.listen(data_bits_output_queue, threshold=threshold) # Transmit and wait till demodulated self.t.transmit(test_packet) # Todo change this to be none blocking so plots etc. can be shown while not self.r.demodulator.demodulated_flag: time.sleep(0.1) self.r.demodulator.demodulated_flag = False self.received_data = np.concatenate(list(data_bits_output_queue)) received_bytes = np.packbits(self.received_data) text = bytes(received_bytes) log.special(f'Received data in bytes form {text}')
def text_to_bits(self, text: str): send_bytes = list(text.encode()) log.special(f'send_bytes {send_bytes}') return np.unpackbits(np.array(send_bytes, dtype='uint8'))
def demodulate(self, transmission_start_index, audio_data_queue, output_queue): log.special(transmission_start_index) data, start_block_index = self.find_transmission_start( transmission_start_index, audio_data_queue) # Phy level data of fixed length: # Get phy level data i.e. symbol_width, symbol count audio_block_size = self.defaults['audio_block_size'] initial_pulse_width = self.defaults['ampam']['initial_pulse_width'] threshold_data_bits = self.defaults['ampam']['threshold_data_bits'] pulse_width_data_bits = self.defaults['ampam']['pulse_width_data_bits'] pulse_count_data_bits = self.defaults['ampam']['pulse_count_data_bits'] initial_pulse_count = pulse_width_data_bits + pulse_count_data_bits + threshold_data_bits # TODO make into a function while len(data) < initial_pulse_count * initial_pulse_width: try: data_new, block_num = audio_data_queue.popleft() data = np.append(data, data_new) except IndexError: time.sleep(0.5) data, phy_bits, = self.ampam_demod( data, initial_pulse_width, initial_pulse_count, thresholding_bits=threshold_data_bits, ) # Calculate no of audio blocks required # TODO manage this better pulse_width_bytes = np.packbits( phy_bits[threshold_data_bits:threshold_data_bits + pulse_width_data_bits]) pulse_count_bytes = np.packbits( phy_bits[threshold_data_bits + pulse_width_data_bits:threshold_data_bits + pulse_width_data_bits + pulse_count_data_bits]) pulse_width = pulse_width_bytes[0] * 2**8 + pulse_width_bytes[1] pulse_count = pulse_count_bytes[0] * 2**8 + pulse_count_bytes[1] log.debug( f'Receiving pam with pulse_count {pulse_count} pulse_width {pulse_width}' ) total_transmission_length = initial_pulse_count * initial_pulse_width + pulse_count * pulse_width end_block_index = start_block_index + math.floor( (transmission_start_index[1] + total_transmission_length) / audio_block_size) end_block_n = (total_transmission_length + transmission_start_index[1]) % audio_block_size log.debug( f'Calculated end block index = {end_block_index}, current block_num {block_num}' ) log.debug( f'Calculated end block n = {end_block_n}, total trans length {total_transmission_length}, original n {transmission_start_index[1]}' ) if end_block_index == block_num: log.warning('egg') data = data[:pulse_count * pulse_width + 1] else: while block_num < end_block_index: try: data_new, block_num = audio_data_queue.popleft() if block_num == end_block_index: data = np.append(data, data_new[:end_block_n]) break else: data = np.append(data, data_new) except IndexError: if len(data) > 1000 * pulse_width: # TODO bayesian updating of mean, incorporating new data, and old data prior to give posterior point estimate for mean data, bits = self.ampam_demod(data, pulse_width) output_queue.append(bits) else: time.sleep(0.1) data, bits = self.ampam_demod(data, pulse_width) output_queue.append(bits) self.demodulated_flag = True log.info('Demodulated')