Add files via upload

main
Jon Kraft 2023-07-24 09:14:00 -06:00 committed by GitHub
parent 0c588367bc
commit 2a91b071cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1332 additions and 0 deletions

View File

@ -0,0 +1,53 @@
classdef AnalogAmplitudeCalibrationFormat
properties
CourseSubarray1Data
CourseSubarray2Data
FineSubarray1Data
FineSubarray2Data
end
methods
function s = toStruct(this)
s.CourseSubarray1Data = this.CourseSubarray1Data;
s.CourseSubarray2Data = this.CourseSubarray2Data;
s.FineSubarray1Data = this.FineSubarray1Data;
s.FineSubarray2Data = this.FineSubarray2Data;
end
function [cal1,cal2] = getCourseCalValues(this)
cal1 = this.getCourseCal1();
cal2 = this.getCourseCal2();
end
function [cal1,cal2] = getFineCalValues(this)
cal1 = this.getFineCal1();
cal2 = this.getFineCal2();
end
end
methods (Access = private)
function cal1 = getCourseCal1(this)
cal1 = this.getCal(this.CourseSubarray1Data);
end
function cal1 = getFineCal1(this)
cal1 = this.getCal(this.FineSubarray1Data);
end
function cal2 = getCourseCal2(this)
cal2 = this.getCal(this.CourseSubarray2Data);
end
function cal2 = getFineCal2(this)
cal2 = this.getCal(this.FineSubarray2Data);
end
function cal = getCal(~,data)
% get amplitudes
amp = mean(max(abs(fft(data))));
scaling = min(amp) ./ amp;
cal = reshape(scaling,[1 4]);
end
end
end

View File

@ -0,0 +1,45 @@
classdef AnalogPhaseCalibrationFormat
properties
PhaseSetting
Subarray1Measurements
Subarray2Measurements
end
methods
function s = toStruct(this)
s.PhaseSetting = this.PhaseSetting;
s.Subarray1Measurements = this.Subarray1Measurements;
s.Subarray2Measurements = this.Subarray2Measurements;
end
function [cal1,cal2] = getCalValues(this)
cal1 = this.sub1Cal();
cal2 = this.sub2Cal();
end
end
methods (Access = private)
function cal1 = sub1Cal(this)
cal1 = this.subCal(this.Subarray1Measurements);
end
function cal2 = sub2Cal(this)
cal2 = this.subCal(this.Subarray2Measurements);
end
function cal = subCal(this,data)
% Get signal amplitude
datafft = abs(fft(data));
amp = max(datafft,[],1);
% Get location of min amplitude
[~,phaseIdx] = min(amp,[],2);
% Get calibration phase
calPhase = wrapTo360(this.PhaseSetting(phaseIdx)-180);
cal = [0;calPhase.'];
end
end
end

167
Matlab/AntennaInteractor.m Normal file
View File

@ -0,0 +1,167 @@
classdef AntennaInteractor < handle
properties
ArrayControl
PlutoControl
Model
Fc
SubSteer
ArraySteer
LastPhase
LastGain
AnalogWeights
DigitalWeights
end
methods
function this = AntennaInteractor(fc,calValues)
[rx,bf,model] = setupAntenna(fc);
this.ArrayControl = bf;
this.PlutoControl = rx;
this.Model = model;
this.Fc = fc;
this.SubSteer = phased.SteeringVector("SensorArray",this.Model.Subarray,'NumPhaseShifterBits',7);
this.ArraySteer = phased.SteeringVector("SensorArray",this.Model);
this.AnalogWeights = calValues.AnalogWeights;
this.DigitalWeights = calValues.DigitalWeights;
end
function updateCalibration(this,calValues)
this.updateAnalogWeights(calValues.AnalogWeights);
this.updateDigitalWeights(calValues.DigitalWeights);
end
function updateAnalogWeights(this,analogWeights)
this.AnalogWeights = analogWeights;
end
function updateDigitalWeights(this,digitalWeights)
this.DigitalWeights = digitalWeights;
end
function [patternData,rxdata] = capturePattern(this,steerangles)
patternData = zeros(1024,numel(steerangles));
for ii = 1 : numel(steerangles)
[analogweights,digitalweights] = this.getAllWeights(steerangles(ii));
rxdata = this.steerAnalog(analogweights);
patternData(:,ii) = rxdata * conj(digitalweights);
end
end
function [sumdiffampdelta,sumdiffphasedelta,sumpatterndata,diffpatternData] = captureMonopulsePattern(this,steerangles)
sumpatterndata = zeros(1024,numel(steerangles));
diffpatternData = zeros(1024,numel(steerangles));
for ii = 1 : numel(steerangles)
% capture data
[analogweights,digitalweights] = this.getAllWeights(steerangles(ii));
rxdata = this.steerAnalog(analogweights);
% sum
sumpatterndata(:,ii) = rxdata * conj(digitalweights);
% diff
diffdigitalweights = digitalweights .* [1;-1];
diffpatternData(:,ii) = rxdata * conj(diffdigitalweights);
end
% calulate sum and diff amplitude and phase deltas
sumamp = mag2db(helperGetAmplitude(sumpatterndata));
diffamp = mag2db(helperGetAmplitude(diffpatternData));
sumdiffampdelta = sumamp-diffamp;
sumphase = helperGetPhase(sumpatterndata);
diffphase = helperGetPhase(diffpatternData);
sumdiffphasedelta = sign(wrapTo180(sumphase-diffphase));
end
function patternData = capturePatternWithNull(this,steerangles,nullangle)
patternData = zeros(1024,numel(steerangles));
for ii = 1 : numel(steerangles)
[analogweights,digitalweights] = this.getAllWeightsNull(steerangles(ii),nullangle);
rxdata = this.steerAnalog(analogweights);
patternData(:,ii) = rxdata * conj(digitalweights);
end
end
function rxdata = steerAnalog(this,analogWeights)
% Set analog phase shifter
phases = this.getPhaseCodes(analogWeights);
if ~isequal(this.LastPhase,phases)
this.ArrayControl.RxPhase(:) = phases;
this.LastPhase = phases;
end
% Set analog gain
gainCode = this.getGainCodes(analogWeights);
if ~isequal(this.LastGain,gainCode)
this.ArrayControl.RxGain(:) = gainCode;
this.LastGain = gainCode;
end
% receive data
this.ArrayControl.LatchRxSettings();
this.PlutoControl();
rxdata = this.PlutoControl();
end
function phases = getPhaseCodes(this,analogWeights)
sub1weights = analogWeights(:,1);
sub2weights = analogWeights(:,2);
sub1phase = this.getPhase(sub1weights);
sub2phase = this.getPhase(sub2weights);
phases = [sub1phase',sub2phase'];
phases = phases - phases(1);
phases = wrapTo360(phases);
end
function codes = getGainCodes(~,analogWeights)
codes = helperGainCodes(analogWeights);
end
end
methods (Access = private)
function [analogweights,digitalweights] = getAllWeights(this,steerangle)
defaultAnalogWeights = this.AnalogWeights;
defaultDigitalWeights = this.DigitalWeights;
% get analog weights
analogweights = this.getWeights(steerangle,defaultAnalogWeights,this.SubSteer);
% get digital weights, flip to ensure they are being applied to
% the correct channel.
flippedDigitalWeights = [defaultDigitalWeights(2);defaultDigitalWeights(1)];
digitalweights = this.getWeights(steerangle,flippedDigitalWeights,this.ArraySteer);
digitalweights = [digitalweights(2);digitalweights(1)];
end
function [analogweights,digitalweights] = getAllWeightsNull(this,steerangle,nullangle)
defaultAnalogWeights = this.AnalogWeights;
defaultDigitalWeights = this.DigitalWeights;
% get analogweights
analogweights = this.getWeightsNull(steerangle,nullangle,defaultAnalogWeights,this.SubSteer);
% get digital weights
flippedDigitalWeights = [defaultDigitalWeights(2);defaultDigitalWeights(1)];
digitalweights = this.getWeightsNull(steerangle,nullangle,flippedDigitalWeights,this.ArraySteer);
digitalweights = [digitalweights(2);digitalweights(1)];
end
function weights = getWeights(this,steerangle,defaultweights,sv)
initialweights = sv(this.Fc,steerangle);
weights = initialweights .* defaultweights;
end
function weights = getWeightsNull(this,steerangle,nullangle,defaultweights,sv)
steerweight = sv(this.Fc,steerangle);
nullweight = sv(this.Fc,nullangle);
rn = nullweight'*steerweight/(nullweight'*nullweight);
steernullweight = steerweight-nullweight*rn;
weights = steernullweight .* defaultweights;
end
function phase = getPhase(~,weights)
phase = rad2deg(angle(weights));
end
end
end

