Протестируйте глубокую нейронную сеть с захваченными данными, чтобы обнаружить олицетворение маршрутизатора WLAN

Этот пример показывает, как обучить радиочастотную (RF) дактилоскопическую сверточную нейронную сеть (CNN) с захваченными данными. Вы захватываете системы координат беспроводной локальной сети (WLAN) от реальных маршрутизаторов с помощью программно определяемого радио (SDR). Вы программируете второй SDR, чтобы передать неизвестные системы координат и захватить их. Вы обучаете CNN, используя эти записанные сигналы. Затем вы программируете программно определяемое радио (SDR) как олицетворитель маршрутизатора, который передает сигналы-маяк с адресом управления доступом к среде (MAC) одного из известных маршрутизаторов и использует CNN, чтобы идентифицировать его как олицетворитель.

Для получения дополнительной информации об олицетворении маршрутизатора и валидации проекта сети с моделируемыми данными смотрите пример разработки глубокой нейронной сети с моделируемыми данными для обнаружения олицетворения маршрутизатора WLAN.

Train с захваченными данными

Соберите набор данных 802.11a/g/n/ac OFDM без высокой пропускной способности (non-HT) системы координат от реальных маршрутизаторов WLAN. Как описано в примере «Проектирование глубокой нейронной сети с моделируемыми данными для обнаружения олицетворения маршрутизатора WLAN», только устаревшее поле длинного обучения (L-LTF), присутствующее в преамбулах, используется в качестве обучающих блоков, чтобы избежать любой зависимости данных.

В этом примере данные были собраны с использованием сценария, изображенного на следующем рисунке. Наблюдатель является стационарным радио ADALM-PLUTO. Известные данные маршрутизатора были собраны следующим образом:

  1. Установите центральную частоту наблюдателя на основе канала WLAN, используемого маршрутизаторами

  2. Получите систему координат

  3. Извлечение сигнала L-LTF

  4. Декодируйте MAC-адрес, который будет использоваться в качестве метки

  5. Сохраните сигнал L-LTF вместе с его меткой

  6. Повторите шаги 2-5, чтобы собрать numFramesPerRouter системы координат из numKnownRouters маршрутизаторы.

Неизвестные системы координат маршрутизатора моделируются с помощью мобильного радио ADALM-PLUTO в качестве передатчика. Этот радио неоднократно передает системы координат со случайным MAC-адресом. Неизвестные данные маршрутизатора были собраны следующим образом:

  1. Сгенерируйте системы координат со случайным MAC-адресом

  2. Повторно начните передачу систем координат с помощью радио ADALM-PLUTO

  3. Сбор NUMFRAMES системы координат

  4. Извлечение сигнала L-LTF

  5. Сохраните системы координат L-LTF с меткой «Неизвестно»

  6. Переместите радио в другое место

  7. Повторите шаги 3-6, чтобы собрать данные из NUMLOC местоположения

Этот объединенный набор данных известных и неизвестных маршрутизаторов используется для обучения той же модели DL, что и в примере проекта глубокой нейронной сети с моделируемыми данными для обнаружения олицетворения маршрутизатора WLAN.

Этот пример загружает обучающие данные и обученную сеть из https://www.mathworks.com/supportfiles/spc/RFFingerprinting/RFFingerprintingCapturedData.tar.gz. Если у вас нет подключения к Интернету, можно загрузить файл вручную на компьютер, подключенный к Интернету, и сохранить в той же директории, что и текущие файлы примера. По причинам конфиденциальности MAC-адреса были анонимизированы в загруженных данных. Чтобы повторить результаты этого примера, соберите свои собственные данные, как описано в Приложении: Известный и Неизвестный Набор Данных Маршрутизатора.

rfFingerprintingDownloadData('captured')
Starting download of data files from:
	https://www.mathworks.com/supportfiles/spc/RFFingerprinting/RFFingerprintingCapturedData.tar.gz
Download and extracting files done

