Main Content

Getting Started with Radar Signal Generation Using NI-RFSG Scripting

This example shows how to generate a realistic radar pulse train using an NI™ VST. Specifically, it demonstrates how to generate a pulse train comprising 100 MHz wide chirps, initially using a simple functional definition, and finally using scripting and waveform sequences.

RadarSignalIllustration.png

Set Up

Clear the current workspace and set the output display format to short engineering notation.

clear;
format shortEng;

Define Radar Pulse Train Parameters

Specify the radar pulse train parameters for center frequency, sweep bandwidth, sampling frequency, PRI, PRF, and the idle time.

Note that oversampling is used to improve visualization but is not otherwise necessary.

fc              = 2.8e9;            % Radar center frequency
sweepBandwidth  = 100e6;
fs              = 8*sweepBandwidth; % Oversample to ensure a smooth time-domain visualization
pulseWidth      = 10e-6;
PRI             = 16*pulseWidth;    % Pulse repetition interval
PRF             = 1/PRI;            % Pulse repetition frequency
pulsesPerTrain  = 8;
idleTime        = 2e-3;

Define Radar Pulse Train

Define a full radar pulse train with the specified parameters.

waveformGenerator = phased.LinearFMWaveform(...
    SampleRate=fs, ...
    PulseWidth=pulseWidth, ...
    PRF=1/PRI, ...
    SweepBandwidth=sweepBandwidth, ...
    SweepInterval="Positive", ...
    SweepDirection="Up", ...
    OutputFormat="Pulses", ...
    NumPulses=pulsesPerTrain, ...
    Envelope="Rectangular");

Create pulse train and dead time samples separately.

pulses = waveformGenerator();
idleSamples = zeros(ceil(idleTime*fs), 1, 'like', pulses);

pulseTrain = [pulses; idleSamples];
lenTrain = length(pulseTrain);

Visualize the radar pulse train in the time-domain.

tdScope = timescope(SampleRate=fs, ...
                    TimeSpan=lenTrain/fs, ...
                    BufferLength=lenTrain);

tdScope(pulseTrain)

Visualize the spectrogram of the radar pulse train.

nfft = 8*1024;
nov = floor(nfft/2);
spectrogram(pulses,hamming(nfft),nov,nfft,fs,'centered','xaxis','MinThreshold',-110);
colormap ("bone")

Connect to Instrument

Connect to VST instrument using the ividev function. To determine or change the resource name for your system, use the NI Measurement and Automation Explorer (NI-MAX). For this example, specify the driver name as niRFSG, the resource name as PXI1Slot2, and the IVI driver setup name-value argument as Model:5841.

Alternatively, you can leave the resource name unspecified ("") for simulated hardware. The driver setup is also optional. If you do not specify a name-value argument for the driver setup, ividev uses default setup values. For more information about default argument values, see ividev.

isSimulated = false;
deviceID = "PXI1Slot2";
if isSimulated
    vsg = ividev("niRFSG", deviceID, Simulate=true, DriverSetup="Model:5841");
else
    vsg = ividev("niRFSG", deviceID);
end

Generate Pulse Trains Without Scripting

To generate pulse trains without scripting, you must copy all waveform samples to the VST's memory. For pulse trains, this is wasteful because most of the waveform consists of idle time.

Write Waveform to Instrument Memory

Configure the VST to generate an arbitrary waveform. Set the following parameters to the specified value.

  • Frequency to the radar center frequency

  • Reference power level to -10 dBm

  • Generation mode to arbitrary waveform

  • Set the prefilter gain to prevent overflow in the generator's internal filters

  • Signal bandwidth to match null-to-null bandwidth

peakPowerLevel_dBm = -10;
configureRF(vsg, fc, peakPowerLevel_dBm);

configureGenerationMode(vsg, "ARB_WAVEFORM");
configurePowerLevelType(vsg, "PEAK_POWER");
vsg.Arb.IQRate = fs; 
vsg.Arb.PrefilterGain = -2.0;
vsg.Arb.SignalBandwidth = 2/pulseWidth;

moreDataPending = false;
% To write a waveform, set the VSG to the configuration state.
abort(vsg);
waveformName = "SinglePulseTrain";
writeArbWaveform(vsg, waveformName, length(pulseTrain), real(pulseTrain), imag(pulseTrain), moreDataPending);