View File

@ -0,0 +1,27 @@
classdef ArrayFactorDataFormat
% Carry array factor data for calibration example
properties
SteeringAngle
UncalibratedPattern
AnalogCourseAmplitudeCalPattern
AnalogPhaseCalPattern
AnalogFineAmplitudeCalPattern
DigitalAmplitudeCalPattern
FullCalibration
end
methods
function s = toStruct(this)
s.SteeringAngle = this.SteeringAngle;
s.UncalibratedPattern = this.UncalibratedPattern;
s.AnalogCourseAmplitudeCalPattern = this.AnalogCourseAmplitudeCalPattern;
s.AnalogPhaseCalPattern = this.AnalogPhaseCalPattern;
s.AnalogFineAmplitudeCalPattern = this.AnalogFineAmplitudeCalPattern;
s.DigitalAmplitudeCalPattern = this.DigitalAmplitudeCalPattern;
s.FullCalibration = this.FullCalibration;
end
end
end

View File

@ -0,0 +1,25 @@
classdef CalibrationDataFormat
% Store calibration data
properties
ExampleData
CalibrationWeights = CalibrationWeightFormat();
AntennaPattern = ArrayFactorDataFormat();
AnalogPhaseCalibration = AnalogPhaseCalibrationFormat();
AnalogAmplitudeCalibration = AnalogAmplitudeCalibrationFormat();
DigitalCalibration = DigitalCalibrationFormat();
end
methods
function s = toStruct(this)
s.ExampleData = this.ExampleData;
s.CalibrationValues = this.CalibrationWeights.toStruct();
s.AntennaPattern = this.AntennaPattern.toStruct();
s.AnalogPhaseCalibration = this.AnalogPhaseCalibration.toStruct();
s.AnalogAmplitudeCalibration = this.AnalogAmplitudeCalibration.toStruct();
s.DigitalCalibration = this.DigitalCalibration.toStruct();
end
end
end

View File

@ -0,0 +1,17 @@
classdef CalibrationValueFormat
% Store the antenna calibration values
properties
AnalogWeights
DigitalWeights
end
methods
function s = toStruct(this)
s.AnalogWeights = this.AnalogWeights;
s.DigitalWeights = this.DigitalWeights;
end
end
end

View File

@ -0,0 +1,25 @@
classdef CalibrationWeightFormat
% Hold calibration weights at each step of the calibration process.
properties
UncalibratedWeights = CalibrationValueFormat()
AnalogCourseAmplitudeWeights = CalibrationValueFormat()
AnalogPhaseWeights = CalibrationValueFormat()
AnalogFineAmplitudeWeights = CalibrationValueFormat()
DigitalAmplitudeWeights = CalibrationValueFormat()
FinalCalibrationWeights = CalibrationValueFormat()
end
methods
function s = toStruct(this)
s.UncalibratedWeights = this.UncalibratedWeights.toStruct();
s.AnalogCourseAmplitudeWeights = this.AnalogCourseAmplitudeWeights.toStruct();
s.AnalogPhaseWeights = this.AnalogPhaseWeights.toStruct();
s.AnalogFineAmplitudeWeights = this.AnalogFineAmplitudeWeights.toStruct();
s.DigitalAmplitudeWeights = this.DigitalAmplitudeWeights.toStruct();
s.FinalCalibrationWeights = this.FinalCalibrationWeights.toStruct();
end
end
end

View File

@ -0,0 +1,28 @@
classdef DigitalCalibrationFormat
properties
MeasuredData
end
methods
function s = toStruct(this)
s.AmplitudeCalData = this.MeasuredData;
end
function gain = channelGain(this)
fReceive = max(abs(fft(this.MeasuredData)));
gain = max(fReceive) ./ fReceive;
end
function channelWeights = getChannelPhaseOffset(this)
phase = deg2rad(0:360);
st_vec = [ones(size(phase)); exp(1i*phase)];
sig = this.MeasuredData*conj(st_vec);
sigfft = fft(sig);
af = max(abs(sigfft));
[~, ind_phase] = max(af);
channelWeights = st_vec(:,ind_phase);
end
end
end

BIN
Matlab/GainProfile.mat Normal file

Binary file not shown.

View File