Чтобы запустить этот пример быстро, используйте загруженную предварительно обученную сеть. Чтобы обучить сеть на вашем компьютере, выберите опцию «Обучите сеть сейчас» (т.е. установите trainNow к true). Обучение этой сети занимает около 5 минут при помощи графического процессора Nvidia (R) Titan Xp. Обучение на центральном процессоре может привести к очень длительной длительности обучения.

trainNow = false;  %#ok<*UNRCH> 

Этот пример использует данные четырех известных маршрутизаторов. Набор данных содержит 3600 системы координат на маршрутизатор, где 90% используется в качестве обучающих систем координат и 10% используется в качестве тестовых систем координат.

numKnownRouters = 4;
numFramesPerRouter = 3600;
numTrainingFramesPerRouter = numFramesPerRouter * 0.9;
numTestFramesPerRouter = numFramesPerRouter * 0.1;
frameLength = 160;

Предварительная обработка известных и неизвестных данных маршрутизатора

Разделите собранные сложные данные полосы частот на синфазные и квадратурные компоненты и измените его форму на матрицу 2 x frameLength x 1 x numFramesPerRouter * numKnownRouters. Повторите тот же процесс для неизвестных данных маршрутизатора. В следующем коде используются ранее собранные и предварительно обработанные данные. Чтобы использовать свои собственные данные, сначала соберите данные, как описано в Приложении: Известные и неизвестные Наборы данных маршрутизатора. Скопируйте новые файлы данных с именем rfFingerprintingCapturedDataUser.mat и rfFingerprintingCapturedUnknownFramesUser.mat в ту же директорию, что и в этом примере. Затем обновляйте load команды для загрузки этих файлов.

if trainNow
  % Load known router data
  load('rfFingerprintingCapturedData.mat')
  
  % Create label vectors
  yTrain = repelem(MACAddresses, numTrainingFramesPerRouter);
  yTest = repelem(MACAddresses, numTestFramesPerRouter);
  
  % Separate between I and Q
  numTrainingSamples = numTrainingFramesPerRouter*numKnownRouters*frameLength;
  xTrainingFrames = xTrainingFrames(1:numTrainingSamples,1);
  xTrainingFrames = [real(xTrainingFrames), imag(xTrainingFrames)];
  numTestSamples = numTestFramesPerRouter*numKnownRouters*frameLength;
  xTestFrames = xTestFrames(1:numTestSamples,1);
  xTestFrames = [real(xTestFrames), imag(xTestFrames)];
  
  % Reshape dataset into an 2 x frameLength x 1 x numTrainingFramesPerRouter*numKnownRouters matrix
  xTrainingFrames = permute(...
    reshape(xTrainingFrames,[frameLength,numTrainingFramesPerRouter*numKnownRouters, 2, 1]),...
    [1 3 4 2]);
  
  % Reshape dataset into an 2 x frameLength x 1 x numTestFramesPerRouter*numKnownRouters matrix
  xTestFrames = permute(...
    reshape(xTestFrames,[frameLength,numTestFramesPerRouter*numKnownRouters, 2, 1]),...
    [1 3 4 2]);
  
  % Load unknown router data
  load('rfFingerprintingCapturedUnknownFrames.mat')
  
  % Number of training units
  numUnknownFrames = size(unknownFrames, 4);
  
  % Split data into 90% training and 10% test
  numUnknownTrainingFrames = floor(numUnknownFrames*0.9);
  numUnknownTest = numUnknownFrames - numUnknownTrainingFrames;
  
  % Add ADALM-PLUTO data into training and test datasets
  xTrainingFrames(:,:,:,(1:numUnknownTrainingFrames) + numTrainingFramesPerRouter*numKnownRouters) ...
    = unknownFrames(:,:,:, 1:numUnknownTrainingFrames);
  xTestFrames(:,:,:,(1:numUnknownTest) + numTestFramesPerRouter*numKnownRouters) ...
    = unknownFrames(:,:,:, (1:numUnknownTest) + numUnknownTrainingFrames);
  
  % Shuffle data
  vr = randperm(numKnownRouters*numTrainingFramesPerRouter+numUnknownTrainingFrames);
  xTrainingFrames = xTrainingFrames(:,:,:,vr);
  
  % Add "unknown" label and shuffle
  yTrain = [yTrain, repmat("Unknown", [1, numUnknownTrainingFrames])];
  yTrain = categorical(yTrain(vr));
  
  yTest = [yTest, repmat("Unknown", [1, numUnknownTest])];
  yTest = categorical(yTest);
