def process_file(self, file_name): b, a = self.butter_lowpass(100e3, 1e6) with open(file_name, "rb") as f: f.read(self._struct_len) while True: data = f.read(self._struct_len) if not data: break if len(data) != self._struct_len: break slice = numpy.frombuffer(data, dtype=self._struct_elem) if self._struct_elem == numpy.uint8: slice = slice.astype(numpy.float32) # convert to float slice = (slice-127.35)/128. # Normalize slice = slice.view(numpy.complex64) # reinterpret as complex # Multiply the two signals, effectively shifting signal by offset_freq slice = slice*self._shift_signal #slice = self._shift_signal slice = scipy.signal.lfilter(b, a, slice) slice = scipy.signal.decimate(slice, 4) #slice = slice[::4] #slice = self._shift_signal iq.write(sys.stdout, slice)
def process_one(basename, time_stamp, signal_strength, bin_index, freq, signal): mix_signal, mix_freq = cad.cut_and_downmix(signal=signal, search_offset=freq, search_window=search_window) dataarray, data, access_ok, lead_out_ok, confidence, level, nsymbols = dem.demod(mix_signal) msg = "RAW: %s %09d %010d A:%s L:%s %3d%% %.3f %3d %s"%(basename,time_stamp,mix_freq,("no","OK")[access_ok],("no","OK")[lead_out_ok],confidence,level,(nsymbols-12),data) out_queue.put(msg) if mix_freq < 1626e6 and confidence>95 and nsymbols>40 and access_ok==1: iq.write("keep.%010d-f%010d.raw"%(time_stamp,freq),signal)
def process_one(basename, time_stamp, signal_strength, bin_index, freq, signal): mix_signal, mix_freq = cad.cut_and_downmix(signal=signal, search_offset=freq, search_window=search_window) dataarray, data, access_ok, lead_out_ok, confidence, level, nsymbols = dem.demod( mix_signal) msg = "RAW: %s %09d %010d A:%s L:%s %3d%% %.3f %3d %s" % ( basename, time_stamp, mix_freq, ("no", "OK")[access_ok], ("no", "OK")[lead_out_ok], confidence, level, (nsymbols - 12), data) out_queue.put(msg) if mix_freq < 1626e6 and confidence > 95 and nsymbols > 40 and access_ok == 1: iq.write("keep.%010d-f%010d.raw" % (time_stamp, freq), signal)
print "CP length", dp.cp_length cycled_prs = numpy.concatenate((ifft_prs[-dp.cp_length:], ifft_prs)) return cycled_prs else: return ifft_prs #print cycled_prs #print len(cycled_prs) if __name__ == "__main__": #sample_rate = 2048000 sample_rate = 2000000 cycled_prs = modulate_prs(sample_rate) iq.write("/tmp/generated.cfile", cycled_prs) signal = numpy.concatenate(([0] * 2048, cycled_prs)) #signal = numpy.concatenate(([0] * 2048, cycled_prs, [0] * 2048, cycled_prs)) #signal = numpy.concatenate(([0] * 2048, prs, [0] * 2048, prs)) iq.write("/tmp/foo.cfile", signal) #print dp.frequency_interleaving_sequence_array dp = parameters.dab_parameters(1, sample_rate) Tu = dp.fft_length offset = 600 shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * offset / float(sample_rate))
verbose=verbose, debug=debug) dataarray, data, access_ok, lead_out_ok, confidence, level, nsymbols = d.demod( signal) print "RAW: %s %07d %010d A:%s L:%s %3d%% %.3f %3d %s" % ( rawfile, timestamp, freq, ("no", "OK")[access_ok], ("no", "OK")[lead_out_ok], confidence, level, (nsymbols - 12), data) if 0: # Create r / phi file with open("%s.rphi" % (os.path.basename(basename)), 'wb') as out: signal = [ item for sample in signal for item in [abs(sample), cmath.phase(sample)] ] s = "<" + len(signal) * 'f' out.write(struct.Struct(s).pack(*signal)) if debug: # The graphical debugging file iq.write("%s.peaks" % (os.path.basename(basename)), d.peaks) if 0: # The actual samples we used iq.write("%s.samples" % (os.path.basename(basename)), mynormalize(d.samples)) if 0: # The data bitstream with open("%s.data" % (os.path.basename(basename)), 'wb') as out: for c in dataarray: out.write(chr(c))
frequency_offset = float(arg) elif opt in ('-v', '--verbose'): verbose = True elif opt in ('-d', '--decimation'): decimation = int(arg) print "deci:",decimation if sample_rate == None: print >> sys.stderr, "Sample rate missing!" exit(1) if center == None: print >> sys.stderr, "Need to specify center frequency!" exit(1) if len(remainder)==0: file_name = "/dev/stdin" basename="stdin" else: file_name = remainder[0] basename= filename= re.sub('\.[^.]*$','',file_name) signal = iq.read(file_name) cad = CutAndDownmix(center=center, input_sample_rate=sample_rate, symbols_per_second=symbols_per_second, search_depth=search_depth, verbose=verbose, decimation=decimation) signal, freq = cad.cut_and_downmix(signal=signal, search_offset=search_offset, search_window=search_window, frequency_offset=frequency_offset) iq.write("%s-f%010d.cut" % (os.path.basename(basename), freq), signal) print "output=","%s-f%10d.cut" % (os.path.basename(basename), freq)
for i in range(len(auto_correlated)): auto_correlated[i] = numpy.angle(signal[i] * numpy.conj(time_shifted_signal[i])) / 2. / 3.14 * Tu / 2 #plt.plot(auto_correlated) #plt.show() fine_offset = numpy.average(auto_correlated) print "Fine frequency offset:", fine_offset return fine_offset if __name__ == "__main__": import iq sample_rate = 2000000 #Tu = int(2048 * (sample_rate/2048000.)) Tu = sample_rate / 1000 signal = iq.read(sys.argv[1]) time_shifted_signal = signal[Tu:] auto_correlated = [0] * len(time_shifted_signal) for i in range(len(time_shifted_signal)): #auto_correlated[i] = numpy.angle(signal[i] * numpy.conj(time_shifted_signal[i]))/ 2 / 3.14 * 1000 auto_correlated[i] = numpy.angle(signal[i] * numpy.conj(time_shifted_signal[i]))/ 2 / 3.14 * Tu / 2 #print auto_correlated iq.write("/tmp/bar.cfile", auto_correlated)
if verbose: print "raw filename:",rawfile print "base freq:",freq d = Demod(sample_rate=sample_rate, use_correlation=use_correlation, verbose=verbose, debug=debug) dataarray, data, access_ok, lead_out_ok, confidence, level, nsymbols = d.demod(signal) print "RAW: %s %07d %010d A:%s L:%s %3d%% %.3f %3d %s"%(rawfile,timestamp,freq,("no","OK")[access_ok],("no","OK")[lead_out_ok],confidence,level,(nsymbols-12),data) if 0: # Create r / phi file with open("%s.rphi" % (os.path.basename(basename)), 'wb') as out: signal = [item for sample in signal for item in [abs(sample), cmath.phase(sample)]] s = "<" + len(signal) * 'f' out.write(struct.Struct(s).pack(*signal)) if debug: # The graphical debugging file iq.write("%s.peaks" % (os.path.basename(basename)), d.peaks) if 0: # The actual samples we used iq.write("%s.samples" % (os.path.basename(basename)), mynormalize(d.samples)) if 0: # The data bitstream with open("%s.data" % (os.path.basename(basename)), 'wb') as out: for c in dataarray: out.write(chr(c))
if sample_rate == None: print >> sys.stderr, "Sample rate missing!" exit(1) if center == None: print >> sys.stderr, "Need to specify center frequency!" exit(1) if len(remainder) == 0: file_name = "/dev/stdin" basename = "stdin" else: file_name = remainder[0] basename = filename = re.sub('\.[^.]*$', '', file_name) signal = iq.read(file_name) cad = CutAndDownmix(center=center, sample_rate=sample_rate, symbols_per_second=symbols_per_second, preamble_length=preamble_length, search_depth=search_depth, verbose=verbose) signal, freq = cad.cut_and_downmix(signal=signal, search_offset=search_offset, search_window=search_window) iq.write("%s-f%10d.cut" % (os.path.basename(basename), freq), signal) print "output=", "%s-f%10d.cut" % (os.path.basename(basename), freq)
#shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*offset/float(sample_rate)) #signal = signal * shift_signal #phase = -1.21851901212 #signal = signal * cmath.rect(1,-phase) max_cor = 0 best_loc = 0 best_shift = 0 #for offset_khz in range(0, 1): #for offset_khz in range(-10, 10): #for offset_khz in range(-8, -6): # offset = offset_khz * 1000 #print offset_khz for offset in range(offset-500, offset+500): shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*offset/float(sample_rate)) signal_shifted = signal * shift_signal iq.write("/tmp/bar.cfile", signal_shifted) location, cor, phase = estimate_prs(signal_shifted, prs) print offset, cor, location, phase if cor > max_cor: #print "better" max_cor = cor best_loc = location best_shift = offset print max_cor, best_loc, best_shift print best_loc + 492
import iq import sys import numpy import make_prs import matplotlib.pyplot as plt import scipy.signal sample_rate = 2000000 signal = iq.read(sys.argv[1]) offset = -6000 shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * offset / float(sample_rate)) signal = signal * shift_signal iq.write("/tmp/bar.cfile", signal)
def cut_and_downmix(self, signal, search_offset=None, direction=None, frequency_offset=0, phase_offset=0): if self._verbose: iq.write("/tmp/signal.cfile", signal) #t0 = time.time() shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * search_offset / float(self._input_sample_rate)) #print "t_shift_signal:", time.time() - t0 #t0 = time.time() signal = signal * shift_signal #print "t_shift1:", time.time() - t0 #t0 = time.time() signal = scipy.signal.fftconvolve(signal, self._input_low_pass, mode='same') #print "t_filter:", time.time() - t0 #t0 = time.time() signal_center = self._center + search_offset if self._verbose: iq.write("/tmp/signal-shifted-filtered.cfile", signal) signal = signal[::self._decimation] if self._verbose: iq.write("/tmp/signal-filtered-deci.cfile", signal) # Ring Alert and Pager Channels have a 64 symbol preamble if signal_center > 1626000000: preamble_length = 64 direction = iridium.DOWNLINK else: preamble_length = 16 # Take the FFT over the preamble + 10 symbols from the unique word (UW) fft_length = 2**int( math.log(self._output_samples_per_symbol * (preamble_length + 10), 2)) if self._verbose: print 'fft_length', fft_length #signal_mag = [abs(x) for x in signal] #plt.plot(normalize(signal_mag)) #print "t_misc:", time.time() - t0 #t0 = time.time() begin = self._signal_start(signal[:int(self._search_depth * self._output_sample_rate)]) signal = signal[begin:] if self._verbose: print 'begin', begin iq.write("/tmp/signal-filtered-deci-cut-start.cfile", signal) iq.write("/tmp/signal-filtered-deci-cut-start-x2.cfile", signal**2) #print "t_signal_start:", time.time() - t0 #t0 = time.time() signal_preamble = signal[:fft_length]**2 #plt.plot([begin+skip, begin+skip], [0, 1], 'r') #plt.plot([begin+skip+fft_length, begin+skip+fft_length], [0, 1], 'r') if self._verbose: iq.write("/tmp/preamble-x2.cfile", signal_preamble) #plt.plot([x.real for x in signal_preamble]) #plt.plot([x.imag for x in signal_preamble]) #plt.show() signal_preamble = signal_preamble * numpy.blackman( len(signal_preamble)) # Increase size of FFT to inrease resolution fft_result, fft_freq = self._fft(signal_preamble, len(signal_preamble) * 16) fft_bin_size = fft_freq[101] - fft_freq[100] if self._verbose: print 'FFT bin size (Hz)', fft_bin_size * self._output_sample_rate # Use magnitude of FFT to detect maximum and correct the used bin mag = numpy.absolute(fft_result) max_index = numpy.argmax(mag) if self._verbose: print 'FFT peak bin:', max_index print 'FFT peak bin (Hz)', (fft_freq[max_index] * self._output_sample_rate) / 2 #see http://www.dsprelated.com/dspbooks/sasp/Quadratic_Interpolation_Spectral_Peaks.html alpha = abs(fft_result[max_index - 1]) beta = abs(fft_result[max_index]) gamma = abs(fft_result[max_index + 1]) correction = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma) real_index = max_index + correction a = math.floor(real_index) corrected_index = fft_freq[a] + (real_index - a) * fft_bin_size offset_freq = corrected_index * self._output_sample_rate / 2. if self._verbose: print 'FFT bin correction', correction print 'FFT interpolated peak:', max_index - correction print 'FFT interpolated peak (Hz):', offset_freq #print "t_fft:", time.time() - t0 #t0 = time.time() # Generate a complex signal at offset_freq Hz. shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * offset_freq / float(self._output_sample_rate)) # Multiply the two signals, effectively shifting signal by offset_freq signal = signal * shift_signal if self._verbose: iq.write("/tmp/signal-filtered-deci-cut-start-shift.cfile", signal) #print "t_shift2:", time.time() - t0 #t0 = time.time() preamble_uw = signal[:(preamble_length + 16) * self._output_samples_per_symbol] if direction is not None: offset, phase, _ = self._sync_search.estimate_sync_word_freq( preamble_uw, preamble_length, direction) else: offset_dl, phase_dl, confidence_dl = self._sync_search.estimate_sync_word_freq( preamble_uw, preamble_length, iridium.DOWNLINK) offset_ul, phase_ul, confidence_ul = self._sync_search.estimate_sync_word_freq( preamble_uw, preamble_length, iridium.UPLINK) if confidence_dl > confidence_ul: direction = iridium.DOWNLINK offset = offset_dl phase = phase_dl else: direction = iridium.UPLINK offset = offset_ul phase = phase_ul if offset == None: raise DownmixError("No valid freq offset for sync word found") offset = -offset phase += phase_offset offset += frequency_offset #print "t_css:", time.time() - t0 #t0 = time.time() shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * offset / float(self._output_sample_rate)) signal = signal * shift_signal offset_freq += offset if self._verbose: iq.write("/tmp/signal-filtered-deci-cut-start-shift-shift.cfile", signal) #print "t_shift3:", time.time() - t0 #t0 = time.time() #plt.plot([cmath.phase(x) for x in signal[:fft_length]]) # Multiplying with a complex number on the unit circle # just changes the angle. # See http://www.mash.dept.shef.ac.uk/Resources/7_6multiplicationanddivisionpolarform.pdf signal = signal * cmath.rect(1, -phase) if self._verbose: iq.write( "/tmp/signal-filtered-deci-cut-start-shift-shift-rotate.cfile", signal) signal = scipy.signal.fftconvolve(signal, self._rrc, 'same') #print "t_rrc:", time.time() - t0 #plt.plot([x.real for x in signal]) #plt.plot([x.imag for x in signal]) #print max(([abs(x.real) for x in signal])) #print max(([abs(x.imag) for x in signal])) #plt.plot(numpy.absolute(fft_result)) #plt.plot(fft_freq, numpy.absolute(fft_result)) #plt.plot([], [bins[bin]], 'rs') #plt.plot(mag) #plt.plot(signal_preamble) #plt.show() return (signal, signal_center + offset_freq, direction)
def cut_and_downmix(self, signal, search_offset=None, direction=None, frequency_offset=0, phase_offset=0): if self._verbose: iq.write("/tmp/signal.cfile", signal) #t0 = time.time() shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*search_offset/float(self._input_sample_rate)) #print "t_shift_signal:", time.time() - t0 #t0 = time.time() signal = signal * shift_signal #print "t_shift1:", time.time() - t0 #t0 = time.time() signal = scipy.signal.fftconvolve(signal, self._input_low_pass, mode='same') #print "t_filter:", time.time() - t0 #t0 = time.time() signal_center = self._center + search_offset if self._verbose: iq.write("/tmp/signal-shifted-filtered.cfile", signal) signal = signal[::self._decimation] if self._verbose: iq.write("/tmp/signal-filtered-deci.cfile", signal) # Ring Alert and Pager Channels have a 64 symbol preamble if signal_center > 1626000000: preamble_length = 64 direction = iridium.DOWNLINK else: preamble_length = 16 # Take the FFT over the preamble + 10 symbols from the unique word (UW) fft_length = 2 ** int(math.log(self._output_samples_per_symbol * (preamble_length + 10), 2)) if self._verbose: print 'fft_length', fft_length #signal_mag = [abs(x) for x in signal] #plt.plot(normalize(signal_mag)) #print "t_misc:", time.time() - t0 #t0 = time.time() begin = self._signal_start(signal[:int(self._search_depth * self._output_sample_rate)]) signal = signal[begin:] if self._verbose: print 'begin', begin iq.write("/tmp/signal-filtered-deci-cut-start.cfile", signal) iq.write("/tmp/signal-filtered-deci-cut-start-x2.cfile", signal ** 2) #print "t_signal_start:", time.time() - t0 #t0 = time.time() signal_preamble = signal[:fft_length] ** 2 #plt.plot([begin+skip, begin+skip], [0, 1], 'r') #plt.plot([begin+skip+fft_length, begin+skip+fft_length], [0, 1], 'r') if self._verbose: iq.write("/tmp/preamble-x2.cfile", signal_preamble) #plt.plot([x.real for x in signal_preamble]) #plt.plot([x.imag for x in signal_preamble]) #plt.show() signal_preamble = signal_preamble * numpy.blackman(len(signal_preamble)) # Increase size of FFT to inrease resolution fft_result, fft_freq = self._fft(signal_preamble, len(signal_preamble) * 16) fft_bin_size = fft_freq[101] - fft_freq[100] if self._verbose: print 'FFT bin size (Hz)', fft_bin_size * self._output_sample_rate # Use magnitude of FFT to detect maximum and correct the used bin mag = numpy.absolute(fft_result) max_index = numpy.argmax(mag) if self._verbose: print 'FFT peak bin:', max_index print 'FFT peak bin (Hz)', (fft_freq[max_index] * self._output_sample_rate) / 2 #see http://www.dsprelated.com/dspbooks/sasp/Quadratic_Interpolation_Spectral_Peaks.html alpha = abs(fft_result[max_index-1]) beta = abs(fft_result[max_index]) gamma = abs(fft_result[max_index+1]) correction = 0.5 * (alpha - gamma) / (alpha - 2*beta + gamma) real_index = max_index + correction a = math.floor(real_index) corrected_index = fft_freq[a] + (real_index - a) * fft_bin_size offset_freq = corrected_index * self._output_sample_rate / 2. if self._verbose: print 'FFT bin correction', correction print 'FFT interpolated peak:', max_index - correction print 'FFT interpolated peak (Hz):', offset_freq #print "t_fft:", time.time() - t0 #t0 = time.time() # Generate a complex signal at offset_freq Hz. shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*offset_freq/float(self._output_sample_rate)) # Multiply the two signals, effectively shifting signal by offset_freq signal = signal*shift_signal if self._verbose: iq.write("/tmp/signal-filtered-deci-cut-start-shift.cfile", signal) #print "t_shift2:", time.time() - t0 #t0 = time.time() preamble_uw = signal[:(preamble_length + 16) * self._output_samples_per_symbol] if direction is not None: offset, phase, _ = self._sync_search.estimate_sync_word_freq(preamble_uw, preamble_length, direction) else: offset_dl, phase_dl, confidence_dl = self._sync_search.estimate_sync_word_freq(preamble_uw, preamble_length, iridium.DOWNLINK) offset_ul, phase_ul, confidence_ul = self._sync_search.estimate_sync_word_freq(preamble_uw, preamble_length, iridium.UPLINK) if confidence_dl > confidence_ul: direction = iridium.DOWNLINK offset = offset_dl phase = phase_dl else: direction = iridium.UPLINK offset = offset_ul phase = phase_ul if offset == None: raise DownmixError("No valid freq offset for sync word found") offset = -offset phase += phase_offset offset += frequency_offset #print "t_css:", time.time() - t0 #t0 = time.time() shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*offset/float(self._output_sample_rate)) signal = signal*shift_signal offset_freq += offset if self._verbose: iq.write("/tmp/signal-filtered-deci-cut-start-shift-shift.cfile", signal) #print "t_shift3:", time.time() - t0 #t0 = time.time() #plt.plot([cmath.phase(x) for x in signal[:fft_length]]) # Multiplying with a complex number on the unit circle # just changes the angle. # See http://www.mash.dept.shef.ac.uk/Resources/7_6multiplicationanddivisionpolarform.pdf signal = signal * cmath.rect(1,-phase) if self._verbose: iq.write("/tmp/signal-filtered-deci-cut-start-shift-shift-rotate.cfile", signal) signal = scipy.signal.fftconvolve(signal, self._rrc, 'same') #print "t_rrc:", time.time() - t0 #plt.plot([x.real for x in signal]) #plt.plot([x.imag for x in signal]) #print max(([abs(x.real) for x in signal])) #print max(([abs(x.imag) for x in signal])) #plt.plot(numpy.absolute(fft_result)) #plt.plot(fft_freq, numpy.absolute(fft_result)) #plt.plot([], [bins[bin]], 'rs') #plt.plot(mag) #plt.plot(signal_preamble) #plt.show() return (signal, signal_center+offset_freq, direction)