wiki:Other/Summer/2020/FPGAspectrum

Using FPGAs for Spectrum Sensing and Modulation Recognition

Project Objective

This project seeks to aid the use of 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. Additionally, we will be constructing a matched filter to compare its performance against the machine learning based modulation recognition.

Who We Are


Ryan Davis
Class of 2021
Rutgers University
Computer Engineering and
Computer Science

Zhuohuan Li
Class of 2020
Rutgers University
Computer Engineering

Sid Mandayam
Class of 2022
Rutgers University
Computer Science and
Mathematics

Jacob Morin
Class of 2021
Pingry High School

Reading Material

Week 1 Activities

  • Get ORBIT/COSMOS account and familiarize oneself with the testbed procedures
  • Learn about FPGAs
  • Presentation 1

Week 2 Activities

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
  • Presentation 3

Week 4 Activities

Week 5 Activities

  • Begin looking in to matched filters
  • Finish data collection on the Grid (a lot of debugging)
  • Presentation 5

Week 6 Activities

Week 7 Activities

Final Presentation

Poster

WiFi Packet Generation


% 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


# 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
}

Random Number Generation with LFSR

// Jacob Morin

// Call with either 1 or 3 command arguments:
// First command argument: amount of loops
// Second command argument: start
// Third command argument: end
package mainimport (
    "fmt"
    "os"
    "strconv"
)func lfsr3(sequence chan uint8, start int, end int, repititions int) {
    for i := 0; i <= repititions; i++ {
        //starting value
        var seed uint16 = uint16(i)
        //keeps track of the value at any given time
        var lfsr uint16 = seed        //number of times it takes for the lfsr to revert to its start state
        var period int = 0
        //last bit of lfsr
        var value uint16 = 0
        //number of 0's in lfsr
        var numZeros int = 0
        //number of 1's in lfsr
        var numOnes int = 0        stop := false
        //until LFSR goes back to its start state (stop will become true)
        for stop != true {
            //increments count
            period++            //shifts
            lfsr ^= lfsr >> 7  //7 right
            lfsr ^= lfsr << 9  //9 left
            lfsr ^= lfsr >> 13 //13 right            if (period > start) && (period < end) {
                //adds last bit to sequence
                value = lfsr & 1
                if value == 0 {
                    numZeros++
                    sequence <- 0
                }
                if value == 1 {
                    numOnes++
                    sequence <- 1
                }
            }            //if LFSR reaches startState, make stop true to exit the loop
            if lfsr == seed {
                stop = true
            }
        }    }}func main() {    //makes channel for the random number
    sequence := make(chan uint8)    //command line
    args := os.Args
    len := len(args)    //first argument in command line determines how many times to loop
    if len > 1 {
        repititions, err := strconv.Atoi(args[1])
        if err != nil {
            fmt.Println("error")
        }
        // assumed values
        start := 6000
        end := 7000        // second argument in command line overrides start
        // third argument in command line overrides end
        if len > 3 {
            y, err := strconv.Atoi(args[2])
            if err != nil {
                fmt.Println("error")
            }
            start = y            z, err := strconv.Atoi(args[3])
            if err != nil {
                fmt.Println("error")
            }
            end = z
        }
        //calls function
        go lfsr3(sequence, start, end, repititions)        printSequence := ""
        //Call lfsr3 'repitions' number of times
        for i := 1; i <= repititions; i++ {
            //number of values per sequences
            for j := 0; j < 999; j++ {
                //receives and prints value
                value := <-sequence
                printSequence += strconv.Itoa(int(value))
            }            fmt.Println("At", i, "got random number:", printSequence, "\n")
            printSequence = ""
        }
    }}

Matched Filter

% Zhuohuan Li
% Sid Mandayam

antenna = phased.IsotropicAntennaElement('FrequencyRange',[5e9 15e9]);
transmitter = phased.Transmitter('Gain',20,'InUseOutputPort',true);
fc = 10e9;
target = phased.RadarTarget('Model','Nonfluctuating',...
   'MeanRCS',1,'OperatingFrequency',fc);
txloc = [0;0;0];
tgtloc = [5000;5000;10];
transmitterplatform = phased.Platform('InitialPosition',txloc);
targetplatform = phased.Platform('InitialPosition',tgtloc);
[tgtrng,tgtang] = rangeangle(targetplatform.InitialPosition,...
   transmitterplatform.InitialPosition);waveform = phased.RectangularWaveform('PulseWidth',25e-6,...
   'OutputFormat','Pulses','PRF',10e3,'NumPulses',1);
c = physconst('LightSpeed');
maxrange = c/(2*waveform.PRF);
SNR = npwgnthresh(1e-6,1,'noncoherent');
Pt = radareqpow(c/fc,maxrange,SNR,...
   waveform.PulseWidth,'RCS',target.MeanRCS,'Gain',transmitter.Gain);transmitter.PeakPower = Pt;radiator = phased.Radiator('PropagationSpeed',c,...
   'OperatingFrequency',fc,'Sensor',antenna);
channel = phased.FreeSpace('PropagationSpeed',c,...
   'OperatingFrequency',fc,'TwoWayPropagation',false);
collector = phased.Collector('PropagationSpeed',c,...
   'OperatingFrequency',fc,'Sensor',antenna);
receiver = phased.ReceiverPreamp('NoiseFigure',0,...
   'EnableInputPort',true,'SeedSource','Property','Seed',2e3);
filter = phased.MatchedFilter(...
   'Coefficients',getMatchedFilter(waveform),...
   'GainOutputPort',true);wf = waveform();
[wf,txstatus] = transmitter(wf);
wf = radiator(wf,tgtang);
wf = channel(wf,txloc,tgtloc,[0;0;0],[0;0;0]);
wf = target(wf);
wf = channel(wf,tgtloc,txloc,[0;0;0],[0;0;0]);
wf = collector(wf,tgtang);
rx_puls = receiver(wf,~txstatus);
[mf_puls,mfgain] = filter(rx_puls);
Gd = length(filter.Coefficients)-1;mf_puls=[mf_puls(Gd+1:end); mf_puls(1:Gd)]; % main line of matched filter
subplot(2,1,1)
t = unigrid(0,1e-6,1e-4,'[)');
rangegates = c.*t;
rangegates = rangegates/2; % end with this lineplot(rangegates,abs(rx_puls))
title('Received Pulse')
xlabel('Meters')
ylabel('Amplitude')
hold on
plot([tgtrng, tgtrng], [0 max(abs(rx_puls))],'r')
subplot(2,1,2)
plot(rangegates,abs(mf_puls))
title('After Matched Filter')
xlabel('Meters')
ylabel('Amplitude')
hold on
plot([tgtrng, tgtrng], [0 max(abs(mf_puls))],'r')
hold off
Last modified 4 years ago Last modified on Jul 30, 2020, 4:32:05 AM

Attachments (15)

Note: See TracWiki for help on using the wiki.