end

Обучите CNN

Используйте ту же архитектуру NN и опции обучения, что и в обучении с примером моделируемых данных.

poolSize = [2 1];
strideSize = [2 1];
% Create network architecture
layers = [
  imageInputLayer([frameLength 2 1], 'Normalization', 'none', 'Name', 'Input Layer')
  
  convolution2dLayer([7 1], 50, 'Padding', [1 0], 'Name', 'CNN1')
  batchNormalizationLayer('Name', 'BN1')
  leakyReluLayer('Name', 'LeakyReLu1')
  maxPooling2dLayer(poolSize, 'Stride', strideSize, 'Name', 'MaxPool1')
  
  convolution2dLayer([7 2], 50, 'Padding', [1 0], 'Name', 'CNN2')
  batchNormalizationLayer('Name', 'BN2')
  leakyReluLayer('Name', 'LeakyReLu2')
  maxPooling2dLayer(poolSize, 'Stride', strideSize, 'Name', 'MaxPool2')
  
  fullyConnectedLayer(256, 'Name', 'FC1')
  leakyReluLayer('Name', 'LeakyReLu3')
  dropoutLayer(0.5, 'Name', 'DropOut1')
  
  fullyConnectedLayer(80, 'Name', 'FC2')
  leakyReluLayer('Name', 'LeakyReLu4')
  dropoutLayer(0.5, 'Name', 'DropOut2')
  
  fullyConnectedLayer(numKnownRouters+1, 'Name', 'FC3')
  softmaxLayer('Name', 'SoftMax')
  classificationLayer('Name', 'Output')
  ];

Сконфигурируйте опции обучения, чтобы использовать оптимизатор ADAM с мини-пакетом размером 128. Используйте тестовые системы координат для валидации, так как оптимизация гиперпараметров была выполнена в [1].

По умолчанию ExecutionEnvironment установлено в 'auto', который использует графический процессор для обучения, если он доступен. В противном случае trainNetwork (Deep Learning Toolbox) использует центральный процессор для обучения. Чтобы явным образом задать окружение выполнения, установите ExecutionEnvironment одному из 'cpu', 'gpu', 'multi-gpu', или 'parallel'. Выбор 'cpu' может привести к очень длительной длительности обучения.

if trainNow
  miniBatchSize = 128;
  
  % Training options
  options = trainingOptions('adam', ...
    'MaxEpochs',30, ...
    'ValidationData',{xTestFrames, yTest}, ...
    'ValidationFrequency',floor((numTrainingFramesPerRouter*numKnownRouters + numUnknownTrainingFrames)/miniBatchSize/3), ...
    'Verbose',false, ...
    'L2Regularization', 0.0001, ...
    'InitialLearnRate', 0.0001, ...
    'MiniBatchSize', miniBatchSize, ...
    'ValidationPatience', 5, ...
    'Plots','training-progress', ...
    'Shuffle', 'every-epoch');
  
  % Train the network
  capturedDataNet = trainNetwork(xTrainingFrames, yTrain, layers, options);
else
  load('rfFingerprintingCapturedDataTrainedNN.mat','capturedDataNet','xTestFrames','yTest','MACAddresses')
end

Следующий график показывает процесс обучения сети, запускаемой на компьютере с одним графическим процессором Nvidia Titan Xp, где сеть сходилась примерно за 10 эпох до почти 100% точности. Конечная точность сети - 100%.

Сгенерируйте матрицу неточностей.

figure
yTestPred = classify(capturedDataNet,xTestFrames);
cm = confusionchart(yTest, yTestPred);
cm.Title = 'Confusion Matrix for Test Data';
cm.RowSummary = 'row-normalized';

Тест с SDR

