diff --git a/pyModeS/extra/rtlreader.py b/pyModeS/extra/rtlreader.py index 6bc9285..fc35270 100644 --- a/pyModeS/extra/rtlreader.py +++ b/pyModeS/extra/rtlreader.py @@ -3,88 +3,105 @@ import pyModeS as pms from rtlsdr import RtlSdr import time -modes_sample_rate = 2e6 +sampling_rate = 2e6 +smaples_per_microsec = 2 + modes_frequency = 1090e6 buffer_size = 1024 * 100 -read_size = 1024 * 20 +read_size = 1024 * 10 pbits = 8 fbits = 112 preamble = [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0] -th_amp = 0.2 # signal amplitude threshold for 0 and 1 bit +# th_amp = 0.2 # signal amplitude threshold for 0 and 1 bit th_amp_diff = 0.8 # signal amplitude threshold difference between 0 and 1 bit class RtlReader(object): def __init__(self, **kwargs): super(RtlReader, self).__init__() - self.signal_buffer = [] + self.signal_buffer = [] # amplitude of the sample only self.sdr = RtlSdr() - self.sdr.sample_rate = modes_sample_rate + self.sdr.sample_rate = sampling_rate self.sdr.center_freq = modes_frequency self.sdr.gain = "auto" - # sdr.freq_correction = 75 self.debug = kwargs.get("debug", False) self.raw_pipe_in = None self.stop_flag = False + self.noise_floor = 1e6 + + def _calc_noise(self): + """Calculate noise floor""" + window = smaples_per_microsec * 100 + means = np.array(self.signal_buffer).reshape(-1, window).mean(axis=1) + return min(means) def _process_buffer(self): + """process raw IQ data in the buffer""" + + # update noise floor + self.noise_floor = min(self._calc_noise(), self.noise_floor) + + # set minimum signal amplitude + min_sig_amp = 3.162 * self.noise_floor # 10 dB SNR + + # Mode S messages messages = [] - # signal_array = np.array(self.signal_buffer) - # pulses_array = np.where(np.array(self.signal_buffer) < th_amp, 0, 1) - # pulses = "".join(str(x) for x in pulses_array) buffer_length = len(self.signal_buffer) i = 0 while i < buffer_length: - if self.signal_buffer[i] < th_amp: + if self.signal_buffer[i] < min_sig_amp: i += 1 continue - # if pulses[i : i + pbits * 2] == preamble: if self._check_preamble(self.signal_buffer[i : i + pbits * 2]): frame_start = i + pbits * 2 frame_end = i + pbits * 2 + (fbits + 1) * 2 frame_length = (fbits + 1) * 2 frame_pulses = self.signal_buffer[frame_start:frame_end] - msgbin = "" + threshold = max(frame_pulses) * 0.2 + + msgbin = [] for j in range(0, frame_length, 2): p2 = frame_pulses[j : j + 2] if len(p2) < 2: break - if p2[0] < th_amp and p2[1] < th_amp: + if p2[0] < threshold and p2[1] < threshold: break elif p2[0] >= p2[1]: - c = "1" + c = 1 elif p2[0] < p2[1]: - c = "0" + c = 0 else: - msgbin = "" + msgbin = [] break - msgbin += c + + msgbin.append(c) # advance i with a jump i = frame_start + j if len(msgbin) > 0: - msghex = pms.bin2hex(msgbin) + msghex = pms.bin2hex("".join([str(i) for i in msgbin])) if self._check_msg(msghex): messages.append([msghex, time.time()]) if self.debug: self._debug_msg(msghex) - elif i > buffer_length - 500: - # save some for next process - break + # elif i > buffer_length - 500: + # # save some for next process + # break else: i += 1 - # keep reminder of buffer for next iteration + # reset the buffer self.signal_buffer = self.signal_buffer[i:] + return messages def _check_preamble(self, pulses): @@ -122,10 +139,8 @@ class RtlReader(object): pass def _read_callback(self, data, rtlsdr_obj): - # scaling signal (imporatant) amp = np.absolute(data) - amp_norm = np.interp(amp, (amp.min(), amp.max()), (0, 1)) - self.signal_buffer.extend(amp_norm.tolist()) + self.signal_buffer.extend(amp.tolist()) if len(self.signal_buffer) >= buffer_size: messages = self._process_buffer()