@ -0,0 +1,141 @@
clear; close all;
warning('off','MATLAB:system:ObsoleteSystemObjectMixin');
% Key Parameters
signal_freq = 10.145e9; % this is the HB100 frequency
%signal_freq = findTxFrequency();
plutoURI = 'ip:192.168.2.1';
phaserURI = 'ip:phaser.local';
run_calibration = true;
use_calibration = true;
%% Run Calibration
if run_calibration == true
CalibrationData = calibrationRoutine(signal_freq);
finalcalweights = CalibrationData.CalibrationWeights.FinalCalibrationWeights;
save("calibration_data.mat", "finalcalweights");
else
if isfile("calibration_data.mat") == true
load("calibration_data.mat", "finalcalweights");
else
use_calibration = false;
end
end
%% Load the measured gain profiles
load('GainProfile.mat','subArray1_NormalizedGainProfile','subArray2_NormalizedGainProfile','gaincode');
% Setup the pluto
rx = setupPluto(plutoURI);
% Setup the phaser
bf = setupPhaser(rx,phaserURI,signal_freq);
bf.RxPowerDown(:) = 0;
bf.RxGain(:) = 127;
% Create the model of the phaser, which consists of 2 4-element subarrays
nElements = 4;
subarrayModel = phased.ULA('NumElements',nElements,'ElementSpacing',bf.ElementSpacing);
nSubarrays = 2;
arrayModel = phased.ReplicatedSubarray("Subarray",subarrayModel,"GridSize",[1,nSubarrays],'SubarraySteering','Custom');
% Create the steering vector for the subarray and the main array
subarraySteer = phased.SteeringVector("SensorArray",subarrayModel,'NumPhaseShifterBits',7);
arraySteer = phased.SteeringVector("SensorArray",arrayModel);
% Set the analog and digital calibration weights. To see the uncalibrated
% array factor, all weights are set to 1.
if use_calibration == true
% These will need to be set based on the calibration routine
analogWeights = finalcalweights.AnalogWeights;
digitalWeights = finalcalweights.DigitalWeights;
else
% Weights all equal to 1 is an uncalibrated antenna
analogWeights = ones(4,2);
digitalWeights = ones(2,1);
end
%% Sweep the steering angle and capture data
steeringAngle = -90 : 90;
ArrayFactor = zeros(size(steeringAngle));
for ii = 1 : numel(steeringAngle)
currentangle = steeringAngle(ii);
% Get the steering weights for the subarray elements
subarraysteerweights = subarraySteer(signal_freq,currentangle);
adjustedsubarrayweights = subarraysteerweights .* analogWeights;
% Get element phase from steering weights
sub1weights = adjustedsubarrayweights(:,1);
sub2weights = adjustedsubarrayweights(:,2);
sub1phase = rad2deg(angle(sub1weights));
sub2phase = rad2deg(angle(sub2weights));
phases = [sub1phase',sub2phase'];
phases = phases - phases(1);
phases = wrapTo360(phases);
% Get the element gain from steering weights
sub1gain = mag2db(abs(sub1weights));
sub2gain = mag2db(abs(sub2weights));
calibGainCode = zeros(1,8);
for nch = 1 : 4
% Set gain codes for array 1
xp = sub1gain(nch);
if xp == -Inf
calibGainCode(nch) = 0;
else
calibGainCode(nch) = round(interp1(subArray1_NormalizedGainProfile(:,nch),gaincode,xp));
end
% Set gain codes for array 2
xp = sub2gain(nch);
if xp == -Inf
calibGainCode(nch+4) = 0;
else
calibGainCode(nch+4) = round(interp1(subArray2_NormalizedGainProfile(:,nch),gaincode,xp));
end
% Make sure the values of the gain code is always <= 127
calibGainCode(calibGainCode>127 | isnan(calibGainCode)) = 127;
end
% Set element phase and gain
bf.RxPhase(:) = phases;
bf.RxGain(:) = calibGainCode;
% Collect data
bf.LatchRxSettings();
receivedSig_HW = rx();
% Get the steering weights for the digital channels, we need to flip
% them before applying the steering vector because the receive data is
% out of order
flipdigitalweights = [digitalWeights(2);digitalWeights(1)];
arraysteerweights = arraySteer(signal_freq,currentangle);
adjustedarrayweights = arraysteerweights .* flipdigitalweights;
adjustedarrayweights = [adjustedarrayweights(2);adjustedarrayweights(1)];
% Apply the digital steering weights
receivedSig_HW_sum = receivedSig_HW * conj(adjustedarrayweights);
% Get the array factor
receivedFFT = fft(receivedSig_HW_sum);
ArrayFactor(ii) = (max(abs(receivedFFT)));
end
%% Compare the measured array factor and model
[~,ind] = max(ArrayFactor);
EmitterAz = steeringAngle(ind);
figure(101)
subarrayWeights = conj(subarraySteer(signal_freq,EmitterAz));
arrayWeights = arraySteer(signal_freq,EmitterAz);
pattern(arrayModel,signal_freq,-90:90,0,'CoordinateSystem', ...
'Rectangular','Type','powerdb','ElementWeights',[subarrayWeights,subarrayWeights],'Weights',arrayWeights)
hold on;
% Plot the measured data and the model
plot(steeringAngle,mag2db(ArrayFactor./max(abs(ArrayFactor))))
%%
bf.release();
rx.release();

352
Matlab/calibrationRoutine.m Normal file
View File