Протестируйте эффективность обученной сети на классе «Неизвестно». Сгенерируйте системы координат с MAC-адресами известных маршрутизаторов и одного неизвестного маршрутизатора. Передайте эти системы координат с помощью радио ADALM-PLUTO и получите с помощью другого радио ADALM-PLUTO. Поскольку нарушения канала и RF, созданные между этими двумя радиостанциями, отличаются от тех, которые созданы между реальными маршрутизаторами и наблюдателем, нейронная сеть должна классифицировать все принятые сигналы как «неизвестные». Если полученный MAC-адрес является известным, то система объявляет источник олицетворителем маршрутизатора. Если полученный MAC-адрес неизвестен, то система объявляет источник неизвестным маршрутизатором. Для выполнения этого теста вам нужны две радиостанции ADALM-PLUTO для передачи и приема. Кроме того, необходимо установить пакет поддержки Communication Toolbox для ADALM-PLUTO Radio.

Генерация сигналов

Сгенерируйте сигнал передачи, состоящий из систем координат с различными MAC-адресами. Передатчик неоднократно передает эти системы координат WLAN. Приемник захватывает системы координат WLAN и определяет, является ли он олицетворителем маршрутизатора, используя принятый MAC-адрес и отпечаток RF, обнаруженный обученным NN.

chanBW='CBW20';     % Channel Bandwidth
osf = 2;            % Oversampling Factor
frameLength=160;    % Frame Length in samples
% Create Beacon frame-body configuration object
frameBodyConfig = wlanMACManagementConfig;

% Create Beacon frame configuration object
beaconFrameConfig = wlanMACFrameConfig('FrameType', 'Beacon');
beaconFrameConfig.ManagementConfig = frameBodyConfig;

% Create interpolation and decimation objects
decimator = dsp.FIRDecimator('DecimationFactor',osf);

% Save known MAC addresses
knownMACAddresses = MACAddresses;
MACAddressesToSimulate = [MACAddresses, "ABCDEFABCDEF"];

% Create WLAN waveform with the MAC addresses of known routers and an
% unknown router
txWaveform = zeros(1540,5);
for i = 1:length(MACAddressesToSimulate)
  
  % Set MAC Address
  beaconFrameConfig.Address2 = MACAddressesToSimulate(i);
  
  % Generate Beacon frame bits
  [beacon, mpduLength] = wlanMACFrame(beaconFrameConfig, 'OutputFormat', 'bits');
  
  nonHTcfg = wlanNonHTConfig(...
    'ChannelBandwidth', chanBW,...
    "MCS", 1,...
    "PSDULength", mpduLength);
  txWaveform(:,i) = [wlanWaveformGenerator(beacon, nonHTcfg); zeros(20,1)];
end

txWaveform = txWaveform(:);

% Get center frequency for channel 153 in 5 GHz band
fc = helperWLANChannelFrequency(153, 5);
fs = wlanSampleRate(nonHTcfg);

txSig  = resample(txWaveform,osf,1);

% Samples per frame in Burst Mode
spf = length(txSig)/length(MACAddressesToSimulate);

runSDRSection = false;
if helperIsPlutoSDRInstalled()  
  radios = findPlutoRadio();
  if length(radios) >= 2
    runSDRSection = true;
  else
    disp("Two ADALM-PLUTO radios are needed. Skipping SDR test.")
  end
else
    disp("Communications Toolbox Support Package for Analog Devices ADALM-PLUTO Radio not found.")
    disp("Click Add-Ons in the Home tab of the MATLAB toolstrip to install the support package.")
    disp("Skipping SDR test.")
end


if runSDRSection
  % Set up PlutoSDR transmitter
  deviceNameSDR = 'Pluto';
  txGain = 0;
  txSDR = sdrtx(deviceNameSDR);
  txSDR.RadioID = 'usb:0';
  txSDR.BasebandSampleRate = fs*osf;
  txSDR.CenterFrequency = fc;
  txSDR.Gain = txGain;
  
  % Set up PlutoSDR Receiver
  rxSDR = sdrrx(deviceNameSDR);
  rxSDR.RadioID = 'usb:1';
  rxSDR.BasebandSampleRate = txSDR.BasebandSampleRate;
  rxSDR.CenterFrequency = txSDR.CenterFrequency;
  rxSDR.GainSource ='Manual';
  rxSDR.Gain = 30;
  rxSDR.OutputDataType = 'double';
  rxSDR.EnableBurstMode=true;
  rxSDR.NumFramesInBurst = 20;
  rxSDR.SamplesPerFrame = osf*spf;
