= Using FPGAs for Spectrum Sensing and Modulation Recognition = == Project Objective == This project seeks to use machine learning to recognize different wireless devices. The project will use software defined radios (SDR) to record various devices, such as iphones, bluetooth earbuds, and Wifi laptops. These recordings will become the training data to a set of neural networks. The second part of the project will quantify the accuracy of the neural networks in classifying various device types based on their RF signatures. == Who We Are == || [[Image(Picture1.jpg)]]\\Ryan Davis\\Class of 2021\\Rutgers University\\Computer Engineering and\\ Computer Science\\ || [[Image(Picture2.png)]]\\Zhuohuan Li\\Class of 2020\\Rutgers University\\Computer Engineering\\ || [[Image(Picture3.jpg)]]\\Sid Mandayam\\Class of 2022\\Rutgers University\\Computer Science and\\ Mathematics\\ || [[Image(Picture2.jpg)]]\\Jacob Morin\\Class of 2021\\Pingry High School\\ || == Reading Material == * [https://www.xilinx.com/support/documentation/sw_manuals/ug998-vivado-intro-fpga-design-hls.pdf Overview of FPGA architecture (especially for Xilinx devices), and comparison between FPGA and CPU] * [https://arachnoid.com/software_defined_radios/#Theory__The_Frequency_Domain Overview of I/Q Communication Theory] * [https://www.mathworks.com/help/wlan/ref/wlanwaveformgenerator.html Artificial WiFi Packet Generation] * [https://www.sciencedirect.com/topics/engineering/matched-filter Matched Filter Demodulation] == Week 1 Activities == * Get ORBIT/COSMOS account and familiarize oneself with the testbed procedures * Learn about FPGAs * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%201.pdf Presentation 1] == Week 2 Activities == * Write a UDP client / server in Go * Generate IQ samples for IEEE 802.11 WiFi packets * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%202.pdf Presentation 2] == Week 3 Activities == * Rework UDP client / server to work with Go to Verilog compiler * Transmit and receive generated WiFi packets using the USRPs on the Grid * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%203%206_17.pdf Presentation 3] == Week 4 Activities == * Automate data collection on the Grid * Learn more about Go lang * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%204%206_25.pdf Presentation 4] == Week 5 Activities == * Begin looking in to matched filters * Finish data collection on the Grid (a lot of debugging) * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%205%207_2.pdf Presentation 5] == Week 6 Activities == * Matched Filters in MATLAB * Collect data * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%206%207_9.pdf Presentation 6] == Week 7 Activities == * Dataset documentation / Big metadata file * Matched Filters in Go * [https://www.orbit-lab.org/attachment/wiki/Other/Summer/2020/FPGAspectrum/Presentation%207%207_16.pdf Presentation 7] == Final Presentation == == WiFi Packet Generation == \\ {{{#!matlab % Ryan Davis PAYLOAD = 1500; % bytes PATH = ""; for i = 0:7 filename = "WiFi_802.11n_" + i + "MCS_int16.dat"; ht = wlanHTConfig("MCS", i, "ChannelBandwidth", "CBW20"); payload = randi([0 1], [1 PAYLOAD*8]); txSig = wlanWaveformGenerator(payload,ht); output_txSig = formatOutput(txSig); fid = fopen(PATH + filename, "w"); fwrite(fid, output_txSig, "int16"); fclose(fid); end clear; function arr = formatOutput(txSig) arr = zeros(size(txSig)*2); j = 1; for i = 1:size(txSig) arr(j) = cast(real(txSig(i)), "int16"); arr(j+1) = cast(imag(txSig(i)), "int16"); j=j+2; end end }}} == Experiment Automation == \\ {{{#!ruby # Ryan Davis # Adapted from code by Ivan Seskar Experiment.name = "Artificial_WiFi" Experiment.project = "Artificial_WiFi" consoleExec("omf tell -t all -a offh") consoleExec("omf load -i usrpcal_2020-02-24.ndz -t node3-2,node3-19,node8-7,node8-14,node13-7,node13-14,node18-2,node18-19,node3-1,node3-20,node18-1,node18-20 -r 0") consoleExec("omf tell -t node3-2,node3-19,node8-7,node8-14,node13-7,node13-14,node18-2,node18-19,node3-1,node3-20,node18-1,node18-20 -a on") freqs = ["2412e6", "2437e6", "2462e6", "5180e6", "5240e6", "5745e6", "5825e6"] mcss = ["0", "1", "2", "3", "4", "5", "6", "7"] topos = {"3" => [["node18-1", "node18-2"], ["node3-1", "node3-2"], ["node18-19", "node18-20"], ["node3-19", "node3-20"]], # format: dist => [["txnode_A", "rxnode_A"], ["txnode_B", "rxnode_B"] ... ] "15" => [["node13-7", "node8-7"], ["node13-14","node8-14"]], "45" => [["node18-1", "node3-1"], ["node18-2", "node3-2"], ["node18-19", "node3-19"], ["node18-20", "node3-20"]], "72" => [["node18-20", "node3-1"], ["node18-1", "node3-20"]] } defApplication('tx', 'tx_samples_from_file') { |a| a.version(1, 0, 0) a.shortDescription = "" a.description = "" a.path = "export LC_ALL=C;/usr/local/lib/uhd/examples/tx_samples_from_file" a.defProperty('freq', "center frequency in Hz", '--freq', {:dynamic => false, :type => :string}) a.defProperty('ant', "antenna to be used", '--subdev', {:dynamic => false, :type => :string}) a.defProperty('rate', "baseband rate in Hz", '--rate', {:dynamic => false, :type => :string}) a.defProperty('gain', "receiver gain in dB", '--gain', {:dynamic => false, :type => :string}) a.defProperty('file', "reveived baseband waveform file name", '--file', {:dynamic => false, :type => :string}) a.defProperty('type', "sample types", '--type', {:dynamic => false, :type => :string}) a.defProperty('repeat', "continuously repeat", '--repeat', {:dynamic => false, :type => :string}) } defApplication('rx', 'rx_samples_to_file') { |a| a.version(1, 0, 0) a.shortDescription = "" a.description = "" a.path = "export LC_ALL=C;/usr/local/lib/uhd/examples/rx_samples_to_file" a.defProperty('freq', "center frequency in Hz", '--freq', {:dynamic => false, :type => :string}) a.defProperty('rate', "baseband rate in Hz", '--rate', {:dynamic => false, :type => :string}) a.defProperty('gain', "receiver gain in dB", '--gain', {:dynamic => false, :type => :string}) a.defProperty('nsamps', "number of samples", '--nsamps', {:dynamic => false, :type => :string}) a.defProperty('file', "reveived baseband waveform file name", '--file', {:dynamic => false, :type => :string}) a.defProperty('type', "sample types", '--type', {:dynamic => false, :type => :string}) a.defProperty('discardtime', "time at which storing samples starts", '--discardtime', {:dynamic => false, :type => :string}) } topos.each { |dist, topo| topo.each { |node_pair| freqs.each { |freq| mcss.each { |mcs| infilename = "WiFi_802.11n_"+mcs+"_int16.dat" exptag = dist+"ft_"+freq+"Hz_"+mcs+"MCS_"+node_pair[0]+","+node_pair[1] outfilename = "/root/rx_"+exptag+"_int16.dat" info("Setting up group for experiment: " + exptag) rxGroup = node_pair[1]+"@"+exptag txGroup = node_pair[0]+"@"+exptag defGroup(txGroup, node_pair[0]) { |n| n.addApplication('tx') { |app| app.setProperty('freq', freq) app.setProperty('ant', "A:0") app.setProperty('gain', "30") app.setProperty('type', "short") app.setProperty('file', infilename) app.setProperty('rate', "20e6") app.setProperty('repeat'," ") } } defGroup(rxGroup, node_pair[1]) { |n| n.addApplication('rx') { |app| app.setProperty('freq',freq) app.setProperty('gain', "30") app.setProperty('type',"short") app.setProperty('nsamps',"40000000") app.setProperty('file',outfilename) app.setProperty('rate',"40e6") } } } } } } trap("INT") { allGroups.stopApplications allGroups.exec("/usr/bin/pkill -9 -f rx_samples") allGroups.exec("/usr/bin/pkill -9 -f tx_samples") exit! } onEvent(:ALL_UP_AND_INSTALLED) { |event| # Wait for nodes to associate and give it an extra 5 sec just in case... sleep 5 # scp IQ binary file to transmitters txfiles = "txfiles/WiFi*" topos.each { |dist, topo| topo.each { |node_pair| consoleExec("ssh root@" + node_pair[0] + " rm -f /root/*.dat") consoleExec("ssh root@" + node_pair[1] + " rm -f /root/*.dat") consoleExec("scp -o StrictHostKeyChecking=no " + txfiles + " root@"+node_pair[0]+":"); consoleExec("scp -o StrictHostKeyChecking=no test.sh root@"+node_pair[0]+":"); # TODO temp for debugging } } topos.each { |dist, topo| topo.each { |node_pair| freqs.each { |freq| mcss.each { |mcs| exptag = dist+"ft_"+freq+"Hz_"+mcs+"MCS_"+node_pair[0]+","+node_pair[1] info ("\nStarting experiment: " + exptag) rxGroup = node_pair[1]+"@"+exptag txGroup = node_pair[0]+"@"+exptag group(rxGroup).startApplications # start receiver (captures for 1 sec) sleep 1 # make sure we do not start transmitting before receiving group(txGroup).startApplications # start transmitter sleep 5 # wait for applications to hopefully finish group(txGroup).stopApplications group(rxGroup).stopApplications outfilename = "/root/rx_"+exptag+"_int16.dat" consoleExec("scp -o StrictHostKeyChecking=no root@" + node_pair[1] + ":" + outfilename + " /spare/spectrum/Artificial_WiFi/") #copy recved data to archive consoleExec("ssh root@" + node_pair[1] + " rm -f " +outfilename) } } } } allGroups.stopApplications Experiment.done } }}}