async def streaming(): sdr = RtlSdr() # configure device Fs = 2.4e6 # Hz sdr.sample_rate = Fs # Hz sdr.center_freq = 98e6 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' # Sampling for 1 sec t_sampling = 1 N_samples = round(Fs * t_sampling) samples = sdr.read_samples(N_samples) fig = plt.figure(1) plt.xlabel('Frequency (MHz)') plt.ylabel('Relative power (dB)') fig.show() async for samples in sdr.stream(): plt.psd(samples, NFFT=1024, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) plt.title("Dynamic Plot") plt.draw() plt.pause(0.1) fig.clear() # to stop streaming: await sdr.stop() # done sdr.close()
def check_rtl_device(device): try: sdr = RtlSdr(device_index = device) sdr.close() print("rtlsdr device", device, "ready") except: print("rtlsdr device", device, "not found")
def main(): sdr = RtlSdr() print 'Configuring SDR...' sdr.rs = 2.4e6 sdr.fc = 100e6 sdr.gain = 10 print ' sample rate: %0.6f MHz' % (sdr.rs/1e6) print ' center frequency %0.6f MHz' % (sdr.fc/1e6) print ' gain: %d dB' % sdr.gain print 'Reading samples...' samples = sdr.read_samples(256*1024) print ' signal mean:', sum(samples)/len(samples) print 'Testing callback...' sdr.read_samples_async(test_callback, 256*1024) try: import pylab as mpl print 'Testing spectrum plotting...' mpl.figure() mpl.psd(samples, NFFT=1024, Fc=sdr.fc/1e6, Fs=sdr.rs/1e6) mpl.show() except: # matplotlib not installed/working pass print 'Done\n' sdr.close()
def read_frequency(fq): sdr = RtlSdr() # Set parameters sampling_rate = 2400000 center_freq = fq * 1.000e6 # print(sdr.valid_gains_db) gain = 40.2 sdr.set_sample_rate(sampling_rate) sdr.set_center_freq(center_freq) sdr.set_gain(gain) time_duration = 1 # if noisy plot try longer duration N_Samples = sampling_rate * time_duration y = sdr.read_samples(N_Samples) # comment out after collecting data # y = np.load(str(int(center_freq)) + ".npy") # uncomment after collecting data sdr.close() interval = 2048 chunks = N_Samples // interval N = interval * chunks y = y[:N] # np.save(str(int(center_freq)), y) # comment out after collecting data # Calculate average power spectrum y = y[:len(y // interval * interval)] y = y.reshape(N // interval, interval) y_windowed = y * np.kaiser(interval, 6) Y = fftshift(fft(y_windowed, axis=1), axes=1) Pspect = mean(abs(Y) * abs(Y), axis=0) return Pspect
def main(): sdr = RtlSdr() print 'Configuring SDR...' sdr.rs = 2.4e6 sdr.fc = 100e6 sdr.gain = 10 print ' sample rate: %0.6f MHz' % (sdr.rs / 1e6) print ' center frequency %0.6f MHz' % (sdr.fc / 1e6) print ' gain: %d dB' % sdr.gain print 'Reading samples...' samples = sdr.read_samples(256 * 1024) print ' signal mean:', sum(samples) / len(samples) print 'Testing callback...' sdr.read_samples_async(test_callback, 256 * 1024) try: import pylab as mpl print 'Testing spectrum plotting...' mpl.figure() mpl.psd(samples, NFFT=1024, Fc=sdr.fc / 1e6, Fs=sdr.rs / 1e6) mpl.show() except: # matplotlib not installed/working pass print 'Done\n' sdr.close()
async def streaming(): sdr = RtlSdr() sdr.sample_rate = 1.2e6 sdr.center_freq = 91.8e6 prev = None device.write(np.array([0] * 100000).astype('int16')) async for samples in sdr.stream(): samples = np.array(samples).astype('complex64') samples = signal.decimate(samples, int(1.2e6 / 200e3)) if prev is not None: samples = np.insert(samples, 0, prev) prev = samples[-1] samples = np.angle(samples[1:] * np.conj(samples[:-1])) x = np.exp(-1 / (200e3 * 75e-6)) samples = signal.lfilter([1 - x], [1, -x], samples) samples = signal.decimate(samples, int(200e3 / 50e3)) samples *= 10000 device.write(samples.astype('int16')) await sdr.stop() sdr.close()
async def main(): import math sdr = RtlSdr() print('Configuring SDR...') sdr.rs = 2.4e6 sdr.fc = 100e6 sdr.gain = 10 print(' sample rate: %0.6f MHz' % (sdr.rs / 1e6)) print(' center frequency %0.6f MHz' % (sdr.fc / 1e6)) print(' gain: %d dB' % sdr.gain) print('Streaming samples...') i = 0 async for samples in sdr.stream(): power = sum(abs(s)**2 for s in samples) / len(samples) print('Relative power:', 10 * math.log10(power), 'dB') i += 1 if i > 100: sdr.stop() break print('Done') sdr.close()
class Rtl_threading(threading.Thread): def __init__(self, addr, fc, fs, size, corr): '''Add one more augument, corr''' threading.Thread.__init__(self) self.sdr = RtlSdr(addr) # configure device self.sdr.sample_rate = fs; # Hz self.sdr.center_freq = fc; # Hz # self.freq_correction = corr; # PPM if addr==1: self.sdr.gain = 32.8 else: #0 self.sdr.gain = 32.8 # init param self.addr = addr; self.size = size self.counter = 0; #0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 def run(self): # start lock to avoid reading the same data global event, output; #init the synchronization if event.isSet(): event.clear() event.wait() else: event.set() output[self.addr] = self.sdr.read_samples(self.size); def close(self): self.sdr.close();
async def main(): import math sdr = RtlSdr() print('Configuring SDR...') sdr.rs = 2.4e6 sdr.fc = 100e6 sdr.gain = 10 print(' sample rate: %0.6f MHz' % (sdr.rs/1e6)) print(' center frequency %0.6f MHz' % (sdr.fc/1e6)) print(' gain: %d dB' % sdr.gain) print('Streaming samples...') i = 0 async for samples in sdr.stream(): power = sum(abs(s)**2 for s in samples) / len(samples) print('Relative power:', 10*math.log10(power), 'dB') i += 1 if i > 100: sdr.stop() break print('Done') sdr.close()
async def streaming(): size = 256 x_vec = np.linspace(0, 5, size + 1)[0:-1] y_vec = np.random.randn(len(x_vec)) line1 = [] sdr = RtlSdr() sdr.sample_rate = 2.048e6 # Hz sdr.center_freq = 101e6 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 4 i = 0 async for samples in sdr.stream(256): i = i + 1 print("{i} sample") print(samples) for sample in samples: rand_val = sample * 10000 y_vec[-1] = rand_val line1 = live_plotter(x_vec, y_vec, line1) y_vec = np.append(y_vec[1:], 0.0) print(rand_val) # to stop streaming: await sdr.stop() # done sdr.close()
def collectSignal(freq, freq_file_path, mag_file_path): # Define function for writing signal data into file def write_data(data_points, magnitudeData, frequencyData, mag_file, freq_file): i = 0 mag_file.write('[') freq_file.write('[') while i < data_points - 1: mag_file.write("%s, " % magnitudeData[i]) freq_file.write("%s, " % frequencyData[i]) i += 1 mag_file.write('%s]\n' % magnitudeData[i]) freq_file.write('%s]\n' % frequencyData[i]) sdr = RtlSdr() # Configure SDR sdr.sample_rate = 2.4e6 # Hz sdr.center_freq = freq # Hz sdr.freq_correction = 60 # PPM sdr.gain = 4 # 'auto' # Initialize data_points = 1024 samples = sdr.read_samples(256 * data_points) mag_file_path = mag_file_path + "magdata.txt" freq_file_path = freq_file_path + "freqdata.txt" ### *** IMPORTANT *** (for later, when optimizing) ### I'm not sure if we should leave this outside of the function ### and move it to the end of the main code, after the flight path ### ends. Idk the impact of leaving the SDR open/on for an extended ### period of time. If we move sdr.close() outside, we have to ### remember to also move the above code outside as well. ### Leaving this line within this function should be fine for now. sdr.close() # PSD plot data psddata = psd(samples, NFFT=data_points, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) # Extracting pertinent information from the PSD plot calculation magnitudeData = psddata[0] frequencyData = psddata[1] # Check for .txt file and write data # Magnitude has not been converted to dB yet. To convert, 10*log(magnitude). This comment is for Ron. if Path(mag_file_path).is_file() and Path(freq_file_path).is_file(): with open(mag_file_path, 'a') as mag_file, open(freq_file_path, 'a') as freq_file: write_data(data_points, magnitudeData, frequencyData, mag_file, freq_file) else: with open(mag_file_path, 'w') as mag_file, open(freq_file_path, 'w') as freq_file: write_data(data_points, magnitudeData, frequencyData, mag_file, freq_file)
def capture_samples(self): sdr = RtlSdr() sdr.sample_rate = self.sample_rate sdr.center_freq = self.freq - self.dc_offset sdr.gain = 'auto' self.samples = sdr.read_samples(self.sample_count) self.samples_to_np() sdr.close()
def get_info_from_device_index(self, device_index): self.device_index = device_index if self.device_serial is None: self.device_serial = RtlSdr.get_device_serial_addresses( )[device_index] sdr = RtlSdr(device_index) self._get_info_from_device(sdr) sdr.close()
def get_info_from_device_serial(self, device_serial): self.device_serial = device_serial if self.device_index is None: self.device_index = RtlSdr.get_device_index_by_serial( device_serial) sdr = RtlSdr(device_serial=device_serial) self._get_info_from_device(sdr) sdr.close()
def main(): sdr = RtlSdr() # some defaults sdr.rs = 2.4e6 sdr.fc = 146e6 sdr.gain = 50 noiseWindowLength = 20 noiseWindow = [] rampWindowLength = 5 rampWindow = [] rampPercent = 1.2 backgroundNoise = False pulseFound = False results = [] # Loop enough times to collect 3 seconds of data sampleLoops = int(sdr.rs * 3 / 1024) for i in range(0, sampleLoops): samples = sdr.read_samples(1024) curMag, freqs = magnitude_spectrum(samples, Fs=sdr.rs) maxSignal = max(curMag) noiseWindow.append(maxSignal) if len(noiseWindow) > noiseWindowLength: noiseWindow.pop(0) backgroundNoise = sum(noiseWindow) / noiseWindowLength rampWindow.append(backgroundNoise) if len(rampWindow) > rampWindowLength: rampWindow.pop(0) if rampWindow[rampWindowLength - 1] > rampWindow[0] * rampPercent: pulseFound = True else: pulseFound = False results.append([maxSignal, backgroundNoise, pulseFound]) sdr.close() f = open("data.csv", "w") for result in results: f.write(str(result[0])) f.write(",") f.write(str(result[1])) f.write(",") f.write(str(result[2])) f.write("\n") f.close()
class SDRThread(QThread): signal = pyqtSignal(object) def __init__(self, sample_rate=2.4e6, center_freq=100.0e6, freq_correction=60, gain=33.8, chunks=1024): QThread.__init__(self) # configure device try: self.sdr = RtlSdr() except LibUSBError: print("No Hardware Detected") self.isRunning = False else: self.sdr.sample_rate = sample_rate # Hz self.sdr.center_freq = center_freq # Hz self.sdr.freq_correction = freq_correction # PPM self.sdr.gain = gain # dB self.isRunning = True self.CHUNK = chunks def __del__(self): if self.isRunning: self.wait() def stop_thread(self): self.isRunning = False self.sdr.cancel_read_async() self.sdr.close() def sdr_tune(self, cf): self.sdr.center_freq = cf # Hz def sdr_gain(self, gain=33.8): self.sdr.gain = gain def run(self): if self.isRunning: self.sdr.read_samples_async(self.sdr_async_callback, self.CHUNK, None) def sdr_async_callback(self, iq, ctx): power, _ = mlab.psd(iq, NFFT=self.CHUNK, Fs=self.sdr.sample_rate, scale_by_freq=False) self.signal.emit(np.sqrt(power))
def main(): sdr = RtlSdr() # some defaults sdr.rs = 2.4e6 sdr.fc = 146e6 sdr.gain = 50 noiseWindowLength = 20 noiseWindow = [] rampWindowLength = 5 rampWindow = [] rampPercent = 1.2 backgroundNoise = False pulseFound = False sampleCount = int(sdr.rs * 3 / 1024) f = open("data.csv", "w") for i in range(0, sampleCount): samples = sdr.read_samples(1024) curMag, freqs = magnitude_spectrum(samples, Fs=sdr.rs) maxSignal = max(curMag) noiseWindow.append(maxSignal) if len(noiseWindow) > noiseWindowLength: noiseWindow.pop(0) backgroundNoise = sum(noiseWindow) / noiseWindowLength rampWindow.append(backgroundNoise) if len(rampWindow) > rampWindowLength: rampWindow.pop(0) if rampWindow[rampWindowLength - 1] > rampWindow[0] * rampPercent: pulseFound = True else: pulseFound = False f.write(str(maxSignal)) f.write(",") f.write(str(backgroundNoise)) f.write(",") f.write(str(pulseFound)) f.write("\n") f.close() # cleanup sdr.close()
def main(): sdr = RtlSdr() wf = Waterfall(sdr) # some defaults sdr.rs = 2.4e6 sdr.fc = 100e6 sdr.gain = 10 wf.start() # cleanup sdr.close()
class SDR: def __init__(self,freq): self.sample_rate = 1e6 self.center_freq = freq self.gain = 36 self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain def __del__(self): self.sdr.close()
def main(): sdr = RtlSdr() wf = Waterfall(sdr) # some defaults # Sample rate sdr.rs = 1e6 sdr.set_direct_sampling('q') sdr.fc = 0 sdr.gain = 10 wf.start() # cleanup sdr.close()
def main(): sdr = RtlSdr() wf = Waterfall(sdr) # some defaults sdr.rs = 2.4e6 sdr.fc = 100e6 #sdr.gain = 10 sdr.gain = 'auto' ### setting up TCP server t1 = threading.Thread(target=server_run, args=(q2,)) t1.start() wf.start() # cleanup sdr.close()
def transmit_and_capture(data, outfile, length, title='Captured Data', verbose=False, fs_audio=48000, fs_sdr=240000, fc0=443.650e6, plot=False): """Transmit and receive a signal. length seconds """ sdr = RtlSdr() # Create an RtlSdr object p = pyaudio.PyAudio() # Create a PyAudio object Nsamples=256000*length fc = fc0*(1.0-85e-6) # Get device numbers din, dout, dusb = audio_dev_numbers(p, in_name='USB', out_name='default', debug=verbose) # Create SDR capture thread as daemon capture = threading.Thread(target=sdr_record, args=(sdr, outfile, Nsamples, fc, fs_sdr)) capture.daemon = True # Create play thread as daemon play = threading.Thread(target=play_audio, args=(data, p, fs_audio, dusb)) play.daemon = True # Start both threads capture.start() play.start() time.sleep(length+2) try: if plot: print 'Loading data...' y = np.load(outfile) print 'Generating plot...' tt,ff,xmf = myspectrogram_hann_ovlp(y, 256, fs_sdr, fc) plt.title(title) plt.show() else: print 'Captured data saved to ' + outfile except IOError: type, value, traceback = sys.exc_info() print('Error loading %s: %s' % (value.filename, value.strerror)) except Exception as e: print 'Error: '+str(e) finally: print 'Cleaning up...' sdr.close() p.terminate() print 'Closed SDR and PyAudio'
def main(): now = datetime.datetime.now() current_time = now.strftime("%H:%M:%S.%f") print("Current Time =", current_time) #aquire location #start calibration process (needed?) #start syc process sdr = RtlSdr() # rtl-sdr instance # configure device timeToSample = 1 # in sec sampleRate = 2.4e6 # in Mhz sdr.sample_rate = sampleRate sdr.center_freq = 433e6 # in Mhz sdr.gain = 30 # in dB print("gain set to:", sdr.get_gain()) print(now) numberOfSamples = sampleRate * timeToSample fig = figure() ax = fig.add_subplot(111, projection='3d') # used for 3d IQ/time plot samples = sdr.read_samples(numberOfSamples) # aquire samples sdr.close() # I/Q seperation real = samples.real imag = samples.imag samp = np.arange(0, numberOfSamples, 1) # used as an axis #ax.scatter(samp[0:-1:100],real[0:-1:100],imag[0:-1:100],marker='^',s=2)#used for pumba slack simulateRecivers(real, sampleRate) # used to simulation #plt.subplot(3, 1, 2) # xlabel('Real axis')#used for pumba slack # ylabel('img axis')#used for pumba slack ''' pxx,farr=psd(samples, NFFT=1024, Fs=sampleRate / 1e6, Fc=sdr.center_freq / 1e6) plt.subplot(2, 1, 1) plt.plot(samp, imag) plt.subplot(2, 1, 2) plt.plot(farr,pxx) ''' show()
def find_devices() -> str: devices = "" # could do with a call that returns the valid device_index's max_device = 10 for device in range(max_device): try: sdr = RtlSdr(device_index=device) type_of_tuner = sdr.get_tuner_type() # index = sdr.get_device_index_by_serial('0000001') # permissions required # addresses = sdr.get_device_serial_addresses() # permissions required sdr.close() devices += f"device {device}, type {type_of_tuner} {allowed_tuner_types[type_of_tuner]}\n" except Exception: pass if devices == "": devices = f"No rtlsdr devices found, scanned 0 to {max_device-1}" print(devices) return devices
def main(): sdr = RtlSdr(1) wf = Waterfall(sdr) # some defaults sdr.rs = 1.024e6 sdr.fc = 89.3e6 sdr.gain = 'auto' wf.start() # cleanup sdr.close()
def main(): sdr = RtlSdr() print 'Configuring SDR...' sdr.rs = 2.4e6 sdr.fc = 70e6 sdr.gain = 4 print ' sample rate: %0.6f MHz' % (sdr.rs / 1e6) print ' center frequency %0.6f MHz' % (sdr.fc / 1e6) print ' gain: %d dB' % sdr.gain print 'Reading samples...' samples = sdr.read_samples(1024) print ' signal mean:', sum(samples) / len(samples) print 'Testing callback...' sdr.read_samples_async(test_callback) sdr.close()
def main(): sdr = RtlSdr() print 'Configuring SDR...' sdr.rs = 2.4e6 sdr.fc = 70e6 sdr.gain = 4 print ' sample rate: %0.6f MHz' % (sdr.rs/1e6) print ' center frequency %0.6f MHz' % (sdr.fc/1e6) print ' gain: %d dB' % sdr.gain print 'Reading samples...' samples = sdr.read_samples(1024) print ' signal mean:', sum(samples)/len(samples) print 'Testing callback...' sdr.read_samples_async(test_callback) sdr.close()
def read_n_plot(): sdr = RtlSdr() # configure device sdr.sample_rate = 2.4e6 sdr.center_freq = 90e6 sdr.gain = 4 samples = sdr.read_samples(12000 * 1024) sdr.close() demod_result = demodulate(samples) write_to_txt(demod_result) write_to_audio(demod_result, "recmusic.wav") plot_t(demod_result) # use matplotlib to estimate and plot the PSD psd(samples, NFFT=1024, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) xlabel('Frequency (MHz)') ylabel('Relative power (dB)') show()
def capture(freq, label, range_freq, range_gain): for freq_var in range_freq: for gain_var in range_gain: # Configure device (freq in herz, freq_correction is PPM) sdr = RtlSdr() sdr.sample_rate = 250000 sdr.center_freq = freq + freq_var sdr.freq_correction = 60 sdr.gain = gain_var # Read 10 seconds of 250k sampled data samples = sdr.read_samples(10 * 256 * 1024) sdr.close() # Use matplotlib to estimate and plot the PSD psd(samples[:65536], NFFT=1024, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) #print(psd) xlabel('Frequency (MHz)') ylabel('Relative power (dB)') # Show and save a pic #show() file_name = 'data-' + label + '-' + str( double(freq + freq_var)) + '-g-' + str(gain_var) print("Saving " + file_name) savefig(file_name + '.png') # Save samples to file fh = open(file_name + '.iq', "wb") x = samples x = x[:5000000] for sample in x: ba = bytearray(struct.pack("f", numpy.float32(sample.real))) for b in ba: fh.write(bytearray([b])) ba = bytearray(struct.pack("f", numpy.float32(sample.imag))) for b in ba: fh.write(bytearray([b])) fh.close() clf()
def find_powerfull_FM(): sdr = RtlSdr() # configure device Fs = 2e6 # Hz sdr.sample_rate = Fs # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' FM_band_min = 87.5 FM_band_max = 109 powe = np.ndarray(0) freq = np.ndarray(0) t_sampling = 0.1 # Sampling for 100 ms N_samples = round(Fs * t_sampling) for i in np.arange(FM_band_min, FM_band_max, Fs / 1e6): sdr.center_freq = i * 1e6 # Hz counter = 0 prev_int = 0 while 1: counter = counter + 1 samples = sdr.read_samples(N_samples) ################################################################################### power, psd_freq = plt.psd(samples, NFFT=1024, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) ##################################################################################### ind_pow = np.argmax(power) freq_ind = round(psd_freq[ind_pow], 1) if freq_ind == prev_int and counter >= 3: powe = np.append(powe, ind_pow) freq = np.append(freq, freq_ind) break prev_int = freq_ind # done sdr.close() max_fm_station_power = np.argmax(powe) max_fm_station_freq = freq[max_fm_station_power] return max_fm_station_freq
def main(): gin = sys.argv[1] ppm = sys.argv[2] chn = sys.argv[3] if ppm == '0': ppm = '1' if chn == 'a': frc = 161.975e6 if chn == 'b': frc = 162.025e6 sdr = RtlSdr() wf = Waterfall(sdr) # some defaults sdr.rs = 1e6 sdr.fc = frc sdr.gain = float(gin) sdr.freq_correction = int(float(ppm)) wf.start() # cleanup sdr.close()
def main(): gin=sys.argv[1] ppm=sys.argv[2] chn=sys.argv[3] if ppm=='0': ppm='1' if chn=='a': frc=161.975e6 if chn=='b': frc=162.025e6 sdr = RtlSdr() wf = Waterfall(sdr) # some defaults sdr.rs = 1e6 sdr.fc = frc sdr.gain = float(gin) sdr.freq_correction = int(float(ppm)) wf.start() # cleanup sdr.close()
async def streaming(sample_processor: Callable[[SampleStream, RtlSdr], None], center_freq=100300000, sample_rate=2.048e6): """SDR streaming function :param sample_processor: Function that is used to process the samples, must take an array of floats as the first argument and an sdr object (for metadata) as the second :param sample_rate: The sample rate to obtain samples at in Hz :param center_freq int: The center frequency for capturing in Hz """ sdr = RtlSdr() sdr.sample_rate=sample_rate sdr.center_freq = center_freq sdr.freq_correction = 60 sdr.gain = 'auto' async for samples in sdr.stream(): sample_processor(samples, sdr) await sdr.stop() sdr.close()
def storing_stream_with_windows(l, device_number, folder, subfolders, center_frequency, samplerate, gain, nsamples, freq_correction, user_hash): l.acquire() print(device_number, center_frequency, samplerate, gain, nsamples, freq_correction) # configure device sdr = RtlSdr(device_index=device_number) sdr.center_freq = center_frequency sdr.sample_rate = samplerate if freq_correction: sdr.freq_correction = freq_correction # PPM sdr.gain = gain print('hello world') timestamp = time.mktime(time.gmtime()) samples = sdr.read_bytes(nsamples*2) sdr.close() l.release() print("save") basename = "{hash}_{freq}_{time:0.0f}".format(hash=user_hash, freq=center_frequency, time=timestamp) filename = path.join(folder, subfolders[0], "tmp_" + basename) # np.savez_compressed(filename, samples) # storing by numpy and copressing it '''np.save(filename, samples) os.rename(filename + ".npy", path.join(folder, subfolders[0], basename + ".npy"))''' f = open(filename, 'wb') f.write(samples) f.close() os.rename(filename, path.join(folder, subfolders[0], basename + ".dat")) del samples filename = path.join(folder, subfolders[1], basename + ".npy") sdrmeta(filename, device_number, folder, subfolders, center_frequency, samplerate, gain, nsamples, freq_correction, user_hash) return filename
def main(): sdr = RtlSdr() wf = Waterfall(sdr) # some defaults sdr.rs = 1e6 sdr.fc = 103.4e6 sdr.gain = 10 # mqtt client client.on_connect = on_connect client.username_pw_set("slip","slip") client.connect("ec2-35-180-123-52.eu-west-3.compute.amazonaws.com",1883) #client.loop_start() #client.publish("laverie/1","102.5,0") #client.disconnect() #client.loop_stop() wf.start() # cleanup sdr.close()
def from_rtl(self, freq=93.3e6, rate=256000, samples=8192000): try: sdr = RtlSdr() # configure device # in Hz sdr.sample_rate = int(rate) sdr.center_freq = freq sdr.gain = 'auto' # Read samples samples = sdr.read_samples(samples) # Clean up the SDR device sdr.close() del (sdr) self.data = np.array(samples).astype('complex64') self.dtype = self.data.dtype self.rate = rate * u.Hz self.center_freq = freq * u.Hz self.nitems = len(self.data) self.exptime = (self.nitems / self.rate) except: raise IOError("Could not read from RTLSDR")
def storing_stream_with_windows(lock, rs, cf, gain, ns, device, path_storing): if 0==0:#librtlsdr.rtlsdr_get_device_count() > 0: lock.acquire(timeout=ns/rs*1.1) print("locked") sdr = RtlSdr(device_index = device) # some defaults sdr.rs = rs sdr.fc = cf sdr.gain = gain timestamp = time.time() samples = sdr.read_bytes(ns * 2) sdr.close() lock.release() #print("print") filename = get_groundstationid() + "_f" + str(cf) + "_d" + str(device) + "_t" + str(int(timestamp)) f = open(path_storing + filename + ".tmp", 'wb') f.write(samples) f.close() os.rename(path_storing + filename + ".tmp", path_storing + filename + ".dat")
class FMRadio: # num samplesmust be multiple of 256 def __init__(self,freq,N_samples): self.sample_rate = 1e6 self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2e5/44100 # for baseband recovery self.center_freq = freq+250e3 self.gain = 36 self.N_samples = N_samples self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = 'auto' #self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 2, rate = 44100, output = True) adj = 0 hamming = 10*signal.hamming(self.N_samples*.10 + adj) lpf = np.append( np.zeros(self.N_samples*.45),hamming) self.lpf = np.roll(np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*.45))),int(-.25*self.N_samples)) def __del__(self): print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a blocksize amount's time return self.sdr.read_samples(self.N_samples) # def demodulate_threaded(self,samples): # async_demodulation = self.pool.apply_async(self.demodulate, samples, callback=self.play) def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fft(samples)*self.lpf toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(spectrum)) plt.show() # Decimate in two rounds. One to 200k, another to 44.1k # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. n_s = spectrum.size channel_spectrum = spectrum[int(n_s*.75-.5*n_s/self.decim_r1):int(.75*n_s+.5*n_s/self.decim_r1)] #np.append(spectrum[0:int(n_s/self.decim_r1*.5)],spectrum[n_s-int(n_s/self.decim_r1*.5):n_s]) #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias #print channel_spectrum.size toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(np.fft.ifftshift(channel_spectrum))) plt.show() lp_samples = np.fft.ifft(np.fft.ifftshift(channel_spectrum)) power = np.abs(self.rms(lp_samples)) lp_samples /= power #lp_samples = self.lowpass_filter(lp_samples,4) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) #dpm = np.mean(np.abs(dphase)) # normalize # dphase /= dpm dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,21) # np.cos(dphase) #phase = np.sin(rebuilt) #phase = self.lowpass_filter(phase,8) #rebuilt= self.lowpass_filter(rebuilt,8) toplot = False if toplot: fig = plt.figure() ax = fig.add_subplot(111) ax.plot(rebuilt) plt.show() modulated = rebuilt * np.sin(2*np.pi*38000/2e5*np.r_[0:rebuilt.size]) spectrum = np.fft.fft(rebuilt) mod_spectrum = np.fft.fft(modulated) #* self.lpf2 n_z = spectrum.size #base_spectrum = np.append(spectrum[0:1024],spectrum[n_z-1024:n_z]) base_spectrum = np.append(spectrum[0:int(n_z/self.decim_r2*.5)],spectrum[n_z-int(n_z/self.decim_r2*.5):n_s]) stereo_spectrum = np.append(mod_spectrum[0:int(n_z/self.decim_r2*.5)],mod_spectrum[n_z-int(n_z/self.decim_r2*.5):n_s]) stereo_spectrum *= np.fft.ifftshift(np.hamming(stereo_spectrum.size)) toplot = False if(toplot): fig = plt.figure() plt.plot(np.linspace(-22050,22050,stereo_spectrum.size),np.abs(np.fft.fftshift(stereo_spectrum)), np.linspace(-22050,22050,base_spectrum.size),.05*np.abs(np.fft.fftshift(base_spectrum))) plt.show() output = np.fft.ifft(base_spectrum) diff =np.fft.ifft(stereo_spectrum) #check: should be 1807 or very close to it. it is!! #output = self.lowpass_filter(np.real(output),8) #[12:8204] stereo = np.zeros(output.size*2,dtype='complex') left = output + 10*diff right = output - 10* diff stereo[0:stereo.size:2] = left stereo[1:stereo.size:2] = right #print 1e6/n_s / 44100 * output.size return np.real(stereo) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(output) def lowpass_filter(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi wndw = np.kaiser(width,6) wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw) return new_array[int(width/2):x.size+int(width/2)] # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): while True: self.play(self.demodulate(self.getSamples()))
class FMRadio: sample_buffer = Queue.Queue(maxsize=100) base_spectrum = np.ones(5780) def __init__(self,freq,N_samples): self.sample_rate = 1e6 self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2e5/44100 # for baseband recovery self.center_freq = freq+250e3 self.gain = 36 self.N_samples = N_samples self.is_sampling = False self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 1, rate = 44100, output = True) adj = 0 hamming = 10*signal.hamming(self.N_samples*.10 + adj) lpf = np.append( np.zeros(self.N_samples*.45),hamming) self.lpf = np.roll(np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*.45))),int(-.25*self.N_samples)) def __del__(self): print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a 2048/44100 amount's time return self.sdr.read_samples(self.N_samples) def getSamplesAsync(self): #Asynchronous call. Meant to be put in a loop w/ a calback fn #print 'gonna sample' self.is_sampling = True samples = self.sdr.read_samples_async(self.sampleCallback,self.N_samples,context=self) def sampleCallback(self,samples,sself): self.is_sampling = False self.sample_buffer.put(samples) #print 'put some samples in the jar' # recursive loop #sself.getSamplesAsync() def demodulate_th(self): while(1): try: samples = self.sample_buffer.get() #samples2 = self.sample_buffer.get() # print 'gottum' except: print "wtf idk no samples?" break out1 = self.demodulate(samples) self.sample_buffer.task_done() #out2 = self.demodulate(samples2) #self.sample_buffer.task_done() audio_out = out1 #np.append(out1,out2) self.play(audio_out) print 'gonna try to finish off the to-do list' sample_buffer.join() def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fft(samples)*self.lpf toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(spectrum)) plt.show() # Decimate in two rounds. One to 200k, another to 44.1k # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. n_s = spectrum.size channel_spectrum = spectrum[int(n_s*.75-.5*n_s/self.decim_r1):int(.75*n_s+.5*n_s/self.decim_r1)] #np.append(spectrum[0:int(n_s/self.decim_r1*.5)],spectrum[n_s-int(n_s/self.decim_r1*.5):n_s]) #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias #print channel_spectrum.size toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(np.fft.ifftshift(channel_spectrum))) plt.show() lp_samples = np.fft.ifft(np.fft.ifftshift(channel_spectrum)) #lp_samples = self.lowpass_filter(lp_samples,4) power = np.abs(self.rms(lp_samples)) lp_samples /= power #print np.abs(self.rms(lp_samples)) # polar discriminator dphase = np.zeros(lp_samples.size) A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) #dpm = np.mean(np.abs(dphase)) # normalize # dphase /= dpm #dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,21) # np.cos(dphase) #phase = np.sin(rebuilt) #phase = self.lowpass_filter(phase,8) #rebuilt= self.lowpass_filter(rebuilt,8) toplot = False if toplot: fig = plt.figure() ax = fig.add_subplot(111) ax.plot(rebuilt) plt.show() spectrum = np.fft.fft(rebuilt) #* self.lpf2 n_z = spectrum.size #base_spectrum = np.append(spectrum[0:1024],spectrum[n_z-1024:n_z]) self.base_spectrum = np.append(spectrum[0:int(n_z/self.decim_r2*.5)],spectrum[n_z-int(n_z/self.decim_r2*.5):n_s]) output = np.fft.ifft(self.base_spectrum) output = self.lowpass_filter(np.real(output),8) # just the tip (kills the 19k pilot) # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.real(output)) # plt.show() return np.real(output) def updateimg(self,base_spectrum): spectralimg = np.zeros((base_spectrum.size/20,base_spectrum.size/10)) for i in np.r_[0:base_spectrum.size/10]: spectralimg[np.abs(np.fft.fftshift(base_spectrum)[i*10]/10),i] = 1 cv2.imshow('spectrum',spectralimg) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(output) # utility functions # def lowpass_filter(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi wndw = np.kaiser(width,6) #wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw) return new_array[int(width/2):x.size+int(width/2)] # calculate mean average deviation # def mad(self,samples): ave = np.mean(samples) return np.mean(np.abs(samples-ave)) # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): streamer = MakeDaemon(self.demodulate_th) # run demodulation in the 'background' streamer.start() self.count = 0 while(1): if not self.is_sampling: self.getSamplesAsync() # sampler loop
class Demod: SAMP_RATE = 256000. SAMP_WINDOW = 1024*40 def __init__(self): self.sdr = RtlSdr() # Sampling rate self.sdr.rs = Demod.SAMP_RATE # Pins 1 and 2 self.sdr.set_direct_sampling(1) # I don't think this is used? self.sdr.gain = 1 def run(self, limit=None, callback=lambda x: print(x), carrier=32000, bw=1000, sps=8, codes=manchester, mod=Mods.MAGNITUDE, header=HEADER, footer=FOOTER, pktlen=PKTBYTES): # Center frequency self.sdr.fc = carrier self.mod = mod self.header = header self.footer = footer self.pktlen = 8*pktlen + len(footer) self.rxcallback = callback decim = Demod.SAMP_RATE/bw/sps assert decim == int(decim) self.decim = int(decim) assert Demod.SAMP_WINDOW % self.decim == 0 self.sampchips = Demod.SAMP_WINDOW / self.decim self.corr = codes2corr(codes, sps) self.codelen = len(self.corr[0]) self.last = np.zeros(Demod.SAMP_WINDOW) self.index = 0 self.tocheck = [None] * self.codelen for i in range(self.codelen): self.tocheck[i] = dict() self.tocheck[i]['last'] = ''.join(range(0)) self.tocheck[i]['pkts'] = range(0) if limit is None: def byte_callback(samp, sdr): if select.select([sys.stdin], [], [], 0)[0]: sdr.cancel_read_async() self.ddc(samp, sdr) else: @limit_calls(limit) def byte_callback(samp, sdr): if select.select([sys.stdin], [], [], 0)[0]: sdr.cancel_read_async() self.ddc(samp, sdr) self.sdr.read_bytes_async(byte_callback, Demod.SAMP_WINDOW*2) print (self.index, "samples read") sys.stdout.flush() sys.stdin.readline() def bb2c(self, baseband): mag = np.abs(baseband) phase = np.angle(baseband) dp = np.mod(np.ediff1d(phase)+np.pi, 2*np.pi)-np.pi return mag[1:], phase[1:], dp def decode(self, chips): corrs = [] for c in self.corr: corrs.append(np.correlate(chips, c)) # Vector correlations if np.iscomplex(corrs).any(): corrs = np.abs(corrs) maxes = np.max(np.array(corrs), 0) codes = np.argmax(np.array(corrs), 0) return maxes, codes def debounce(self, i, l, rxstr): try: if i != self.debounce_i or abs(l - self.debounce_l) > 1: self.rxcallback(rxstr) except AttributeError: self.rxcallback(rxstr) self.debounce_i = i self.debounce_l = l def extract(self, nc): for codeoffset in range(self.codelen): pkts = [] codestr = "".join(map(repr, map(int, nc[codeoffset::self.codelen]))) for p in self.tocheck[codeoffset]['pkts']: pkt = p + codestr[0:self.pktlen-len(p)] if len(pkt) < self.pktlen: pkts.append(pkt) elif len(self.footer) == 0 or pkt[-len(self.footer):] == self.footer: str = "" for j in range(0,len(pkt)-1,8): str += chr(int(pkt[j:j+8][::-1], 2)) self.debounce(self.index, -len(p), str) sys.stdout.flush() codestr = self.tocheck[codeoffset]['last'] + codestr for ind in find_all(codestr, self.header): pkt = codestr[ind+len(self.header):ind+len(self.header)+self.pktlen] if len(pkt) < self.pktlen: pkts.append(pkt) elif len(self.footer) == 0 or pkt[-len(self.footer):] == self.footer: str = "" for j in range(0,len(pkt)-1,8): str += chr(int(pkt[j:j+8][::-1], 2)) self.debounce(self.index, ind, str) sys.stdout.flush() self.tocheck[codeoffset]['pkts'] = [] + pkts self.tocheck[codeoffset]['last'] = "" + codestr[-len(self.header)+1:] def ddc(self, samp, sdr): s = np.asarray(samp) i, q = s[::2], s[1::2] i = np.mean(i.reshape(-1,self.decim), 1) # poor man's decimation q = np.mean(q.reshape(-1,self.decim), 1) # poor man's decimation iq = np.empty(len(i), 'complex') iq.real, iq.imag = i, q iq /= (255/2) iq -= (1 + 1j) baseband = np.concatenate((self.last, iq)) self.last = iq mag, phase, dp = self.bb2c(baseband) if self.mod == Mods.MAGNITUDE: sig = mag elif self.mod == Mods.PHASE: sig = phase elif self.mod == Mods.DPHASE: sig = dp else: sig = baseband corrs, codes = self.decode(sig) nc = codes[self.codelen:self.codelen+self.sampchips] self.extract(nc) self.index += 1 def end(self): self.sdr.close() def plot(self): plt.ion() fig = plt.figure() ax1 = fig.add_subplot(311) ax1.plot(self.chips) ax2 = fig.add_subplot(312, sharex=ax1) ax2.plot(self.corrs) ax3 = fig.add_subplot(313, sharex=ax1) ax3.plot(self.demod) plt.show() def checkdemod(self, index, demod=None, packetlen=5): if demod is None: demod = self.demod l = packetlen*8+6+7 b = self.demod[index:index+l*self.codelen:self.codelen] return chipsToString(np.concatenate(([1,0], b, [0]))) def findstring(self, demod = None, packetlen=5): if demod is None: demod = self.demod find = [] for i in range(len(demod)): s, c = self.checkdemod(i, demod, packetlen) if len(s) and s[0] == 'a' and s[-1] == 'x': find.append((i, s[1:-1])) return find
class FMRadio(QtGui.QMainWindow,Ui_MainWindow): sample_buffer = Queue.Queue(maxsize=10) base_spectrum = np.ones(5780) plotOverall = True plotChannel = False plotPlaying = False plotWaveform = False useStereo = False stereoWidth = 10 useMedianFilt = True useLPFilt = True demodFiltSize = 100000 useAudioFilter = True audioFilterSize = 16 toDraw = True demodMain = True demodSub1 = False demodSub2 = False toDrawWaterfalls = True toDrawPlots = False prevCutoff = 0 prevSpec1 = np.zeros(128) prevSpec2 = np.zeros(128) prevSpec3 = np.zeros(128) prevConvo1 = np.zeros(128) prevConvo2 = np.zeros(128,dtype='complex') limiterMax = np.zeros(32) toPlot = (np.cumsum(np.ones(5780)),np.cumsum(np.ones(5780))) def __init__(self,freq,N_samples): self.spectrogram = np.zeros((512,400)) self.chspectrogram = np.zeros((512,400)) self.plspectrogram = np.zeros((256,400)) self.cur_spectrogram = self.spectrogram QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.createQtConnections() ftxt = "%.1f MHz" % (freq/1e6) self.ui.curFreq.setText(ftxt) self.sample_rate = 2.4e5 # tried 1.024e6 - not so great self.decim_r1 = 1 # 1.024e6/2.4e5 # for wideband fm down from sample_rate self.decim_r2 = 2.4e5/48000 # for baseband recovery self.center_freq = freq #+250e3 self.gain = 16 self.N_samples = N_samples self.is_sampling = False self.sdr = RtlSdr() #self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 2, rate = 48000, output = True) self.PLL = PhaseLockedLoop(self.N_samples,19000,self.sample_rate) self.initOpenCV() self.noisefilt = np.ones(6554) b,a = signal.butter(1, 2122/48000*2*np.pi, btype='low') self.demph_zf = signal.lfilter_zi(b, a) adj = 0 hamming = np.kaiser(self.N_samples/4 + adj,1) lpf = np.append( np.zeros(self.N_samples*3/8),hamming) self.lpf = np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*3/8))) #,int(-.25*self.N_samples)) hamming = 10*signal.hamming(self.N_samples/16) lpf = np.append(np.zeros(self.N_samples*15/32),hamming) self.lpf_s1 = (np.append(lpf,np.zeros(int(self.N_samples*15/32)))) #self.lpf_s1 = np.roll(temp,int(.5*self.N_samples*67/120)) #self.lpf_s1 += np.roll(temp,int(-.5*self.N_samples*67/120)) self.lpf_s1 = np.fft.fftshift(self.lpf_s1) #self.lpf_s1 += np.fft.fftshift(self.lpf_s1) # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(range(self.lpf_s1.size),self.lpf_s1) # fig.show() hamming = 10*signal.hamming(self.N_samples/32) lpf = np.append(np.zeros(self.N_samples*31/64),hamming) self.lpf_s2 = (np.append(lpf,np.zeros(int(self.N_samples*31/64)))) #self.lpf_s2 = np.roll(temp,int(.5*self.N_samples*92/120)) #self.lpf_s2 += np.roll(temp,int(-.5*self.N_samples*92/120)) self.lpf_s2 = np.fft.fftshift(self.lpf_s2) # Not currently used def getSamples(self): return self.sdr.read_samples(self.N_samples); def getSamplesAsync(self): #Asynchronous call. Initiates a continuous loop with the callback fn self.is_sampling = True samples = self.sdr.read_samples_async(self.sampleCallback,self.N_samples,context=self) def sampleCallback(self,samples,sself): self.is_sampling = False self.sample_buffer.put(samples) #print 'put some samples in the jar' # recursive loop #sself.getSamplesAsync() def demodulate_th(self): # Initiates a loop to process all the incoming blocks of samples from the Queue # This should be run in its own thread, or the program will become unresponsive while(1): try: samples = self.sample_buffer.get() #samples2 = self.sample_buffer.get() except: #print "wtf idk no samples?" # even though this can't happen... (although I'm not sure why not) #print 'gonna try to finish off the to-do list' #self.sample_buffer.join() break out1 = self.demodulate(samples) self.sample_buffer.task_done() #out2 = self.demodulate(samples2) #self.sample_buffer.task_done() audio_out = out1 #np.append(out1,out2) self.play(audio_out) def gen_spectrogram(self,x,m,prevSpec): itsreal = np.isreal(x[0]) m = int(m) lx = x.size nt = (lx) // m #NT = (lx +m -1)//m #padsize = NT*m -lx cutsize = lx -nt*m padsize = int(cutsize + m/2) if not prevSpec.size == padsize: prevSpec = np.zeros(padsize) xp = np.append(x[cutsize:],prevSpec) prevSpec = x[:(padsize)] xh = np.zeros((m,nt*2), dtype='complex') for n in range(int(nt*2)): block = xp[m*n//2:m*(n+2)//2] xh[:,n] = block*np.hanning(block.size) #if self.prevSpec.size == padsize: # xb = np.append(self.prevSpec[:prevSpec.size-m/2],x) # xc = np.append(self.prevSpec,x[:lx-m/2]) # self.prevSpec = x[lx-m/2:] #else: # xb = np.append(x,np.zeros(-lx+nt*m)) # xc = np.append(x[m/2:],np.zeros(nt*m - lx + m/2)) #xr = np.reshape(xb, (m,nt), order='F') * np.outer(np.hanning(m),np.ones(nt)) #xs = np.reshape(xc, (m,nt), order='F') * np.outer(np.hanning(m),np.ones(nt)) #xm = np.zeros((m,2*nt),dtype='complex') #xm[:,::2] = xr #xm[:,1::2] = xs if itsreal: spec = np.fft.fft(xh,m,axis=0) spec = spec[:m//2,:] else: spec = np.fft.fftshift(np.fft.fft(xh,m,axis=0)) #mx = np.max(spec) pwr = np.log(np.abs(spec) + 1e-6) return (np.real(pwr),prevSpec) def initOpenCV(self): cv2.namedWindow("Spectrogram") def demodulate(self,samples): # DEMODULATION CODE - And the core function # samples must be passed in by the caller self.count += 1 #spectral_window = signal.hanning #spectrum = np.fft.fftshift(np.fft.fft(samples*spectral_window(samples.size))) self.spectrogram = np.roll(self.spectrogram, 16,axis=1) stft,self.prevSpec1 = self.gen_spectrogram(samples,samples.size//8,self.prevSpec1) self.spectrogram[:,:16] = stft[::8,:] # np.log(np.abs(spectrum[::100])) if(self.plotOverall): # and self.count % 10 == 9): #self.drawSpectrum() self.cur_spectrogram = self.spectrogram self.drawCurSpectrum() # cutoff = self.demodFiltSize # h = signal.firwin(128, cutoff,nyq=self.sample_rate/2) # lp = signal.fftconvolve(samples[::self.decim_r1],h,mode='full') # lps = lp.size # hs = h.size # prev = lp[lps-hs:] # lp[:hs/2] += self.prevConvo2[hs/2:] # lp = np.append(self.prevConvo2[:hs/2],lp) # self.prevConvo2 = prev # lp_samples = lp[:lps-hs+1] lp_samples = samples power = np.abs(self.mad(lp_samples)) self.ui.signalMeter.setValue(20*(np.log10(power))) # polar discriminator dphase = np.zeros(lp_samples.size, dtype='complex') A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase[1:] = ( A * np.conj(B) ) dphase[0] = lp_samples[0] * np.conj(self.prevCutoff) #dphase[dphase.size-2] self.prevCutoff = lp_samples[lp_samples.size-1] # limiting dphase /= np.abs(dphase) # if self.useMedianFilt: # rebuilt = signal.medfilt(np.angle(dphase)/np.pi,self.demodFiltSize) # np.cos(dphase) # else: # rebuilt = self.lowpass(np.angle(dphase),self.demodFiltSize) rebuilt = np.real(np.angle(dphase) / np.pi) demodMain = False demodSub1 = False demodSub2 = False isStereo = False if self.demodMain: demodMain = True if self.useStereo: isStereo = True elif self.demodSub1: demodSub1 = True elif self.demodSub2: demodSub2 = True #spectrum = np.fft.fft(rebuilt* spectral_window(rebuilt.size)) #print rebuilt.size/8 self.chspectrogram = np.roll(self.chspectrogram, 16,axis=1) stft,self.prevSpec2 = self.gen_spectrogram(rebuilt,rebuilt.size/8,self.prevSpec2) self.chspectrogram[:,:16] = stft[::-4,:] # np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:50])) if(self.plotChannel):# and self.count % 10 == 9): self.cur_spectrogram = self.chspectrogram self.drawCurSpectrum() #plotspectrum = np.abs(channel_spectrum[::100]) #self.toPlot = (np.linspace(-np.pi,np.pi,plotspectrum.size),plotspectrum) #self.replot() n_z = rebuilt.size if demodMain: h = signal.firwin(128,16000,nyq=1.2e5) output = signal.fftconvolve(rebuilt,h,mode='full') outputa = output # could be done in place but I'm not concerned with memory outputa[:h.size/2] += self.prevConvo1[h.size/2:] #add the latter half of tail end of the previous convolution outputa = np.append(self.prevConvo1[:h.size/2], outputa) # also delayed by half size of h so append the first half self.prevConvo1 = output[output.size-h.size:] # set the tail for next iteration output = outputa[:output.size-h.size:self.decim_r2] # chop off the tail and decimate #stereo_spectrum = spectrum if isStereo: #pilot = rebuilt * np.cos(2*np.pi*19/240*(np.r_[0:rebuilt.size])) h = signal.firwin(512,[18000,20000],pass_zero=False,nyq=1.2e5) pilot_actual = signal.fftconvolve(rebuilt,h,mode='same') self.PLL.adjust(pilot_actual) moddif = rebuilt * np.real(np.square(self.PLL.pll)) #np.cos(2*np.pi*38/240*(np.r_[0:ss] - phase_shift)) h = signal.firwin(128,16000,nyq=1.2e5) moddif = signal.fftconvolve(moddif,h,mode='same') h = signal.firwin(64,16000,nyq=48000/2) diff = signal.fftconvolve(moddif[::self.decim_r2],h,mode='same') diff = np.real(diff) # rdbs = rebuilt * np.power(self.PLL.pll,3) # h = signal.hanning(1024) # rdbs = signal.fftconvolve(rdbs,h) # if np.mean(rdbs) > 0: # # bit ONE # else: # # bit ZERO elif demodSub1: demod = rebuilt * np.exp(-2j*np.pi*67650/2.4e5*np.r_[0:rebuilt.size]) h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.real(np.angle( A * np.conj(B) )) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') elif demodSub2: demod = rebuilt * np.exp(-2j*np.pi*92000/2.4e5*np.r_[0:rebuilt.size]) h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.real(np.angle( A * np.conj(B) )) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') # DC block filter, lol, srsly output = np.real(output) - np.mean(np.real(output)) if np.isnan(output[0]): #print "error" # for some reason, output is NaN for the first 2 loops return np.zeros(6554) # deemphasis - # 2122/samplerate*2 *pi - butterworth filter b,a = signal.butter(1, 2122/48000*2*np.pi, btype='low') output, zf = signal.lfilter(b, a, output,zi=self.demph_zf) self.demph_zf = zf stereo = np.zeros(output.size*2) if (isStereo): diff = signal.lfilter(b,a,diff) w = self.stereoWidth # adjust to change stereo wideness left = output + w/10 * diff right = output - w/10 * diff if(self.useAudioFilter): left = self.lowpass(left,self.audioFilterSize) right = self.lowpass(right,self.audioFilterSize) stereo[0:stereo.size:2] = left stereo[1:stereo.size:2] = right else: if self.useAudioFilter: output = self.lowpass(output,self.audioFilterSize) # just the tip (kills the 19k pilot) stereo[0:stereo.size:2] = output stereo[1:stereo.size:2] = output #normalize to avoid any possible clipping when playing stereo /= 2*np.max(stereo) #spectrum = np.fft.fft(stereo[::2]) output = .5*(stereo[::2]+stereo[1::2]) #spectrum = np.fft.fft(.5*(stereo[::2]+stereo[1::2])*spectral_window(output.size)) self.plspectrogram = np.roll(self.plspectrogram, 24,axis=1) stft,self.prevSpec3 = self.gen_spectrogram(output,512,self.prevSpec3) self.plspectrogram[:,:24] = stft[::-1,:] # np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:20])) if(self.plotPlaying): # and self.count % 2 == 0): #if self.toDrawWaterfalls: self.cur_spectrogram = self.plspectrogram self.drawCurSpectrum(invert=True) #self.drawPlspectrum() #else: # sm = np.abs(np.fft.fftshift(spectrum[::20])) # toPlot = (np.linspace(-2.4e4,2.4e4,sm.size),sm) # self.replot(toPlot) #if(self.toDraw and self.plotWaveform): # if self.toDrawWaterfalls: # sm = np.real(output[::20]) # toPlot = (np.linspace(0,output.size/48000,sm.size),sm) # self.replot(toPlot) # else: # sm = np.real(self.PLL.pll[::200]) # toPlot = (np.linspace(0,output.size/48000,sm.size),sm) # self.replot(toPlot) return np.real(stereo) # Alternate demodulator. Not used, but extremely simple def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling h = signal.firwin(128,80000,nyq=1.2e5) lp_samples = signal.fftconvolve(samples, h) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) / np.pi dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] h = signal.firwin(128,16000,nyq=1.2e5) rebuilt = signal.fftconvolve(dphase,h) output = rebuilt[::self.decim_r2] output = self.lowpass(output, self.audioFilterSize) return np.real(output) # utility functions # def lowpass(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi #wndw = np.kaiser(width,6) wndw = signal.firwin(16,width*999,nyq=24000) #wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw, mode='same') return new_array # calculate mean average deviation # def mad(self,samples): ave = np.mean(samples) return np.mean(np.abs(samples-ave)) # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) # starting point def start(self): # Initiates running things self.streamer = MakeDaemon(self.demodulate_th) # run demodulation in the 'background' self.streamer.start() self.count = 0 self.sampler_t = threading.Thread(target=self.getSamplesAsync) # sampler loop self.sampler_t.start() def createQtConnections(self): QtCore.QObject.connect(self.ui.freqSelect, QtCore.SIGNAL(_fromUtf8("valueChanged(int)")), self.setFreq) QtCore.QObject.connect(self.ui.checkBox, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.setUseStereo) QtCore.QObject.connect(self.ui.mainchannel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodMain) QtCore.QObject.connect(self.ui.subband1, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub1) QtCore.QObject.connect(self.ui.subband2, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub2) QtCore.QObject.connect(self.ui.stereoWidthSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setStereoWidth) QtCore.QObject.connect(self.ui.spectrum_overall, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumOverall) QtCore.QObject.connect(self.ui.spectrum_channel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumChannel) QtCore.QObject.connect(self.ui.spectrum_playing, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumPlaying) QtCore.QObject.connect(self.ui.spectrum_waveform, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumWaveform) QtCore.QObject.connect(self.ui.demodFiltMedian, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltMedian) QtCore.QObject.connect(self.ui.demodFiltLP, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltLP) QtCore.QObject.connect(self.ui.demodFilterSize, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setDemodFiltSize) QtCore.QObject.connect(self.ui.audioFilterActive, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setAudioFiltUse) QtCore.QObject.connect(self.ui.audioFilterSizeSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setAudioFiltSize) QtCore.QObject.connect(self.ui.exitButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.terminate) QtCore.QObject.connect(self.ui.drawPlot, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawSpec) QtCore.QObject.connect(self.ui.waterfallButton, QtCore.SIGNAL(_fromUtf8('toggled(bool)')), self.setDrawWaterfalls) # QtCore.QObject.connect(self.ui.plotButton, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawPlot) self.bindPlot() def bindPlot(self): self.dpi = 100 self.fig = Figure((4.31,2.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.ui.plotFrame) self.initplot() def initplot(self): self.axes = self.fig.add_subplot(111, aspect=200/431) self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.fig.tight_layout() #self.axes.invert_yaxis() #self.anim = animation.FuncAnimation(self.fig,self.drawCurSpectrum,interval=750) def replot(self,toPlot): self.axes.clear() self.axes.plot(toPlot[0],toPlot[1]) self.axes.set_aspect('auto',anchor='C') self.canvas.draw() def setDrawSpec(self,s): self.toDraw = s def drawCurSpectrum(self,invert=False): #self.axes.clear() #self.axes.imshow(self.cur_spectrogram, cmap='spectral') #self.axes.xaxis.set_major_locator(ticker.NullLocator()) #self.axes.yaxis.set_major_locator(ticker.NullLocator()) #self.axes.set_aspect('auto',adjustable='box',anchor='NW') #self.canvas.draw() mx = np.max(self.cur_spectrogram) mn = np.min(self.cur_spectrogram) if invert: self.cur_spectrogram = -cv2.convertScaleAbs(self.cur_spectrogram,alpha=255 / (mx)) else: self.cur_spectrogram = cv2.convertScaleAbs(self.cur_spectrogram,alpha=255 / (mn)) self.cur_spectrogram = cv2.GaussianBlur(self.cur_spectrogram,(5,5),.6) cmapped =cv2.applyColorMap(self.cur_spectrogram,cv2.COLORMAP_JET) cv2.imshow('Spectrogram',cmapped) cv2.waitKey(1); def drawSpectrum(self): self.axes.clear() self.axes.imshow(self.spectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawChspectrum(self): self.axes.clear() self.axes.imshow(self.chspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawPlspectrum(self): self.axes.clear() self.axes.imshow(self.plspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def setDrawPlots(self,s): self.toDrawPlots = s self.toDrawWaterfalls = not s def setDrawWaterfalls(self,s): self.toDrawWaterfalls = s self.toDrawPlots = not s def setFreq(self,freq): if freq % 2 == 0: freq += 1 freq /= 10.0 text = "%.1f MHz" % freq self.ui.curFreq.setText(text) self.center_freq = freq*1e6 #+ 250e3 setf_t = threading.Thread(target=self.setF_th, args=[self.center_freq,]) setf_t.start() setf_t.join() # This function is what is used to adjust the tuner on the RTL # Currently, it causes the program to crash if used after an unspecified period of inactivity # commented lines are attempts that didn't work def setF_th(self,f): while(self.is_sampling == True): pass #self.sdr.cancel_read_async() time.sleep(.1) self.sdr.center_freq = f #self.getSamplesAsync() def setUseStereo(self,u): self.useStereo = u def setStereoWidth(self,w): self.stereoWidth = w/5 def setDemodMain(self,s): self.demodMain = s self.demodSub1 = not s self.demodSub2 = not s #self.useStereo = True def setDemodSub1(self,s): self.demodMain = not s self.demodSub1 = s self.demodSub2 = not s #self.useStereo = False def setDemodSub2(self,s): self.demodMain = not s self.demodSub1 = not s self.demodSub2 = s #self.useStereo = False def setSpectrumOverall(self,s): #self.initplot() #self.cur_spectrogram = self.spectrogram self.plotOverall = s self.plotChannel = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumChannel(self,s): #self.initplot() self.plotChannel = s self.plotOverall = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumPlaying(self,s): #self.initplot() self.plotPlaying = s self.plotChannel = not s self.plotOverall= not s self.plotWaveform = not s def setSpectrumWaveform(self,s): self.plotWaveform = s self.plotPlaying = not s self.plotChannel = not s self.plotOverall= not s def setDemodFiltMedian(self,s): self.useMedianFilt = s self.useLPFilt = not s def setDemodFiltLP(self,s): self.useLPFilt = s self.useMedianFilt = not s def setDemodFiltSize(self,s): #if(s % 2 == 0): # s+=1 self.demodFiltSize = s def setAudioFiltUse(self,s): self.useAudioFilter = s def setAudioFiltSize(self,s): self.audioFilterSize = s def terminate(self): self.__del__() # Destructor - also used to exit the program when user clicks "Quit" def __del__(self): # Program will continue running in the background unless the RTL is told to stop sampling self.sdr.cancel_read_async() print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() cv2.destroyAllWindows()
class WSHandler(tornado.websocket.WebSocketHandler): def check_origin(self, origin): return True def open(self): self.siggen = SigGen() self.sdr = RtlSdr() self.scan = Scan(self.sdr) self.rotor = Rotor() self.callback = PeriodicCallback(self.send_values, timeInterval) def send_values(self): print "::WS: Begin scanning...." scan_vals = self.scan.scan() print "::WS: Detecting Signal Peaks...." peaks = detect_peaks(scan_vals) print "::WS: Sending peak vals to WS...." self.write_message("++") self.write_message(json_encode(peaks)) def on_message(self, message): print ":: Recvd message: %s" % message if (message.startswith("==Frequency:")): str = message.split("|"); freq = str[0].split(" ")[1] rxgain = str[1].split(" ")[1] print "::WS: Setting Tx Freq:" + freq self.siggen.setTxFreq(freq) print "::WS: Setting Rx Freq:" + freq + "| RxGain: " + rxgain self.scan.setFreqGain(freq, rxgain) print "::WS: Initializing Callback function..." self.callback.start() elif (message.startswith("==TxOff")): print "::WS: Resetting Callback" self.callback.stop() print "::WS: Setting Tx Off" self.siggen.setTxOff() print "::WS: Closing SDR instance" #self.sdr.close() elif (message.startswith("==Rotor:")): # ==Rotor: R|2000 str = message.split("|"); dir = str[0].split(" ")[1] deg = str[1] self.rotor.setRotor(dir,deg) def on_close(self): print "::WS: Resetting Callback" self.callback.stop() print "::WS: Setting Tx Off" self.siggen.setTxOff() print "::WS: Closing SDR instance" self.sdr.close() self.rotor.close(); self.siggen.close();
def main(): print("you are using", platform.system(), platform.release(), os.name) # creating the central shared dgsn-node-data for all programs on the nodes ####################################### pathname = os.path.abspath(os.path.dirname(sys.argv[0])) pathname_all = "" for i in range(len(pathname.split(path_separator))-2): # creating the folders two folder levels above pathname_all = pathname_all + pathname.split(path_separator)[i] + path_separator pathname_save = pathname_all + "dgsn-node-data" pathname_config = pathname_all + "dgsn-hub-ops" # creating the dump folder for files and the needed data folders ####################################### if not os.path.exists(pathname_save): os.makedirs(pathname_save) folder = pathname_save + path_separator + "rec" subfolders = ["iq", "sdr", "gapped", "coded", "monitor"] if not os.path.exists(folder): os.makedirs(folder) if os.path.exists(folder): for i in range(len(subfolders)): if not os.path.exists(folder + path_separator + subfolders[i]): os.makedirs(folder + path_separator + subfolders[i]) if not os.path.exists(pathname_config): os.makedirs(pathname_config) pathname_config = pathname_config + path_separator + "io-radio" if not os.path.exists(pathname_config): os.makedirs(pathname_config) # setting the rtlsdr before the gain finding ##################################### # getting one file to each node very simple via github, or via a local file copy data = loading_config_file(pathname_config) # getting the specific settings for the node itself. perhaps it cannot be as fast as others with open(pathname + path_separator +'node-config.json') as data_file: data_node = json.load(data_file) device_number = data["device_number"] center_frequency = data["center_frequency"] samplerate = data["samplerate"] # this will be necessary in case a full fledged pc is a node or in case a micro pc is used with less RAM secondsofrecording = min(data["secondsofrecording"], data_node["secondsofrecording_maximum"]) print("record seconds commanded", data["secondsofrecording"], "record seconds maximum", data_node["secondsofrecording_maximum"], "and it is", secondsofrecording) nsamples = secondsofrecording * samplerate freq_correction = data["freq_correction"] user_hash = get_groundstationid() dt = datetime.datetime(data["recording_start"]["year"], data["recording_start"]["month"], data["recording_start"]["day"], data["recording_start"]["hour"], data["recording_start"]["minute"], data["recording_start"]["second"]) recording_start = time.mktime(dt.timetuple()) dt = datetime.datetime(data["recording_end"]["year"], data["recording_end"]["month"], data["recording_end"]["day"], data["recording_end"]["hour"], data["recording_end"]["minute"], data["recording_end"]["second"]) recording_stop = time.mktime(dt.timetuple()) # getting the data for calibration calibration_start = data["calibration_start"] gain_start = data["gain_start"] gain_end = data["gain_end"] gain_step = data["gain_step"] signal_threshold = data["signal_threshold"] print("gg", gain_start, gain_end) ################################## print("starting the fun...") if platform.system() == "Windows": print("detecting a windows") ############## device_count = librtlsdr.rtlsdr_get_device_count() print("number of rtl-sdr devices:", device_count) if device_count > 0: lock = Lock() jobs = [] gain = 0 calibration_finished = 0 # 1 means calibration is done while time.mktime(time.gmtime()) <= recording_start or calibration_finished == 0: # waiting for the time to be right :) time.sleep(10) print("still to wait", recording_start - time.mktime(time.gmtime()), "to record and", recording_start - time.mktime(time.gmtime())- calibration_start, "to calibration") if time.mktime(time.gmtime()) > recording_start - calibration_start and calibration_finished == 0: sdr = RtlSdr(device_index=device_number) sdr.center_freq = center_frequency sdr.sample_rate = samplerate # sdr.freq_correction = 1 # PPM # calibrating the dongle if gain_start >= gain_end or gain_start >= 49.0: print("fixed gain") if gain_start==0 or gain_start > 49.0: print("autogain") gain = 'auto' else: gain = gain_start else: print("calibrated gain") gain = calibrating_gain_with_windows(sdr, samplerate, gain_step, gain_start, gain_end, signal_threshold) print("used gain", gain) sdr.gain = gain sdr.close() calibration_finished = 1 utctime = time.mktime(time.gmtime()) if utctime >= recording_start and utctime <= recording_stop: print("recording starts now...") for recs in range(2): p = Process(target=storing_stream_with_windows, args=(lock, device_number, folder, subfolders, center_frequency, samplerate, gain, nsamples, freq_correction, user_hash)) jobs.append(p) p.start() print("end") while time.mktime(time.gmtime()) <= recording_stop: time.sleep(2) for n, p in enumerate(jobs): if not p.is_alive() and time.mktime(time.gmtime()) <= recording_stop: jobs.pop(n) recs += 1 p = Process(target=storing_stream_with_windows, args=(lock, device_number, folder, subfolders, center_frequency, samplerate, gain, nsamples, freq_correction, user_hash)) jobs.append(p) p.start() print("rec number", recs, 'added') for job in jobs: job.join() elif platform.system() == "Linux" or platform.system() == "Linux2": print("detecting a linux") # getNumber_of_rtlsdrs_with_linux() gain = 0 calibration_finished = 0 while time.mktime(time.gmtime()) <= recording_start or calibration_finished == 0: # waiting for the time to be right :) time.sleep(10) print("still to wait", recording_start - time.mktime(time.gmtime()), "to record and", recording_start - time.mktime(time.gmtime())- calibration_start, "to calibration") if time.mktime(time.gmtime()) > recording_start - calibration_start and calibration_finished == 0: if gain_start >= gain_end or gain_start >= 49.0: print("fixed gain") if gain_start==0 or gain_start > 49.0: print("autogain") gain = 0 else: gain = gain_start else: print("calibrated gain") gain = calibrating_gain_with_linux(device_number, center_frequency, samplerate, gain_step, gain_start, gain_end, signal_threshold) print("used gain", gain) calibration_finished = 1 utctime = time.mktime(time.gmtime()) if utctime >= recording_start and utctime <= recording_stop: print("recording starts now...") rtl_sdr_exe = "rtl_sdr" sdr = Popen([rtl_sdr_exe, "-d", str(device_number), "-f", str(center_frequency), "-s", str(samplerate), "-g", str(gain), "-p", str(freq_correction), "-"], stdout=PIPE, stderr=None) while time.mktime(time.gmtime()) <= recording_stop: stream_data = sdr.stdout.read(nsamples*2) storing_stream_with_linux(stream_data, device_number, folder, subfolders, center_frequency, samplerate, gain, nsamples, freq_correction, user_hash) sdr.kill() print("it's done. thank you, please come back again!")
class FMRadio(QtGui.QMainWindow,Ui_MainWindow): sample_buffer = Queue.Queue(maxsize=10) base_spectrum = np.ones(5780) plotOverall = True plotChannel = False plotPlaying = False plotWaveform = False useStereo = False stereoWidth = 10 useMedianFilt = True useLPFilt = False demodFiltSize = 11 useAudioFilter = True audioFilterSize = 16 toDraw = True demodMain = True demodSub1 = False demodSub2 = False toDrawWaterfalls = True toDrawPlots = False prevCutoff = 0 toPlot = (np.cumsum(np.ones(5780)),np.cumsum(np.ones(5780))) def __init__(self,freq,N_samples): QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.createQtConnections() self.sample_rate = 2.4e5 ###1e6 #self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2.4e5/48000 # for baseband recovery self.center_freq = freq #+250e3 self.gain = 38 self.N_samples = N_samples self.is_sampling = False self.spectrogram = np.zeros((328,200)) self.chspectrogram = np.zeros((328,200)) self.plspectrogram = np.zeros((164,200)) self.sdr = RtlSdr() #self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 2, rate = 48000, output = True) adj = 0 hamming = np.kaiser(self.N_samples/4 + adj,1) lpf = np.append( np.zeros(self.N_samples*3/8),hamming) self.lpf = np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*3/8))) #,int(-.25*self.N_samples)) hamming = 10*signal.hamming(self.N_samples/16) lpf = np.append(np.zeros(self.N_samples*15/32),hamming) self.lpf_s1 = (np.append(lpf,np.zeros(int(self.N_samples*15/32)))) #self.lpf_s1 = np.roll(temp,int(.5*self.N_samples*67/120)) #self.lpf_s1 += np.roll(temp,int(-.5*self.N_samples*67/120)) self.lpf_s1 = np.fft.fftshift(self.lpf_s1) #self.lpf_s1 += np.fft.fftshift(self.lpf_s1) # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(range(self.lpf_s1.size),self.lpf_s1) # fig.show() hamming = 10*signal.hamming(self.N_samples/32) lpf = np.append(np.zeros(self.N_samples*31/64),hamming) self.lpf_s2 = (np.append(lpf,np.zeros(int(self.N_samples*31/64)))) #self.lpf_s2 = np.roll(temp,int(.5*self.N_samples*92/120)) #self.lpf_s2 += np.roll(temp,int(-.5*self.N_samples*92/120)) self.lpf_s2 = np.fft.fftshift(self.lpf_s2) def createQtConnections(self): QtCore.QObject.connect(self.ui.freqSelect, QtCore.SIGNAL(_fromUtf8("valueChanged(int)")), self.setFreq) QtCore.QObject.connect(self.ui.checkBox, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.setUseStereo) QtCore.QObject.connect(self.ui.mainchannel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodMain) QtCore.QObject.connect(self.ui.subband1, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub1) QtCore.QObject.connect(self.ui.subband2, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub2) QtCore.QObject.connect(self.ui.stereoWidthSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setStereoWidth) QtCore.QObject.connect(self.ui.spectrum_overall, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumOverall) QtCore.QObject.connect(self.ui.spectrum_channel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumChannel) QtCore.QObject.connect(self.ui.spectrum_playing, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumPlaying) QtCore.QObject.connect(self.ui.spectrum_waveform, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumWaveform) QtCore.QObject.connect(self.ui.demodFiltMedian, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltMedian) QtCore.QObject.connect(self.ui.demodFiltLP, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltLP) QtCore.QObject.connect(self.ui.demodFilterSize, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setDemodFiltSize) QtCore.QObject.connect(self.ui.audioFilterActive, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setAudioFiltUse) QtCore.QObject.connect(self.ui.audioFilterSizeSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setAudioFiltSize) QtCore.QObject.connect(self.ui.exitButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.terminate) QtCore.QObject.connect(self.ui.drawPlot, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawSpec) QtCore.QObject.connect(self.ui.waterfallButton, QtCore.SIGNAL(_fromUtf8('toggled(bool)')), self.setDrawWaterfalls) # QtCore.QObject.connect(self.ui.plotButton, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawPlot) self.bindPlot() def bindPlot(self): self.dpi = 100 self.fig = Figure((4.31,2.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.ui.plotFrame) self.initplot() #self.anim = animation.FuncAnimation(self.fig,self.replot,interval=2000,blit=False) #self.canvas.mpl_connect('click_event',self.on_click_plot) # self.curve = QwtPlotCurve("Frequencies") # self.curve.setData(self.toPlot[0],self.toPlot[1]) #np.r_[-5e5:5e5:1e6/self.toPlot.size],np.abs(self.toPlot)) # self.curve.attach(self.ui.spectrumPlot) # self.ui.spectrumPlot.replot() # #threading.Timer(1,self.replot).start() def initplot(self): self.axes = self.fig.add_subplot(111, aspect=200/431) self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) #self.axes.invert_yaxis() def replot(self): self.axes.clear() #self.axes.set_s self.axes.plot(self.toPlot[0],self.toPlot[1]) self.axes.set_aspect('auto',anchor='C') self.canvas.draw() def setDrawSpec(self,s): self.toDraw = s def drawSpectrum(self): self.axes.clear() self.axes.imshow(self.spectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawChspectrum(self): self.axes.clear() self.axes.imshow(self.chspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawPlspectrum(self): self.axes.clear() self.axes.imshow(self.plspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def setDrawPlots(self,s): self.toDrawPlots = s self.toDrawWaterfalls = not s def setDrawWaterfalls(self,s): self.toDrawWaterfalls = s self.toDrawPlots = not s def setFreq(self,freq): freq /= 10.0 text = "%.1f MHz" % freq self.ui.curFreq.setText(text) self.center_freq = freq*1e6 #+ 250e3 setf_t = threading.Thread(target=self.setF_th, args=[self.center_freq,]) setf_t.start() setf_t.join() def setF_th(self,f): while(self.is_sampling == True): pass self.sdr.center_freq = f def setUseStereo(self,u): self.useStereo = u def setStereoWidth(self,w): self.stereoWidth = np.sqrt(10*w) def setDemodMain(self,s): self.demodMain = s self.demodSub1 = not s self.demodSub2 = not s #self.useStereo = True def setDemodSub1(self,s): self.demodMain = not s self.demodSub1 = s self.demodSub2 = not s #self.useStereo = False def setDemodSub2(self,s): self.demodMain = not s self.demodSub1 = not s self.demodSub2 = s #self.useStereo = False def setSpectrumOverall(self,s): #self.initplot() self.plotOverall = s self.plotChannel = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumChannel(self,s): #self.initplot() self.plotChannel = s self.plotOverall = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumPlaying(self,s): #self.initplot() self.plotPlaying = s self.plotChannel = not s self.plotOverall= not s self.plotWaveform = not s def setSpectrumWaveform(self,s): self.plotWaveform = s self.plotPlaying = not s self.plotChannel = not s self.plotOverall= not s def setDemodFiltMedian(self,s): self.useMedianFilt = s self.useLPFilt = not s def setDemodFiltLP(self,s): self.useLPFilt = s self.useMedianFilt = not s def setDemodFiltSize(self,s): if(s % 2 == 0): s+=1 self.demodFiltSize = s def setAudioFiltUse(self,s): self.useAudioFilter = s def setAudioFiltSize(self,s): self.audioFilterSize = s def terminate(self): self.__del__() def __del__(self): #QtGui.QMainWindow.__del__() #Ui_MainWindow.__del__() #self.streamer.stop() #self.sampler_t.stop() print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() sys.exit() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a 2048/44100 amount's time return self.sdr.read_samples(self.N_samples) def getSamplesAsync(self): #Asynchronous call. Meant to be put in a loop w/ a calback fn #print 'gonna sample' self.is_sampling = True samples = self.sdr.read_samples_async(self.sampleCallback,self.N_samples,context=self) def sampleCallback(self,samples,sself): self.is_sampling = False self.sample_buffer.put(samples) #print 'put some samples in the jar' # recursive loop #sself.getSamplesAsync() def demodulate_th(self): while(1): try: samples = self.sample_buffer.get() #samples2 = self.sample_buffer.get() # print 'gottum' except: print "wtf idk no samples?" break out1 = self.demodulate(samples) self.sample_buffer.task_done() #out2 = self.demodulate(samples2) #self.sample_buffer.task_done() audio_out = out1 #np.append(out1,out2) self.play(audio_out) print 'gonna try to finish off the to-do list' sample_buffer.join() def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fftshift(np.fft.fft(samples)) self.spectrogram = np.roll(self.spectrogram, 1,axis=1) self.spectrogram[:,0] = np.log(np.abs(spectrum[::100])) if(self.toDraw and self.plotOverall and self.count % 10 == 9): # self.toPlot = (np.linspace(-5e5,5e5,spectrum.size),np.abs(spectrum)) # self.replot() self.drawSpectrum() self.count += 1 #fig = plt.figure() #plt.plot(np.abs(spectrum)) #plt.show() # # spectrum *= self.lpf # # Decimate in two rounds. One to 200k, another to 44.1k # # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. # n_s = spectrum.size # # channel_spectrum = spectrum #.25*spectrum[int(n_s*.75-.5*n_s/self.decim_r1):int(.75*n_s+.5*n_s/self.decim_r1)] #np.append(spectrum[0:int(n_s/self.decim_r1*.5)],spectrum[n_s-int(n_s/self.decim_r1*.5):n_s]) # # #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias # #print channel_spectrum.size # # fig = plt.figure() # # plt.plot(np.abs(np.fft.ifftshift(channel_spectrum))) # # plt.show() # #self.fig.plot(np.fft.ifftshift(channel_spectrum)) # # # lp_samples = np.fft.ifft(np.fft.ifftshift(channel_spectrum)) # lp_samples = samples # lp_samples /= power # polar discriminator dphase = np.zeros(lp_samples.size, dtype='complex') A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase[1:] = ( A * np.conj(B) ) dphase[0] = lp_samples[0] * np.conj(self.prevCutoff) #dphase[dphase.size-2] self.prevCutoff = lp_samples[lp_samples.size-1] # if self.useMedianFilt: # rebuilt = signal.medfilt(np.angle(dphase)/np.pi,self.demodFiltSize) # np.cos(dphase) # else: # rebuilt = self.lowpass(np.angle(dphase),self.demodFiltSize) rebuilt = np.angle(dphase) / np.pi # toplot = False # if toplot: # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(rebuilt) power = np.abs(self.mad(lp_samples)) self.ui.signalMeter.setValue(20*(np.log10(power))) demodMain = False demodSub1 = False demodSub2 = False if self.demodMain: demodMain = True # lp_samples = samples elif self.demodSub1: demodSub1 = True #lp_samples = samples * np.exp(-1j*2*np.pi*67650/2.4e5*np.r_[0:samples.size]) elif self.demodSub2: demodSub2 = True #lp_samples = samples * np.exp(-1j*2*np.pi*92000/2.4e5*np.r_[0:samples.size]) spectrum = np.fft.fft(rebuilt) #toplot = self.plotChannel self.chspectrogram = np.roll(self.chspectrogram, 1,axis=1) self.chspectrogram[:,0] = np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:50])) if(self.toDraw and self.plotChannel and self.count % 10 == 9): self.drawChspectrum() #plotspectrum = np.abs(channel_spectrum[::100]) #self.toPlot = (np.linspace(-np.pi,np.pi,plotspectrum.size),plotspectrum) #self.replot() isStereo = False #demodSub1 = False #demodSub2 = False n_z = rebuilt.size if demodMain: #stereo_spectrum = spectrum if self.useStereo: isStereo = True #modulated = rebuilt * np.exp(-2j*np.pi*38000/2.4e5*np.r_[0:rebuilt.size]) #h = signal.firwin(128,22000,nyq=1.2e5) #lp_mod = signal.fftconvolve(modulated,h,mode='same') #decim = lp_mod[::self.decim_r2] #dphase = np.zeros(decim.size, dtype='complex') # # A = decim[1:decim.size] # B = decim[0:decim.size-1] # # dphase[1:] = np.angle( A * np.conj(B) ) #h = signal.firwin(128,22000,nyq=24000) #diff = dphase# [::self.decim_r2] mod_spectrum = np.roll(spectrum,int(.5*n_z*38000/120000)) mod_spectrum += np.roll(spectrum,int(-.5*n_z*38000/120000)) #np.fft.fft(modulated) mod_spectrum *= self.lpf #np.fft.ifftshift(np.hamming(stereo_spectrum.size)) stereo_spectrum = np.append(mod_spectrum[0:np.ceil(n_z/self.decim_r2*.5)],mod_spectrum[n_z-np.ceil(n_z/self.decim_r2*.5):n_z]) diff = np.fft.ifft(stereo_spectrum) #self.base_spectrum = np.append(spectrum[0:int(n_z/self.decim_r2*.5)],spectrum[n_z-int(n_z/self.decim_r2*.5):n_z]) #output = np.fft.ifft(self.base_spectrum) h = signal.firwin(128,16000,nyq=1.2e5) output = signal.fftconvolve(rebuilt,h,mode='same') output = rebuilt[::self.decim_r2] # h = signal.firwin(128,16000,nyq=2.4e4) # output = signal.fftconvolve(output,h,mode='same') elif demodSub1: demod = rebuilt * np.exp(-2j*np.pi*67650/2.4e5*np.r_[0:rebuilt.size]) # spectrum = np.fft.fft(demod)*self.lpf_s1 h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] # base_spectrum = np.append(spectrum[0:int(.5*n_z*7500/2.4e5)],spectrum[n_z-int(.5*n_z*7500/2.4e5):n_z]) # decim = np.fft.ifft(base_spectrum) dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.angle( A * np.conj(B) ) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') #retoutput) elif demodSub2: demod = rebuilt * np.exp(-2j*np.pi*92000/2.4e5*np.r_[0:rebuilt.size]) # spectrum = np.fft.fft(demod)*self.lpf_s2 h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] # base_spectrum = np.append(spectrum[0:int(.5*n_z*7500/2.4e5)],spectrum[n_z-int(.5*n_z*7500/2.4e5):n_z]) # decim = np.fft.ifft(base_spectrum) dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.angle( A * np.conj(B) ) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') #return np.real(output) output -= np.mean(output) stereo = np.zeros(output.size*2, dtype='complex') if (isStereo): #diff = np.fft.ifft(stereo_spectrum) w = self.stereoWidth # adjust to change stereo wideness #print w left = output + w/10 * diff right = output - w/10 * diff if(self.useAudioFilter): left = self.lowpass(left,self.audioFilterSize) right = self.lowpass(right,self.audioFilterSize) stereo[0:stereo.size:2] = left stereo[1:stereo.size:2] = right else: if self.useAudioFilter: output = self.lowpass(output,self.audioFilterSize) # just the tip (kills the 19k pilot) stereo[0:stereo.size:2] = output stereo[1:stereo.size:2] = output spectrum = np.fft.fft(stereo[::2]) self.plspectrogram = np.roll(self.plspectrogram, 1,axis=1) self.plspectrogram[:,0] = np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:20])) if(self.toDraw and self.plotPlaying): # and self.count % 2 == 0): if self.toDrawWaterfalls: self.drawPlspectrum() else: sm = np.abs(np.fft.fftshift(spectrum[::20])) self.toPlot = (np.linspace(-2.4e4,2.4e4,sm.size),sm) self.replot() if(self.toDraw and self.plotWaveform): sm = np.real(stereo[::20]) self.toPlot = (np.linspace(0,output.size/48000,sm.size),sm) self.replot() return np.real(stereo) # def updateimg(self,base_spectrum): # spectralimg = np.zeros((base_spectrum.size/20,base_spectrum.size/10)) # for i in np.r_[0:base_spectrum.size/10]: # spectralimg[np.abs(np.fft.fftshift(base_spectrum)[i*10]/10),i] = 1 # cv2.imshow('spectrum',spectralimg) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(.5*output) # utility functions # def lowpass(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi #wndw = np.kaiser(width,6) wndw = signal.firwin(16,width*990,nyq=24000) #wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw, mode='same') return new_array # calculate mean average deviation # def mad(self,samples): ave = np.mean(samples) return np.mean(np.abs(samples-ave)) # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): self.streamer = MakeDaemon(self.demodulate_th) # run demodulation in the 'background' self.streamer.start() self.count = 0 self.sampler_t = threading.Thread(target=self.getSamplesAsync) # sampler loop self.sampler_t.start()
class Sampler(QtCore.QObject): samplerError = QtCore.pyqtSignal(object) dataAcquired = QtCore.pyqtSignal(object) def __init__(self, gain, sampRate, freqs, numSamples, parent=None): super(Sampler, self).__init__(parent) self.gain = gain self.sampRate = sampRate self.freqs = freqs self.numSamples = numSamples self.offset = 0 self.sdr = None self.errorMsg = None self.WORKING = True self.BREAK = False self.MEASURE = False try: self.sdr = RtlSdr() self.sdr.set_manual_gain_enabled(1) self.sdr.gain = self.gain self.sdr.sample_rate = self.sampRate except IOError: self.WORKING = False print "Failed to initiate device. Please reconnect." self.errorMsg = "Failed to initiate device. Please reconnect." self.samplerError.emit(self.errorMsg) def sampling(self): print 'Starting sampler...' while self.WORKING: prev = 0 counter = 0 gain = self.gain numSamples = self.numSamples self.BREAK = False self.sdr.gain = gain start = time.time() #print self.sdr.get_gain() for i in range(len(self.freqs)): if self.BREAK: break else: centerFreq = self.freqs[i] #print "frequency: " + str(center_freq/1e6) + "MHz" if centerFreq != prev: try: self.sdr.set_center_freq(centerFreq) except: self.WORKING = False print "Device failure while setting center frequency" self.errorMsg = "Device failure while setting center frequency" self.samplerError.emit(self.errorMsg) break prev = centerFreq else: pass #time.sleep(0.01) try: x = self.sdr.read_samples(2048) data = self.sdr.read_samples(numSamples) except: self.WORKING = False print "Device failure while getting samples" self.errorMsg = "Device failure while getting samples" self.samplerError.emit(self.errorMsg) break if self.MEASURE: self.offset = np.mean(data) counter += 1 self.dataAcquired.emit([i, centerFreq, data]) if self.errorMsg is not None: self.samplerError.emit(self.errorMsg) if self.sdr is not None: self.sdr.close()
from rtlsdr import RtlSdr import numpy as np from pylab import psd sdr = RtlSdr() sdr.sample_rate = 2.4e6 sdr.center_freq = 105e6 sdr.gain = 4 passes = 1000 fftbins = 1024 samples = sdr.read_samples(passes * fftbins) sdr.close() print(samples[0]) spectra = psd(samples, NFFT=fftbins, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) print(spectra[0]) print(spectra[1])
class FMRadio: # multiple of 256 def __init__(self,freq,N_samples): self.sample_rate = 1e6 self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2e5/44100 # for baseband recovery self.center_freq = freq self.gain = 36 self.N_samples = N_samples self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 1, rate = 44100, output = True) hamming = 10*signal.hamming(self.N_samples*.10 ) lpf = np.append( np.zeros(self.N_samples*.45),hamming) self.lpf = np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*.45))) def __del__(self): print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a blocksize amount's time return self.sdr.read_samples(self.N_samples) # def demodulate_threaded(self,samples): # async_demodulation = self.pool.apply_async(self.demodulate, samples, callback=self.play) def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fft(samples) * (self.lpf) # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.abs(spectrum)) # plt.show() # Decimate in two rounds. One to 200k, another to 44.1k # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. n_s = spectrum.size channel_spectrum = np.append(spectrum[0:n_s/self.decim_r1*.5],spectrum[n_s-n_s/self.decim_r1*.5:n_s]) #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.abs(channel_spectrum)) # plt.show() lp_samples = np.fft.ifft(channel_spectrum) #lp_samples = self.lowpass_filter(lp_samples,4) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) #dpm = np.mean(np.abs(dphase)) # normalize # dphase /= dpm dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) #phase = np.sin(rebuilt) #phase = self.lowpass_filter(phase,8) #rebuilt= self.lowpass_filter(rebuilt,8) # toplot = False # if toplot: # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(rebuilt) # ax.plot(phase) # plt.show() spectrum = np.fft.fft(rebuilt) #* self.lpf2 n_s = spectrum.size base_spectrum = np.append(spectrum[0:n_s/self.decim_r2*.5],spectrum[n_s-n_s/self.decim_r2*.5:n_s]) output = np.fft.ifft(base_spectrum) #check: should be 1807 or very close to it. it is!! # output = self.lowpass_filter(np.real(output),16) #[12:8204] # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.real(output)) # plt.show() return np.real(output) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(output) def lowpass_filter(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi wndw = np.kaiser(width,6) wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw) return new_array[int(width/2):x.size+int(width/2)] def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): while True: self.play(self.demodulate(self.getSamples()))