Generate Signal Continuously

Start a continuous generation.

initiate(vsg);
configureOutputEnabled(vsg, true);
isDone = checkGenerationStatus(vsg);

In this example, stop signal generation after five seconds or if an error occurs. Check the signal generation status for errors every 100 ms.

count = 1;
duration_s = 5;

fprintf('Starting Generation\n')
Starting Generation
while ~isDone && count <= 10*duration_s
    isDone = checkGenerationStatus(vsg);
    pause(0.100)
    count = count+1;
    % display indicator every second
    if mod(count, 10) == 0
        fprintf(".")
    end
end
.....
fprintf('\nStopping Generation')
Stopping Generation

Stop generation.

configureOutputEnabled(vsg, false);
abort(vsg)

Generate Simple Sequence Using Script

In this example, the waveform (as previously defined) fits in memory and does not change in response to external events. For this scenario, arbitrary generation mode may be sufficient.

However, for situations where it is necessary to produce a complex sequence of waveforms that are possibly based on external events, you can take advantage of patterns in the waveform signal (waveform segments) to enable complex signal generation in the instrument. The following example demonstrates how to use scripting to produce a simple sequence of pulse trains.

In addition, when instrument memory constraints are significant (e.g., requiring a higher sampling rate, larger number of samples, multiple waveforms, complex sequence of waveforms, etc.), you can use sequences to dramatically reduce the memory footprint. The instrument needs to store only the necessary segments and sequence them programmatically.

More realistic situations, such as those encountered using multi-function radars, will situationally adapt the generated waveform based on external events and triggers (these are not shown below).

Configure Script Mode

configureRF(vsg, fc, peakPowerLevel_dBm);
configureGenerationMode(vsg, "SCRIPT");
configurePowerLevelType(vsg, "PEAK_POWER");

vsg.Arb.IQRate = fs; 
vsg.Arb.PrefilterGain = -2.0;
vsg.Arb.SignalBandwidth = 2/pulseWidth;

Reconfigure the generator to produce a single chirp waveform by specifying the number of pulses as 1.

release(waveformGenerator)
waveformGenerator.NumPulses = 1;

singleWaveform = waveformGenerator();

Specify the reduction factor, n, as 1000. To understand some of the factors involved in choosing a value for n, refer to the Appendix at the end of this example.

n = 1000;
idleSamplesBrief = idleSamples(1:n);
numRepeats = length(idleSamples)/n;

Configure Pulse Train Using Scripts

The following script shows the steps to generate a pulse train using sequences of smaller segments, first as an NI-RFSG script and then as MATLAB® code. One sequence represents the waveform and another represents the idle period. You can extend the same code to represent longer sequences, as limited by the driver and hardware.

NI-RFSG script

repeat forever
    repeat pulsePerTrain
        generateSingleWaveform
    end repeat
    
    repeat idleWaveform
        generateIdleSamples
    end repeat
end repeat

MATLAB equivalent to the above script

morePendingData = false;
writeArbWaveform(vsg, "singleWaveform", length(singleWaveform), real(singleWaveform), imag(singleWaveform), morePendingData);
writeArbWaveform(vsg, "idleSamples", length(idleSamplesBrief), real(idleSamplesBrief), imag(idleSamplesBrief), morePendingData);

scriptName = "simplePulseTrain";
repeatScript = compose("script %s\n " + ...
                       "repeat forever\n " + ...
                       "repeat %d\n " + ...
                       "generate singleWaveform\n " + ...
                       "end repeat\n " + ...
                       "repeat %d\n " + ...
                       "generate idleSamples\n " + ...
                       "end repeat\n " + ...
                       "end repeat\n " + ...
                       "end script", scriptName, pulsesPerTrain, numRepeats);

writeScript(vsg, repeatScript);

Start a continuous generation.

initiate(vsg);
configureOutputEnabled(vsg, true);
isDone = checkGenerationStatus(vsg);

In this example, stop signal generation after five seconds or if an error occurs. Check the signal generation status for errors every 100 ms.

count = 1;
duration_s = 5;