end

L-LTF для классификации

Последовательность L-LTF, присутствующая в каждой преамбуле системы координат, используется в качестве входных модулей для NN. Системный объект rfFingerprintingNonHTFrontEnd используется для обнаружения пакетов WLAN, выполнения задач синхронизации и извлечения последовательностей L-LTF и данных. В сложение MAC-адрес также декодируется. В сложение данные предварительно обрабатываются и классифицируются с использованием обученной сети.

if runSDRSection
  numLLTF = 20;       % Number of L-LTF captured for Testing
  
  rxFrontEnd = rfFingerprintingNonHTFrontEnd('ChannelBandwidth', 'CBW20');
  
  disp("The known MAC addresses are:");
  disp(knownMACAddresses)
  
  % Set PlutoSDR to transmit repeatedly
  disp('Starting transmitter')
  transmitRepeat(txSDR, txSig);
  
  % Captured Frames counter
  numCapturedFrames = 0;
  
  disp('Starting receiver')
  % Loop until numLLTF frames are collected
  while numCapturedFrames < numLLTF
    
    % Receive data using PlutoSDR
    rxSig = rxSDR();
    rxSig = decimator(rxSig);
    
    % Perform front-end processing and payload buffering
    [payloadFull, cfgNonHT, rxNonHTData, chanEst, noiseVar, LLTF] = ...
      rxFrontEnd(rxSig);
    
    if payloadFull
      
      % Recover payload bits
      recBits = wlanNonHTDataRecover(rxNonHTData, chanEst, ...
        noiseVar, cfgNonHT, 'EqualizationMethod', 'ZF');
      
      % Decode and evaluate recovered bits
      [mpduCfg, ~, success] = wlanMPDUDecode(recBits, cfgNonHT);
      
      if success == wlanMACDecodeStatus.Success
        % Update counter
        numCapturedFrames = numCapturedFrames+1;
        
        % Create real-valued input
        LLTF = [real(LLTF), imag(LLTF)];
        LLTF = permute(reshape(LLTF,frameLength ,[] , 2, 1), [1 3 4 2]);
        
        ypred = classify(capturedDataNet, LLTF);
        
        if sum(contains(knownMACAddresses, mpduCfg.Address2)) ~= 0
          if categorical(convertCharsToStrings(mpduCfg.Address2))~=ypred
            disp(strcat("MAC Address ", mpduCfg.Address2," is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED"))
          else
            disp(strcat("MAC Address ", mpduCfg.Address2," is known, fingerprint match"))
          end
        else
          disp(strcat("MAC Address ", mpduCfg.Address2," is not recognized, unknown device"));
        end
      end
    end
  end
  release(txSDR)
end
The known MAC addresses are:
    "71B63A2D0B83"    "A3F8AC0F2253"    "EF11D125044A"    "F636A97E07E7"
Starting transmitter
## Establishing connection to hardware. This process can take several seconds.
## Waveform transmission has started successfully and will repeat indefinitely. 
## Call the release method to stop the transmission.
Starting receiver
## Establishing connection to hardware. This process can take several seconds.
MAC Address A3F8AC0F2253 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address F636A97E07E7 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address A3F8AC0F2253 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address F636A97E07E7 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address 71B63A2D0B83 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address EF11D125044A is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address ABCDEFABCDEF is not recognized, unknown device
MAC Address A3F8AC0F2253 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address F636A97E07E7 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address 71B63A2D0B83 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address EF11D125044A is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address ABCDEFABCDEF is not recognized, unknown device
MAC Address A3F8AC0F2253 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address F636A97E07E7 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address 71B63A2D0B83 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address EF11D125044A is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address ABCDEFABCDEF is not recognized, unknown device
MAC Address A3F8AC0F2253 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address F636A97E07E7 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED
MAC Address 71B63A2D0B83 is known, fingerprint mismatch, ROUTER IMPERSONATOR DETECTED