@ -0,0 +1,352 @@
function CalibrationData = calibrationRoutine(fc_hb100)
% Setup:
%
% Place the HB100 in front of the Phaser - 0 degree azimuth. It should be
% sufficiently far from the antenna so that the wavefront is approximately
% planar.
%
% Notes:
%
% The amplitude and phase of all 8 analog channels as well as the two
% digital channels must be calibrated so that the amplitudes in each
% channel are the same and the phase shifts align as expected during
% steering.
%
% The order of the calibration steps is described below.
%
% 1. Course Analog Amplitude Calibration: The first calibration step is an
% initial amplitude calibration so that the amplitude in each of the 4
% elements in each of the 2 subarrays are the same. This is done by
% independently measuring the signal amplitude in each channel when the gain
% is set to maximum.The gain is set so that all of the channel signal
% amplitudes match the lowest signal amplitude channel.
%
% 2. Analog Phase Calibration: The second calibration step is to account for
% the different phase shift in each analog channel. For each subarray,
% select a reference channel. Then measure the phase of other channels
% within the subarray with respect to the reference channel. The search is
% brute force, by sweeping all the possible phases on the chip.
%
% 3. Fine Analog Amplitude Calibration: Changing the default phase shift in
% each analog channel in step (2) causes the amplitude of the signal in
% each channel to change. Therefore, the amplitude calibration is performed
% again.
%
% 4. Digital Amplitude Calibration: Once the analog channels have been
% calibrated, the difference in amplitude between the two digital channels
% is measured. Whenever the digital channel signals are combined, an
% amplitude adjustment is applied based on this different in amplitude.
%
% 5. Digital Phase Calibration: The signal phase into each of the two
% digital channels will not necessarily align. The phase difference is
% measured by shifting the phase of channel 2 until the amplitude of the
% combined signal is maximized. This phase shift is applied when the two
% digital signals are combined.
%% Setup
% Setup antenna and model
[rx,bf,~] = setupAntenna(fc_hb100);
% Setup calibration data storage object
CalibrationData = CalibrationDataFormat();
% Setup the inital analog and digital antenna weights. These are the values
% that get adjusted during calibration. The amplitude and phase of the weights
% represent the gain and phase adjustments that will be made on each channel.
% Initially there is no phase shift or amplitude adjustment.
analogWeights = ones(4,2);
digitalWeights = ones(2,1);
% Store uncalibrated weights for later analysis
CalibrationData.CalibrationWeights.UncalibratedWeights.AnalogWeights = analogWeights;
CalibrationData.CalibrationWeights.UncalibratedWeights.DigitalWeights = digitalWeights;
%% Course Amplitude Calibration
% The amplitude in each analog channel is measured when the gain is
% set to the maximum level. Gain in each channel is adjusted to account
% for differences.
% Set the gain of all 8 channels to maximum.
bf.RxGain(:) = 127;
% Setup data variables
nCapture = 20;
rx1data = zeros(1024,nCapture,4);
rx2data = zeros(1024,nCapture,4);
for nCh = 1:4
% Turn off all the channels.
bf.RxPowerDown(:) = 1;
% Turn on channels under test (subarray 1 and subarray 2)
bf.RxPowerDown(nCh) = 0;
bf.RxPowerDown(nCh+4) = 0;
bf.LatchRxSettings();
% Capture multiple snapshots
for ncapture = 1 : nCapture
rx();
receivedSig = rx();
rx1data(:,ncapture,nCh) = receivedSig(:,2);
rx2data(:,ncapture,nCh) = receivedSig(:,1);
end
end
% Turn all channels back on
bf.RxPowerDown(:) = 0;
% Calculate the average amplitude for each element in each subarray
avgamp1 = mean(max(abs(fft(rx1data))));
avgamp2 = mean(max(abs(fft(rx2data))));
% Reshape into a vector
avgamp1 = reshape(avgamp1,[1 4]);
avgamp2 = reshape(avgamp2,[1 4]);
% Scale each amplitude value to the minimum measured amplitude value
sub1gain = min(avgamp1) ./ avgamp1;
sub2gain = min(avgamp2) ./ avgamp2;
% Plot the analog amplitude calibration values
helperPlotElementGainCalibration(avgamp1,sub1gain,avgamp2,sub2gain);
% Update analog weights with array gain calibration values
analogWeights = analogWeights .* [sub1gain',sub2gain'];
% Store the calibration data for later analysis
CalibrationData.AnalogAmplitudeCalibration.CourseSubarray1Data = rx1data;
CalibrationData.AnalogAmplitudeCalibration.CourseSubarray2Data = rx2data;
CalibrationData.CalibrationWeights.AnalogCourseAmplitudeWeights.AnalogWeights = analogWeights;
%% Calibrate phase
% Place the emitter in front of the phased array.
% Turn on two adjacent channel. On the first channel put 0 phase, and on
% the adjacent channel sweep the phase shift setting from 0 to 360. Minimum
% signal strength occurs when the phase offset between channels is 180
% degrees. The calibration value is set such that the phase shift is
% actually 180 degrees when shifter is set to 180 degrees.
% Setup phase steps to test and variables to hold data
PhaseResolutionBits = 7;
phase_step_size = 360 / (2 ^ PhaseResolutionBits);
channel2phase = double(0:phase_step_size:360);
rawdata1 = zeros(rx.SamplesPerFrame,numel(channel2phase),3);
rawdata2 = zeros(rx.SamplesPerFrame,numel(channel2phase),3);
% Set the reference channel and channels under test
referencechannel = 1;
testchannels = 2:4;
% set the receiver gain based on the amplitude calibration. The gain codes
% are set based on data that was previously captured to determine gain code
% correspondance to actual gain.
bf.RxGain = helperGainCodes(analogWeights);
% Loop through each channel under test
for nChannel = testchannels
% Set all phase shifts to 0
bf.RxPhase(:) = 0;
% Power down all elements
bf.RxPowerDown(:) = 1;
% Turn on element 1 and element under test subarray 1
bf.RxPowerDown(referencechannel) = 0;
bf.RxPowerDown(nChannel) = 0;
% Turn on element 1 and element under test subarray 2
bf.RxPowerDown(referencechannel+4) = 0;
bf.RxPowerDown(nChannel+4) = 0;
bf.LatchRxSettings();
% Loop through each phase offset, set element under test phase shifter,
% capture data.
for ii = 1 : numel(channel2phase)
% Set phase for subarray 1 and 2 element
bf.RxPhase(nChannel) = channel2phase(ii);
bf.RxPhase(nChannel+4) = channel2phase(ii);
bf.LatchRxSettings();
% Capture and store data
rx();
receivedSig_HW = rx();
rawdata1(:,ii,nChannel-1) = receivedSig_HW(:,2);
rawdata2(:,ii,nChannel-1) = receivedSig_HW(:,1);
end
end
% Get signal amplitude for both subarrays
amp1 = max(abs(fft(rawdata1)),[],1);
amp2 = max(abs(fft(rawdata2)),[],1);
% Reshape into a 2d array which is Number Phases x Number Elements
sub1amplitudes = reshape(amp1,[numel(channel2phase) 3]);
sub2amplitudes = reshape(amp2,[numel(channel2phase) 3]);
% Get location of min amplitude
[~,phase1Idx] = min(sub1amplitudes,[],1);
[~,phase2Idx] = min(sub2amplitudes,[],1);
% Get calibration phase by substracting 180 from the minimum phase location
cal1phase = [0;wrapTo360(channel2phase(phase1Idx)-180)'];
cal2phase = [0;wrapTo360(channel2phase(phase2Idx)-180)'];
% Plot the analog phase shift information
helperPlotAnalogPhaseCalibration(channel2phase,sub1amplitudes,sub2amplitudes);
% Convert calibration phase to a phase shift for the element weights, and
% update analog weights
phaseSteer = exp(deg2rad([cal1phase,cal2phase])*1i);
analogWeights = analogWeights .* phaseSteer;
% Store recorded data for later analysis
CalibrationData.AnalogPhaseCalibration.PhaseSetting = channel2phase;
CalibrationData.AnalogPhaseCalibration.Subarray1Measurements = rawdata1;
CalibrationData.AnalogPhaseCalibration.Subarray2Measurements = rawdata2;
CalibrationData.CalibrationWeights.AnalogPhaseWeights.AnalogWeights = analogWeights;
%% Fine Grain Calibration Data
% The amplitude in each analog channel is measured when the gain is
% set to the maximum level with the new default phase shifts applied.
% Gain in each channel is adjusted to account for differences. This is the
% exact same process that was used for the analog course amplitude
% calibration, although now the phase shifter values are set to the default
% determined in the previous section.
% Set the gain of all 8 channels to maximum.
bf.RxGain(:) = 127;
% Set the phase shifts based on the new analog weights
phaseshifts = wrapTo360(rad2deg(angle(analogWeights)));
bf.RxPhase(:) = [phaseshifts(:,1)',phaseshifts(:,2)'];
% Setup data variables
nCapture = 20;
rx1data = zeros(1024,nCapture,4);
rx2data = zeros(1024,nCapture,4);
for nCh = 1:4
% Turn off all the channels.
bf.RxPowerDown(:) = 1;
% Turn on channels under test (subarray 1 and subarray 2)
bf.RxPowerDown(nCh) = 0;
bf.RxPowerDown(nCh+4) = 0;
bf.LatchRxSettings();
% Capture multiple snapshots
for ncapture = 1 : nCapture
rx();
receivedSig = rx();
rx1data(:,ncapture,nCh) = receivedSig(:,2);
rx2data(:,ncapture,nCh) = receivedSig(:,1);
end
end
% Turn all channels back on
bf.RxPowerDown(:) = 0;
% Calculate the average amplitude for each element in each subarray
avgamp1 = mean(max(abs(fft(rx1data))));
avgamp2 = mean(max(abs(fft(rx2data))));
% Reshape into a vector
avgamp1 = reshape(avgamp1,[1 4]);
avgamp2 = reshape(avgamp2,[1 4]);
% Scale each amplitude value to the minimum measured amplitude value
sub1gain = min(avgamp1) ./ avgamp1;
sub2gain = min(avgamp2) ./ avgamp2;
% Normalize the weights back to amplitude 1
analogWeights = analogWeights ./ abs(analogWeights);
% Update analog weights with array gain calibration values
analogWeights = analogWeights .* [sub1gain',sub2gain'];
% Store the calibration data for later analysis
CalibrationData.AnalogAmplitudeCalibration.FineSubarray1Data = rx1data;
CalibrationData.AnalogAmplitudeCalibration.FineSubarray2Data = rx2data;
CalibrationData.CalibrationWeights.AnalogFineAmplitudeWeights.AnalogWeights = analogWeights;
%% Calibrate the two digital channels on Pluto
% After the analog channels have been calibrated, collect data with
% analog calibration value settings and calibrate the digital channels for
% amplitude and phase.
% Collect data with analog weight settings
analogcaldata = helperSteerAnalog(bf,rx,analogWeights);
% Store calibration data for later analysis
CalibrationData.DigitalCalibration.MeasuredData = analogcaldata;
% Calculate the channel calibration gain by normalizing the channel
% amplitudes to the max channel amplitude
channelamplitude = max(abs(fft(analogcaldata)));
gain = max(channelamplitude) ./ channelamplitude;
digitalWeights = digitalWeights .* gain';
% Save the weights for later analysis
CalibrationData.CalibrationWeights.DigitalAmplitudeWeights.AnalogWeights = analogWeights;
CalibrationData.CalibrationWeights.DigitalAmplitudeWeights.DigitalWeights = digitalWeights;
% Calculate the channel calibration phase by steering channel 2 from 0 to
% 360 and finding the maximum combined channel amplitude
channel2phase = deg2rad(0:360);
st_vec = [ones(size(channel2phase)); exp(1i*channel2phase)];
sig = analogcaldata*conj(st_vec);
sigfft = fft(sig);
combinedamplitude = max(abs(sigfft));
[~, phaseIdx] = max(combinedamplitude);
% Plot the digital phase offset pattern and calibration value
ax = axes(figure); hold(ax,"on");
title(ax,"Digital Phase Calibration"); ylabel(ax,"dB"); xlabel(ax,"Channel 2 Phase Offset (deg)");
plot(ax,channel2phase,combinedamplitude,"DisplayName","Combined Channel Power");
scatter(ax,channel2phase(phaseIdx),combinedamplitude(phaseIdx),"DisplayName","Selected Phase Offset");
legend('location','southeast');
% Set the new digital weights
defaultsteervec = st_vec(:,phaseIdx);
digitalWeights = digitalWeights .* defaultsteervec;
% Save the final calibration weights
CalibrationData.CalibrationWeights.FinalCalibrationWeights.AnalogWeights = analogWeights;
CalibrationData.CalibrationWeights.FinalCalibrationWeights.DigitalWeights = digitalWeights;
%% Release Hardware
bf.release(); delete(bf);
rx.release(); delete(rx);
%% Plot final data: uncalibrated data vs. calibrated data vs. simulated data
% Use a custom class called AntennaInteractor to help steer the antenna
initialcalvalues = CalibrationData.CalibrationWeights.UncalibratedWeights;
antennaInteractor = AntennaInteractor(fc_hb100,initialcalvalues);
steerangles = -90:0.5:90;
% Capture the pattern with the initial calibration values
[initialpattern,~] = antennaInteractor.capturePattern(steerangles);
initialamp = mag2db(helperGetAmplitude(initialpattern));
% Capture the pattern with the final calibration values
finalcalvalues = CalibrationData.CalibrationWeights.FinalCalibrationWeights;
antennaInteractor.updateCalibration(finalcalvalues);
[finalpattern,~] = antennaInteractor.capturePattern(steerangles);
finalamp = mag2db(helperGetAmplitude(finalpattern));
% Simulate the expected antenna pattern
rxpos = [0;0;0]; % phaser at 0
txpos = [0;10;0]; % transmitter 10 meters away at 0 boresight
simpattern = mag2db(helperSimulateAntennaSteering(fc_hb100,rxpos,txpos,steerangles));
% Plot data
patternax = axes(figure); hold(patternax,"on"); legend(patternax);
xlabel(patternax,"Steer Angle (deg)"); ylabel(patternax,"Amplitude (dB)"); title(patternax,"Calibration Effect");
plot(patternax,steerangles,initialamp - max(initialamp),'DisplayName','Uncalibrated Array Factor');
plot(patternax,steerangles,finalamp - max(finalamp),'DisplayName','Calibrated Array Factor');
plot(patternax,steerangles,simpattern - max(simpattern),'DisplayName','Simulated Array Factor');
end

BIN
Matlab/calibration_data.mat Normal file

Binary file not shown.

4
Matlab/cleanupAntenna.m Normal file
View File

@ -0,0 +1,4 @@
function cleanupAntenna(rx,bf)
rx.release();
bf.release();
end

BIN
Matlab/finalcalweights.mat Normal file

Binary file not shown.

58
Matlab/findTxFrequency.m Normal file
View File

@ -0,0 +1,58 @@
function txFrequency = findTxFrequency()
% Setup:
%
% Place the HB100 in front of the Phaser - 0 degree azimuth.
%
% Notes:
%
% The frequency of the phaser is swept between 10 and 10.5 GHz. The peak
% frequency is measured. This is assumed to be the frequency of the HB100.
%
% Setup the frequencies to scan.
f_start = 10.e9;
f_stop = 10.5e9;
f_step = 5e6;
fvec = f_start : f_step : f_stop;
% Setup the antenna, setting the frequency to f_start.
[rx,bf,~] = setupAntenna(f_start);
% Setup variables for capturing scan amplitude and frequency.
full_ampl = [];
full_freqs = [];
N = rx.SamplesPerFrame;
% Loop through the frequency vector and save receive data at each center
% frequency.
for centerfrequency = fvec
% The LO is set to 4x the Frequency setting.
bf.Frequency = (centerfrequency + rx.CenterFrequency)/4;
rx();
% Capture the data, sum the channels, and convert to the frequency domain
data = rx();
data = sum(data,2);
famplitude = mag2db(1/N * fftshift(abs(fft(data))));
full_ampl = [full_ampl, famplitude];
% Get the frequency span for this data sample
df = rx.SamplingRate/N;
band = (-rx.SamplingRate/2 : df : rx.SamplingRate/2 - df);
freqspan = centerfrequency-band;
full_freqs = [full_freqs, freqspan'];
end
% Get the max amplitude for each measurement
[maxamplitudes,maxidxs] = max(full_ampl);
% Get the max amplitude in the whole dataset
[~,maxframeidx] = max(maxamplitudes);
maxdatapointidx = maxidxs(maxframeidx);
txFrequency = full_freqs(maxdatapointidx,maxframeidx);
ax = axes(figure);
plot(ax,full_freqs/1e9,full_ampl); xlabel('Frequency (GHz)'); ylabel('Amplitude (dB)');
title(ax,['HB100 Frequency = ' num2str(txFrequency/1e9) 'GHz']);
end

View File

@ -0,0 +1,13 @@
function amplitude = helperCalculateAmplitude(data,maxvalue)
% Get the signal amplitude
% Scale data
datascaled = data / maxvalue;
[nsamples,~] = size(data);
% Convert the signal to the frequency domain
fexampledata = mag2db(abs(fft(datascaled)) / nsamples);
% Amplitude is the largest frequency value
amplitude = max(fexampledata);
end

36
Matlab/helperGainCodes.m Normal file
View File

@ -0,0 +1,36 @@
function calibGainCode = helperGainCodes(analogWeights)
% get gain for each subarray
sub1weights = analogWeights(:,1);
sub2weights = analogWeights(:,2);
sub1gain = getGain(sub1weights);
sub2gain = getGain(sub2weights);
% Loading the measured gain profiles
load('GainProfile.mat','subArray1_NormalizedGainProfile','subArray2_NormalizedGainProfile','gaincode');
calibGainCode = zeros(1,8);
for nch = 1 : 4
xp = sub1gain(nch);
if xp == -Inf
calibGainCode(nch) = 0;
else
calibGainCode(nch) = round(interp1(subArray1_NormalizedGainProfile(:,nch),gaincode,xp));
end
xp = sub2gain(nch);
if xp == -Inf
calibGainCode(nch+4) = 0;
else
calibGainCode(nch+4) = round(interp1(subArray2_NormalizedGainProfile(:,nch),gaincode,xp));
end
end
% Make sure the values of the gain code is always <= 127
calibGainCode(calibGainCode>127 | isnan(calibGainCode)) = 127;
function gain = getGain(weights)
amp = abs(weights);
gain = mag2db(amp);
end
end

View File

@ -0,0 +1,3 @@
function [amp] = helperGetAmplitude(signal)
amp = max(abs(fft(signal)));
end

8
Matlab/helperGetPhase.m Normal file
View File

@ -0,0 +1,8 @@
function phase = helperGetPhase(signal)
fsig = fft(signal);
[~,ampidx] = max(fsig);
phase = zeros(1,numel(ampidx));
for i = 1:numel(ampidx)
phase(i) = rad2deg(angle(fsig(ampidx(i),i)));
end
end

View File

@ -0,0 +1,19 @@
function helperPlotAnalogPhaseCalibration(phasesetting,sub1amplitudes,sub2amplitudes)
% Visualize the element-wise phase calibration data for the entire
% array.
figure; tiledlayout(1,2); nexttile();
helperPlotPhaseSubarrayData("Subarray 1",phasesetting,mag2db(sub1amplitudes)); nexttile();
helperPlotPhaseSubarrayData("Subarray 2",phasesetting,mag2db(sub2amplitudes));
end
function helperPlotPhaseSubarrayData(name, phasesetting, phaseOffsetAmplDb)
% Visualize the element-wise phase calibration data for a subarray.
lines = plot(phasesetting, phaseOffsetAmplDb);
lines(1).DisplayName = "Element 2";
lines(2).DisplayName = "Element 3";
lines(3).DisplayName = "Element 4";
title([name,' - Phase Calibration Data'])
ylabel("Amplitude (dB) Element X + Element 1")
xlabel("Test Element Phase Shift (deg)")
legend("Location","southoutside")
end

View File

@ -0,0 +1,41 @@
function [array1gaincal,array2gaincal] = helperPlotElementGainCalibration(sub1meanamp,sub1gaincal,sub2meanamp,sub2gaincal)
% Calculate and visualize the element-wise amplitude calibration for
% both subarrays.
sub1meanamp = mag2db(sub1meanamp);
sub1gaincal = mag2db(sub1gaincal);
sub2meanamp = mag2db(sub2meanamp);
sub2gaincal = mag2db(sub2gaincal);
% Setup figure
figure; tiledlayout(1,2); a = nexttile();
% Calculate and plot the gain calibration for subarray 1
array1gaincal = helperElementSubarrayGainCalibration(a,'Subarray 1',sub1meanamp, sub1gaincal); a = nexttile();
% Calculate and plot the gain calibration for subarray 2
array2gaincal = helperElementSubarrayGainCalibration(a, 'Subarray 2', sub2meanamp, sub2gaincal);
end
function arraygaincal = helperElementSubarrayGainCalibration(ax,name,amplitudes,arraygaincal)
% Calculate and visualize the element-wise amplitude calibration for
% one subarray.
hold(ax,"on");
% Normalize amplitude for each element in the array
dbNormAmplitudes = amplitudes - max(amplitudes);
% Plot normalized amplitudes and gain adjustments
b = bar(ax,[dbNormAmplitudes',arraygaincal'],'stacked');
b(1).DisplayName = "Initial Normalized Amplitude";
b(2).DisplayName = "Gain Adjustment";
% Plot a line showing the final amplitude of all elements
plot(ax,[0,5],[min(dbNormAmplitudes),min(dbNormAmplitudes)],"DisplayName","Final Element Amplitude","LineWidth",2,"Color","k")
xlabel('Antenna Element')
ylabel('dB');
title([name ' - Gain Calibration'])
legend('Location','southoutside')
end

View File

@ -0,0 +1,18 @@
function gain = helperPlotGainCalibration(name, amplitudes)
% Normalize amplitude for each element in the array
dbNormAmplitudes = mag2db(amplitudes./max(amplitudes));
% Calculate gain adjustment
gain = -mag2db(amplitudes./min(amplitudes));
% Plot normalized amplitudes and gain adjustments
b = bar([dbNormAmplitudes',gain'],'stacked');
b(1).DisplayName = "Initial Normalized Amplitude";
b(2).DisplayName = "Gain Adjustment";
xlabel('Antenna Element')
ylabel('dB');
title([name ' - Gain Calibration'])
legend('Location','southoutside')
end

View File

@ -0,0 +1,86 @@
function [rxamp,rxphase] = helperSimulateAntennaSteering(fctransmit,rxpos,txpos,steerangle,analogweight,digitalweight,nullangle)
% This helper function simulates antenna steering for the ADI workshop.
% analogweight and digitalweight are optional inputs that default to 1.
arguments
fctransmit (1,1) double
rxpos (3,1) double
txpos (3,1) double
steerangle (1,:) double
analogweight (4,2) double = ones(4,2)
digitalweight (2,1) double = ones(2,1)
nullangle = []
end
% Setup the transmitter
txelement = phased.IsotropicAntennaElement;
radiator = phased.Radiator("Sensor",txelement,"OperatingFrequency",fctransmit);
% Setup the Phased Array Receiver based on the Phaser specs
frange = [10.0e9 10.5e9];
sampleRate = 30e6;
nsamples = 1024;
element = phased.IsotropicAntennaElement('FrequencyRange',frange);
hRange = freq2wavelen(frange);
spacing = hRange(2)/2;
subarrayElements = 4;
subarray = phased.ULA('Element',element,'NumElements',subarrayElements,'ElementSpacing',spacing);
array = phased.ReplicatedSubarray('Subarray',subarray,'GridSize',[1,2],"SubarraySteering","Custom");
collector = phased.Collector("Sensor",array,"OperatingFrequency",fctransmit,"WeightsInputPort",true);
% CW signal is used
signal = ones(nsamples,1);
% Set up a channel for radiating signal
channel = phased.FreeSpace("OperatingFrequency",fctransmit,"SampleRate",sampleRate);
% Setup geometry
rxvel = [0;0;0];
txvel = [0;0;0];
[~,ang] = rangeangle(rxpos,txpos);
% Radiate signal
sigtx = radiator(signal,ang);
% Propagate signal
sigtx = channel(sigtx,txpos,rxpos,txvel,rxvel);
% Create steering vector for the two subarray channels
steervec = phased.SteeringVector("SensorArray",array);
substeervec = phased.SteeringVector("SensorArray",subarray);
% Receive signal while steering beam
rxphase = zeros(1,numel(steerangle));
rxamp = zeros(1,numel(steerangle));
for steer = steerangle
% Create the subarray weights.
singlesubweight = substeervec(fctransmit,steer);
% Create the replicated array weights
repweight = steervec(fctransmit,steer);
% insert a null if a null angle was passed in
if ~isempty(nullangle)
% Null the subarray
nullsubweight = substeervec(fctransmit,nullangle);
singlesubweight = getNullSteer(singlesubweight,nullsubweight);
% null the replicated array
nullrepweight = steervec(fctransmit,nullangle);
repweight = getNullSteer(repweight,nullrepweight);
end
% Create the full subarray weights
subweight = [singlesubweight,singlesubweight] .* analogweight;
% Receive the signal
sigreceive = collector(sigtx,[0;0],repweight,subweight) * digitalweight;
rxphase(steer == steerangle) = mean(rad2deg(angle(sigreceive)));
rxamp(steer == steerangle) = mean(abs(sigreceive));
end
end
function nullsteer = getNullSteer(steerweight,nullweight)
rn = nullweight'*steerweight/(nullweight'*nullweight);
nullsteer = steerweight-nullweight*rn;
end

View File

@ -0,0 +1,9 @@
function simpattern = helperSimulateDisabledElement(fc,steerangles,iEl)
% Simulate what happens when we disable an element on each of the antenna
% subarrays.
disabletaper = ones(4,2);
disabletaper(iEl,:) = 0;
rxpos = [0;0;0];
txpos = [0;10;0];
simpattern = helperSimulateAntennaSteering(fc,rxpos,txpos,steerangles,disabletaper);
end

View File

@ -0,0 +1,15 @@
function [sumamp,diffamp,phasedelta] = helperSimulateMonopulse(fc_hb100,steerangles)
% Simulate the monopulse pattern for the ADI phaser.
% Get the sum pattern
rxpos = [0;0;0];
txpos = [0;10;0];
[sumamp,sumphase] = helperSimulateAntennaSteering(fc_hb100,rxpos,txpos,steerangles);
% The diff pattern is generated by setting the digital weights to
% [1;-1]
analogweights = ones(4,2);
digitalweights = [1;-1];
[diffamp,diffphase] = helperSimulateAntennaSteering(fc_hb100,rxpos,txpos,steerangles,analogweights,digitalweights);
phasedelta = sign(wrapTo180(sumphase-diffphase));
end

View File

@ -0,0 +1,8 @@
function pattern = helperSimulateNull(fc_hb100,steerangles,nullangle)
% Simulate the pattern with a null at the specified angle
analogweights = ones(4,2);
digitalweights = ones(2,1);
rxpos = [0;0;0];
txpos = [0;10;0];
[pattern,~] = helperSimulateAntennaSteering(fc_hb100,rxpos,txpos,steerangles,analogweights,digitalweights,nullangle);
end

View File

@ -0,0 +1,21 @@
function sourceaz = helperSourceLocation(CalibrationData)
[rx,bf,fc_hb100,phaseCal,channelWeights,steeringVec,~] = setupAntenna(CalibrationData);
% Capture the initial pattern data, find the location of the interferer -
% assumed to be higher power
steerangles = -90:0.5:90;
patternData = helperCapturePattern(steerangles,steeringVec,fc_hb100,bf,rx,phaseCal,channelWeights);
amp = helperGetAmplitude(patternData);
smoothamp = smooth(amp,20);
[~,azidx] = max(smoothamp);
sourceaz = steerangles(azidx);
ax = axes(figure); hold(ax,"on");
plot(ax,steerangles,amp,"DisplayName","Scan Pattern")
scatter(ax,sourceaz,amp(azidx),"DisplayName","Source Location");
legend();
cleanupAntenna(rx,bf);
end

View File

@ -0,0 +1,27 @@
function rxdata = helperSteerAnalog(bf,rx,analogWeights)
sub1weights = analogWeights(:,1);
sub2weights = analogWeights(:,2);
% Set analog phase shifter
sub1phase = getPhase(sub1weights);
sub2phase = getPhase(sub2weights);
phases = [sub1phase',sub2phase'];
if ~isequal(bf.RxPhase,phases)
bf.RxPhase(:) = phases;
end
% Set analog gain
gainCode = helperGainCodes(analogWeights);
if ~isequal(bf.RxGain,gainCode)
bf.RxGain(:) = gainCode;
end
% receive data
bf.LatchRxSettings();
rx();
rxdata = rx();
end
function phase = getPhase(weights)
phase = wrapTo360(rad2deg(angle(weights)));
end

19
Matlab/setupAntenna.m Normal file
View File

@ -0,0 +1,19 @@
function [rx,bf,phaserModel] = setupAntenna(fc_hb100)
% Setup the Pluto, Phaser, and Phaser Model.
% Setup the pluto
plutoURI = 'ip:192.168.2.1';
rx = setupPluto(plutoURI);
% Setup the phaser
phaserURI = 'ip:phaser.local';
bf = setupPhaser(rx,phaserURI,fc_hb100);
bf.RxPowerDown(:) = 0;
bf.RxGain(:) = 127;
% Create the model of the phaser
nElements = 4;
nSubarrays = 2;
subModel = phased.ULA('NumElements',nElements,'ElementSpacing',bf.ElementSpacing);
phaserModel = phased.ReplicatedSubarray("Subarray",subModel,"GridSize",[1,nSubarrays]);
end

48
Matlab/setupPhaser.m Normal file
View File

@ -0,0 +1,48 @@
function bf = setupPhaser(rx,phaserURI,fc_hb100)
%% Configure phaser
bf = adi.Phaser;
bf.uri = phaserURI;
bf.SkipInit = true; % Bypass writing all initial attributes to speed things up
bf();
bf.ElementSpacing = 0.014;
% Put device in Rx mode
bf.TxRxSwitchControl = {'spi','spi'};
bf.Mode(:) = {'Disabled'};
bf.BeamMemEnable(:) = false;
bf.BiasMemEnable(:) = false;
bf.PolState(:) = false;
bf.PolSwitchEnable(:) = false;
bf.TRSwitchEnable(:) = true;
bf.ExternalTRPolarity(:) = true;
bf.RxVGAEnable(:) = true;
bf.RxVMEnable(:) = true;
bf.RxLNABiasCurrent(:) = 8;
bf.RxVGABiasCurrentVM(:) = 22;
% Self bias LNAs
bf.LNABiasOutEnable(:) = false;
% Fire them up
bf.RxPowerDown(:) = false;
bf.Mode(:) = {'Rx'};
%% Set up PLL
bf.Frequency = (fc_hb100 + rx.CenterFrequency) / 4;
BW = 500e6 / 4; num_steps = 1000;
bf.FrequencyDeviationRange = BW; % frequency deviation range in H1. This is the total freq deviation of the complete freq ramp
bf.FrequencyDeviationStep = int16(BW / num_steps); % frequency deviation step in Hz. This is fDEV, in Hz. Can be positive or negative
bf.RampMode = "disabled";
bf.DelayStartWord = 4095;
bf.DelayClockSource = "PFD";
bf.DelayStartEnable = false; % delay start
bf.RampDelayEnable = false; % delay between ramps.
bf.TriggerDelayEnable = false; % triangle delay
bf.SingleFullTriangleEnable = false; % full triangle enable/disable -- this is used with the single_ramp_burst mode
bf.TriggerEnable = false; % start a ramp with TXdata
%% Flatten phaser phase/gain
bf.RxGain(:) = 127;
bf.RxAttn(:) = 0;
bf.RxPhase(:) = 0;
bf.RxLNAEnable(:) = true;
bf.LatchRxSettings();

19
Matlab/setupPluto.m Normal file
View File

@ -0,0 +1,19 @@
function rx = setupPluto(plutoURI)
rx = adi.AD9361.Rx('uri', plutoURI);
rx.EnabledChannels = [1,2];
rx.SamplesPerFrame = 1024;
rx.CenterFrequency = 2e9;
rx.kernelBuffersCount = 2; % Minimize delay in receive data
rx.GainControlModeChannel0 = 'manual';
rx.GainControlModeChannel1 = 'manual';
rx.GainChannel0 = 6;
rx.GainChannel1 = 6;
rx.SamplingRate = 30e6;
rx();
tx = adi.AD9361.Tx('uri', plutoURI);
tx.EnabledChannels = [1,2];
tx.CenterFrequency = rx.CenterFrequency+2e6;
tx.AttenuationChannel0 = -89;
tx.AttenuationChannel1 = -89;
end