Изо всех сил пытаюсь заставить мою передачу данных работать надежно даже на 2 бит / с - PullRequest
0 голосов
/ 06 июня 2019

Я строю систему передачи данных на «неслышимых» частотах, но лучший результат до сих пор - потеря 6% бит, передавая 450B, со скоростью 2 бит / с. Я не знаю много о передаче данных, и это мой первый проект на Python.

Отправка в форме асинхронной связи теоретически допускает передачу без потерь, поэтому я понятия не имею, почему она теряет биты данных на низких скоростях, таких как 2 бит / с. Вот код для принимающей части, я протестировал передачу с внешними устройствами, и она работает точно и хорошо: /

import pyaudio
import numpy as np
import pylab
#import matplotlib.pyplot as plt
from scipy.io import wavfile
from timeit import default_timer as timer
import sys
import seaborn as sns
import time

class Fourier():

    def __init__(self):
        print("Fourier class constructed\n")

    #Random variables
    received_data = ""
    #i=0
    #f,ax = plt.subplots(2)
    #Default value, gets changed according to set_reading_speed()
    speed = 1
    count = 0
    #Preparing the Plotting Environment with random starting values
    #x = np.arange(10000)
    #y = np.random.randn(10000)

    #Raw audio data plot
    #li, = ax[0].plot(x, y)
    #ax[0].set_xlim(0,4000)
    #ax[0].set_ylim(-20000,20000)
    #ax[0].set_title("Raw Audio Signal")

    #FFT plot
    #li2, = ax[1].plot(x, y)
    #ax[1].set_xlim(0,20000)
    #ax[1].set_ylim(-50,100)
    #ax[1].set_title("Fast Fourier Transform")

    #Show the plot, but without blocking updates
    #plt.pause(0.01)
    #plt.tight_layout()

    FORMAT = pyaudio.paInt16
    CHANNELS = 2
    RATE = 44100
    CHUNK = 2048
    RECORD_SECONDS = 0.1
    WAVE_OUTPUT_FILENAME = "file.wav"

    audio = pyaudio.PyAudio()

    #Start Recording
    stream = audio.open(format=FORMAT,
                        channels=CHANNELS,
                        rate=RATE,
                        input=True)#,
                        #frames_per_buffer=CHUNK)

    stream.start_stream() #Opens the connection and start streaming the data

    result_herz = 0 #Making the variable visible to other class methods

    pass_flag = False #Makes sure we read the first available bit after waiting for the start bit to end
    timeout_flag = False #False until no more bits are received in a timespan of 5 seconds
    data_flag = False #Marks the start of reading data from the channel
    start_flag = False #True while the start bit is detected
    listening_start = time.time() #Making both variables visible
    timeout_start = time.time()
    self.data_flag=False

    def check_timeout(self):
        timeout_end = time.time()
        if (timeout_end - self.timeout_start) > 5.0:
            self.timeout_flag = True
            print("Listener has timed out")
            print("Received {} bits".format(self.count))

    def listen(self):
        #For determining when to read another bit
        self.listening_start = time.time()
        #To determine if timeout_flag should be raised
        self.timeout_start = time.time()
        while not self.timeout_flag:
            #to measure time spent running a cycle
            #start_time = time.clock()
            self.calc() #Picks up data from the microphone and calculates the frequency
            self.check_timeout() #Checks if 5 seconds have passed since the last bit received
            #end_time = round(time.clock() - start_time, 5)
            #print(end_time)

    def plot(self, audio_data, dfft):
        #Plotting data, for it to function the lines of code right under the constructor should be uncommented
        self.li.set_xdata(np.arange(len(audio_data)))
        self.li.set_ydata(audio_data)
        self.li2.set_xdata(np.arange(len(dfft))*10.)
        self.li2.set_ydata(dfft)
        plt.pause(0.01)

    def calc(self):
        input_data = self.stream.read(self.CHUNK) #Read the stream
        audio_data = np.fromstring(input_data, np.int16) #Acquire and convert data to floats
        dfft = 10.*np.log10(abs(np.fft.rfft(audio_data))) #FFT, 10*log10(abs) is to scale it to dB and make sure its not imaginary
        fft_bin = np.fft.fftfreq(len(dfft)) #Calculating the frequencies
        idx = np.argmax(np.abs(dfft)) #Finding the peak in the coefficients
        fft_bin = fft_bin[idx]
        self.result_herz = abs(fft_bin*self.RATE) #Final result
        self.check_frequenc() #Checks frequency
        #print(result_herz)
        #self.plot(audio_data, dfft) #Update the graph

    def check_frequenc(self):
        #Asynchronous data receiving
        if self.result_herz > 14900.0 and self.result_herz < 15100.0: #Checks if it is the start bit
            self.data_flag = False #We don't read data from the start bit
            self.start_flag = True #Signals that the start bit is active
            #print("count reset")
            #self.stream.stop_stream()
            #self.stream.start_stream()
            self.timeout_start = time.time() #Starts the timeout timer
            #print("if n1")

        if self.start_flag == True: #If start bit is active
            #print("if n2")
            if not (self.result_herz > 14900.0 and self.result_herz < 15100.0): #Checks if the start bit is still here
                #print("end of start bit")
                self.start_flag = False
                self.data_flag = True #Allows for reading data
                self.pass_flag = True #Allows for the first bit we arrive on to be instantly read, after that we read once every self.read

        if self.data_flag == True:
            #print("if n3")
            listening_end = time.time()
            if ((listening_end - self.listening_start) >= self.speed) or self.pass_flag: #Checks the timestamps
                self.pass_flag = False #Turn off the pass_flag, it gets activated every 8 bits received
                #print("reading")
                if self.result_herz > 18700.0 and self.result_herz < 18800.0: #Check for ranges
                    #print("read")
                    self.set_data('1') #Write to self.received_data
                    self.timeout_start = time.time() #Reset timeout timer
                    self.listening_start = time.time() #Reset listening timer
                if self.result_herz > 19150.0 and self.result_herz < 19250.0:
                    #print("read")
                    self.set_data('0')
                    self.timeout_start = time.time()
                    self.listening_start = time.time()
        #if not self.data_flag:
            #if self.result_herz > 14900.0 and self.result_herz < 15100.0:
                #self.start_flag=True
            #elif self.start_flag:
                #self.data_flag=true

    def reset_count(self): #Resets the flags and sleeps for half the interval of transmission, to land somewhere near the middle of the signal
        #print("count reset")
        self.start_flag = False
        self.data_flag = False
        time.sleep(self.speed/2.0) #Sleep ends up being called every new Byte of data, so we align ourselves on the first bit

    def set_data(self, value):
        if value == '1':
            self.received_data = self.received_data + '1'
        if value == '0':
            self.received_data = self.received_data + '0'
        self.count = self.count + 1
        if self.count % 8 == 0: #Checks if it is time to sleeps to get in sync
            self.reset_count()

    def set_reading_speed(self, s):
        self.speed = s #Received speed
        print("Listening speed is: {}".format(self.speed))

    def __del__(self): #Destructor
        self.stream.stop_stream()
        self.stream.close()
        self.audio.terminate()

    def get_data(self):
        return self.received_data #Data passing

Иногда я получаю RuntimeWarning: деление на ноль, встречающееся в log10, который приходит из строки 102 | dfft = 10. * np.log10 (abs (np.fft.rfft (audio_data)))

...