Дальнейшие исследования

Захватывайте данные с собственных маршрутизаторов, как объяснено в Приложении: Known and Unknown Router Data Collection, обучайте нейронную сеть с этими данными и тестируйте эффективность сети.

Приложение: Функции помощника

Приложение: Данные известного и неизвестного маршрутизатора Наборы

Использование rfFingerprintingRouterDataCollection сбор данных с известных (т.е. доверенных) маршрутизаторов. Эта функция извлекает сигналы L-LTF, присутствующие в 802.11a/g/n/ac OFDM Non-HT маяках систем координат переданных из коммерческого оборудования 802.11. Для получения дополнительной информации см. пример IEEE ® 802.11™ WLAN - Приемник-маяк OFDM с оборудованием USRP ® (Пакет поддержки Communications Toolbox для Радио USRP). Сигналы L-LTF и соответствующие MAC-адреса маршрутизатора используются для обучения нейронной сети с отпечатками пальцев RF. Этот метод работает лучше всего, если маршрутизаторы и их антенны фиксированы и трудно перемещаться непреднамеренно. Например, в большинстве офисных окружений маршрутизаторы монтируются на потолке. Выполните следующие действия:

  1. Подключите радио ADALM-PLUTO к компьютеру для использования в качестве радио-наблюдателя.

  2. Поместите радио в центральное место, где оно может принимать сигналы от как можно большего количества маршрутизаторов. Исправьте радио так, чтобы оно не двигалось. Если возможно, разместите радио наблюдателя на потолке или высоко на стенке.

  3. Определите номер канала маршрутизаторов. Вы можете использовать приложение Wi-Fi анализатор на вашем телефоне, чтобы узнать номера каналов.

  4. Запустите набор данных, запустив "rfFingerprintingRouterDataCollection(channel)"где channel - номер канала Wi-Fi

  5. Проконтролируйте значение «max (abs (LLTF))». Если он выше 1,2 или меньше 0,01, настройте коэффициент усиления приемника с помощью входов GAIN rfFingerprintingRouterDataCollection функция.

Используйте вспомогательные функции rfFingerprintingUnknownClassDataCollectionTx и rfFingerprintingUnknownClassDataCollectionRx для сбора данных с неизвестных маршрутизаторов. Эти функции устанавливают две радиостанции ADALM-PLUTO для передачи и приема сигналов L-LTF. Принятые сигналы объединяются с известными сигналами маршрутизатора для обучения нейронной сети. Вам нужны две радиостанции ADALM-PLUTO, предпочтительно подключенные к двум отдельным ПК. Выполните следующие действия:

  1. Подключите радио ADALM-PLUTO к стационарному ПК, чтобы выступать в качестве неизвестного маршрутизатора

  2. Запустите передачи при запуске "rfFingerprintingUnknownClassDataCollectionTx"

  3. Подключите другое радио ADALM-PLUTO к мобильному ПК, чтобы выступать в качестве наблюдателя

  4. Запустите набор данных, запустив "rfFingerprintingUnknownClassDataCollectionRx". Эта функция по умолчанию собирает 200 системы координат на место. Каждое местоположение представляет другой неизвестный маршрутизатор.

  5. Когда функция инструктирует вас переехать в новое место, переместите радио наблюдателя в новое место. По умолчанию эта функция собирает данные из 10 местоположений.

  6. Если наблюдатель не получает никаких маяков или он редко получает маяки, переместите наблюдателя ближе к передатчику.

  7. Когда набор данных будет завершен, вызовите "release(sdrTransmitter)"в сеансе работы с MATLAB передающего радио.

Избранная библиография

[1] K. Sankhe, M. Belgiovine, F. Zhou, S. Riyaz, S. Ioannidis and K. Chowdhury, «ORACLE: Optimized Radio clAssification through Convolutional neural neuraL EurNetworks», iworks

Похожие темы