fprintf('Starting Generation\n')
Starting Generation
while ~isDone && count <= 10*duration_s
    isDone = checkGenerationStatus(vsg);
    pause(0.100)
    count = count+1;
    % display indicator every second
    if mod(count, 10) == 0
        fprintf(".")
    end
end
.....
fprintf('\nStopping Generation')
Stopping Generation

Stop generation.

configureOutputEnabled(vsg, false);
abort(vsg)

Acquire and Plot Waveform

You can verify the generated output by using the vector signal analyzer (VSA) on the VST, when configured as a loopback, as illustrated.

Configure VSA

Set the following parameters to the specified value.

  • Reference clock to onboard clock

  • Acquisition type to I/Q data

  • The reference level to -10 dBm

  • Carrier frequency to the radar center frequency

  • Acquisition rate to the sampling frequency

vsa = ividev("niRFSA", deviceID, "IDQuery", true, "ResetDevice", true);
ch = "0";
configureRefClock(vsa, "OnboardClock", 1e7);
configureAcquisitionType(vsa, "IQ");
configureReferenceLevel(vsa, ch, -10);
configureIQCarrierFrequency(vsa, ch, fc);
configureIQRate(vsa, ch, fs);

Configure the VSA to acquire enough samples to ensure that a complete pulse train is obtained.

finiteSamples = true;
numSamples = 2*lenTrain;

configureNumberOfSamples(vsa, ch, finiteSamples, numSamples);

Start Generation and Acquisition

To fetch IQ data, first start the acquisition, and then start the generation.

initiate(vsa)
initiate(vsg)
configureOutputEnabled(vsg, true);

[iData, qData, waveformSplit] = fetchIQSingleRecordSplitF64(vsa, "", 0, numSamples, 10);

Extract information related to the plot from the waveform information.

t0 = waveformSplit.relativeInitialX;
tincr = waveformSplit.xIncrement;
k = double(waveformSplit.actualSamples);
t = t0 + tincr.*(0:k-1);

figure
plot(t, abs(complex(iData, qData)));
axis tight; grid minor

snap_pulses_acq.png

Clean Up

configureOutputEnabled(vsg, false);
abort(vsg);
abort(vsa);

Reducing Memory Footprint

Waveform_Sequence.jpg

Scripting Pulse Train

Without scripting, you need enough memory for multiple pulse trains. With scripting, you need only a single pulse segment and an idle time segment, reducing memory requirements.

lengthFullWaveform = length(pulseTrain);
lengthSinglePulseTrainFull = length(singleWaveform) + length(idleSamples);
sizeReductionFullIdle = 100 * (1 - lengthSinglePulseTrainFull / lengthFullWaveform);

Scripting Idle Time

To determine a reduction factor, n, consider the following criteria:

  1. It is significantly smaller than the size of the idle waveform.

  2. It divides the length of the idle waveform with no remainder.

  3. It meets or exceeds the size of the smallest allowable waveform (for NI PXI-5841, this is 8). To see how to determine this value programmatically, refer to the following code.

  4. The driver must be able to keep up with the generation. This may require being significantly larger than the smallest allowable waveform.

lengthPulseTrainReduced = length(singleWaveform) + n;
sizeReductionPartialIdle = 100 * (1 - lengthPulseTrainReduced / lengthFullWaveform);

usageFull = [lengthFullWaveform; 100];
usageSinglePulse = [lengthSinglePulseTrainFull; floor(100-sizeReductionFullIdle)];
usagePartialIdle = [lengthPulseTrainReduced; floor(100-sizeReductionPartialIdle)];
usageTable = table(usageFull, usageSinglePulse, usagePartialIdle);
usageTable.Properties.RowNames = ["Number of Samples", "Percent (Full)"];
usageTable.Properties.VariableNames = ["Full Waveform", "Scripted Pulse", "Fully Scripted"];
format long
disp(usageTable)
                         Full Waveform    Scripted Pulse    Fully Scripted
                         _____________    ______________    ______________

    Number of Samples       2624000          1728000            129000    
    Percent (Full)              100               65                 4    

How to Script Idle Time (Considerations)

To review the waveform capabilities, including the minimum waveform size and waveform quantum, refer to the following code.

disp(vsg.Arb.WaveformCapabilities)

Clean Up

clear vsa vsg 

See Also

Related Topics