# Integrated Sensing and Communication I:Radar-Centric Approach Using PMCW Waveform

*Since R2024b*

This example shows how to model a radar-centric Integrated Sensing and Communication (ISAC) system based on a MIMO radar transmitting a PMCW waveform. Part II of this example shows how to model a communication-centric ISAC system based on a generic MIMO-OFDM communication system.

### Introduction

ISAC systems represent a pivotal strategy devised to address challenges posed by the increasingly congested frequency spectrum and the escalating demand for large bandwidth by radar and communication systems. In an ISAC framework, both radar and communication functionalities are integrated to share the same hardware infrastructure, utilizing a common transmit waveform. This example shows how communication capabilities can be added to a MIMO (Multiple Input Multiple Output) radar system that transmits a phase-modulated continuous wave (PMCW) waveform. Given that the communication functionality is embedded within the radar system, this ISAC method is characterized as a radar-centric.

This example considers a scenario when an ISAC system is implemented using a monostatic radar. The primary goal of the radar is to detect and estimate parameters of the targets in its field of view. The goal of the communication function added to the radar is to deliver a data payload to a downlink user.

### System parameters

Consider a radar system operating at a carrier frequency of 77 GHz with a bandwidth of 150 MHz.

% Set the random number generator for reproducibility rng('default'); carrierFrequency = 77e9; % Carrier frequency (Hz) waveLength = freq2wavelen(carrierFrequency); % Wavelength bandwidth = 150e6; % Bandwidth (Hz) sampleRate = bandwidth; % Assume the sample rate is equal to the bandwidth

Create a transmitter assuming the peak transmit power is 1 W.

peakPower = 1; % Peak power (W) transmitter = phased.Transmitter('PeakPower', peakPower, 'Gain', 0);

Create a radar receiver and set the noise figure to 3 dB and the reference noise temperature to 290 K.

noiseFigure = 3.0; % Noise figure (dB) referenceTemperature = 1; % Reference temperature (K) radarReceiver = phased.Receiver('SampleRate', sampleRate, 'NoiseFigure', noiseFigure,... 'ReferenceTemperature', referenceTemperature, 'AddInputNoise', true,... 'InputNoiseTemperature', referenceTemperature, 'Gain', 0);

Let the transmitter have a uniform linear array (ULA) of four isotropic antennas spaced at half a wavelength apart.

Ntx = 4; % Number of transmit antenna elements element = phased.IsotropicAntennaElement('BackBaffled', true); txArray = phased.ULA(Ntx, waveLength/2, 'Element', element);

Let the radar receiver also have a ULA of four isotropic elements that are spaced `Ntx*waveLength/2`

meters apart. Such spacing is required to create a largest possible virtual aperture for the MIMO radar without causing grating lobes.

Nrx = 4; % Number of receive antenna elements at the radar receiver rxArray = phased.ULA(Nrx,Ntx*waveLength/2, 'Element', element);

Create a downlink user receiver and set the noise figure to 3.3 dB and the reference noise temperature to 290 K.

downlinkNoiseFigure = 3.3; % Noise figure at the downlink receiver (dB) downlinkReferenceTemperature = 290; % Reference temperature at the downlink receiver (dB) downlinkReceiver = phased.Receiver('SampleRate', sampleRate, 'NoiseFigure', downlinkNoiseFigure,... 'ReferenceTemperature', downlinkReferenceTemperature, 'AddInputNoise', true,... 'InputNoiseTemperature', downlinkReferenceTemperature, 'Gain', 0);

Let the downlink user have a single omnidirectional antenna.

downlinkAntenna = phased.IsotropicAntennaElement;

### ISAC Scenario

Let the radar transmitter and receiver be located at the origin. Point the transmit and the receive array normals along the x-axis.

radarPosition = [0; 0; 0]; % Location of the transmitter (m) radarOrientationAxis = eye(3); % Tx array orientation

Set the downlink user position to be some distance away from the radar transmitter.

`userPosition = [80; 60; 0]; % Location of the receiver (m)`

This example assumes that the transmitter, the radar receiver, and the downlink receiver are static.

The environment encompassing the area between the transmitter and the downlink receiver is populated with scatterers. These scatterers can be static or they can be moving. Within the context of the sensing function, the scatterers present in the communication channel, regardless of their state of motion, are considered as radar targets.

Let the three moving scatterers be the targets of interest.

targetPositions = [60 70 90; % Target positions (m) -25 15 30; 0 0 0]; targetVelocities = [-15 20 0; % Target velocities (m/s) 12 -10 25; 0 0 0]; % Platform to model target motion targetMotion = phased.Platform('InitialPosition', targetPositions, 'Velocity', targetVelocities); % The values of the reflection coefficients are chosen on random targetReflectionCoefficients = randn(1, size(targetPositions, 2)) + 1i*randn(1, size(targetPositions, 2));

Since this example simulates a monostatic radar, it is convenient to know the values of the range, azimuth, and radial velocity for the targets of interest.

[targetAzimuth, ~, targetRange] = cart2sph(targetPositions(1, :), targetPositions(2, :), targetPositions(3, :)); targetAzimuth = rad2deg(targetAzimuth); targetRadialVelocity = sum(targetVelocities.*(targetPositions./vecnorm(targetPositions))); for i = 1:size(targetPositions, 2) fprintf("Target %d: range=%.2f (m), azimuth=%.2f (deg), radial velocity = %.2f\n", i,... targetRange(i), targetAzimuth(i), targetRadialVelocity(i)); end

Target 1: range=65.00 (m), azimuth=-22.62 (deg), radial velocity = -18.46 Target 2: range=71.59 (m), azimuth=12.09 (deg), radial velocity = 17.46 Target 3: range=94.87 (m), azimuth=18.43 (deg), radial velocity = 7.91

The rest of the scatterers in the scene are static. Use `helperGenerateStaticScatterers`

helper function to generate positions of the static scatterers within some region of interest.

regionOfInterest = [0 120; -80 80]; % Bounds of the region of interest numScatterers = 200; % Number of scatterers distributed within the region of interest [scattererPositions, scattererReflectionCoefficients] = helperGenerateStaticScatterers(numScatterers, regionOfInterest);

Use two separate `phased.ScatteringMIMOChannel`

objects to model the propagation channels between the transmitter and the radar receiver, and between the transmitter and the downlink user.

radarChannel = phased.ScatteringMIMOChannel('CarrierFrequency', carrierFrequency, 'TransmitArray', txArray,... 'TransmitArrayPosition', radarPosition, 'ReceiveArray', rxArray, 'ReceiveArrayPosition', radarPosition,... 'TransmitArrayOrientationAxes', radarOrientationAxis, 'ReceiveArrayOrientationAxes', radarOrientationAxis,... 'SampleRate', sampleRate, 'SimulateDirectPath', false, 'ScattererSpecificationSource', 'Input Port'); commChannel = phased.ScatteringMIMOChannel('CarrierFrequency', carrierFrequency, 'TransmitArray', txArray,... 'TransmitArrayPosition', radarPosition, 'ReceiveArray', downlinkAntenna, 'ReceiveArrayPosition', userPosition,... 'TransmitArrayOrientationAxes', radarOrientationAxis, 'SampleRate', sampleRate,... 'SimulateDirectPath', true, 'ScattererSpecificationSource', 'Input Port');

Visualize the channels using `helperVisualizeScatteringMIMOChannel`

helper function.

helperVisualizeScatteringMIMOChannel(radarChannel, scattererPositions, targetPositions, targetVelocities) plot(userPosition(2), userPosition(1), 'pentagram', 'DisplayName', 'Downlink user Rx', 'MarkerSize', 16,... 'Color', '#A2142F', 'MarkerFaceColor', '#A2142F') title('Scattering MIMO Channel for Radar-Centric ISAC Scenario');

### Signaling Scheme

A PMCW radar repeatedly transmits a selected phase-coded sequence. The duration of the transmitted sequence is called a modulation period. Since the duty cycle of a PMCW radar is equal to one, the next modulation period starts right after the previous. This example uses a maximum length pseudo-random binary sequence (PRBS) also frequently referred to as an m-sequence. Maximum length sequences have low autocorrelation sidelobes that result in a good range estimation performance.

Create a 255 chips long PRBS.

Nchip = 255; % Length of the PRBS prbs = mlseq(Nchip); % Maximum length sequence

Given that the chip duration of a phase-modulated waveform is an inverse of the total bandwidth, compute the modulation period.

chipWidth = 1/bandwidth; % Chip duration modulationPeriod = Nchip * chipWidth; % Modulation period

The modulation period determines the maximum unambiguous range of the radar, that is to unambiguously measure a target's range the echo from the target needs to come back before a modulation period is over.

`fprintf("Maximum unambiguous range: %.2f (m).\n", time2range(modulationPeriod));`

Maximum unambiguous range: 254.82 (m).

In order to implement a MIMO radar, each transmit antenna must transmit an orthogonal sequence. One way to achieve orthogonality is to use different orthogonal sequences for each antenna. This approach is expensive as it requires as many different correlators at the receiver as there are transmit antennas. Additionally, in practice it might be hard to achieve good range sidelobes and good crosscorrelation properties for all time delays of interest and all transmitted waveforms.

Another approach is to use outer codes. This example uses the Hadamard code for outer coding. Let `H`

be an `Ntx*Ntx`

Hadamard matrix. Each antenna transmits the same PRBS `Ntx`

times, but each repetition of the sequence is multiplied by a corresponding entry in `H.`

Specifically, the columns of `H`

correspond to the transmit antennas, and the rows correspond to the repetitions of the PRBS. To separate echoes from each transmitter at each receive antenna, the `Ntx`

received repetitions of the transmitted sequence are multiplied by the corresponding values in the Hadamard code matrix `H`

and then summed together.

Use the `hadamard`

function to generate a matrix of Hadamard outer codes and create an outer coded transmit sequences for each antenna.

H = hadamard(Ntx); outterCodedPRBS = kron(H, prbs);

Compute the duration and the length of an outer coded PRBS.

blockDuration = modulationPeriod * Ntx; blockLength = Nchip * Ntx;

A set of outer coded PRBS transmitted by each transmit antenna constitutes a single transmit block. Each such block can carry `Ntx`

bits of user data - one bit per transmit antenna. This is achieved by multiplying sequences transmitted by each antenna by a corresponding BPSK symbol as shown on the following diagram.

### Received Signal Simulation

Simulate transmission of total 256 outer coded blocks.

`Nb = 256; % Total number of transmitted blocks`

Since the targets are moving, the communication channel between the transmitter and the downlink user is going to be time varying. To account for this variation a fresh estimate of the channel matrix must be obtained at regular intervals. In this example, the channel sounding is performed by transmitting an unmodulated outer coded PRBS. Assuming that the downlink user has a full knowledge of the transmitted sequence, the channel estimate can be obtained on the receive side using the standard channel estimation approaches such as zero forcing.

Perform channel sounding every `M`

blocks.

M = 32; % Perform sounding every Mth block numSoundBlocks = numel(1:M:Nb); % Total number of sounding blocks fprintf("Channel matrix update period: %.2f (ms).\n", blockDuration*M*1e3);

Channel matrix update period: 0.22 (ms).

Preallocate space to store transmitted data.

txDataBin = ones(Nb-numSoundBlocks, Ntx); txDataBpsk = ones(Nb, Ntx);

Preallocate space for signals received at the radar receiver and the downlink user receiver.

radarRxSignal = zeros(blockLength, Nrx, Nb); commRxSignal = zeros(blockLength, Nb + 1);

Transmit one block at a time. Propagate it through the radar and the communication channels and store the signals received at the radar and the downlink receivers.

it = 0; for i = 1:Nb if mod(i - 1, M) == 0 % Communication channel sounding % Transmit the outer codded PRBS without any data added to it pmcwSignal = outterCodedPRBS; else % Data transmission % Generate binary payload and peform BPSK modulation it = it + 1; txDataBin(it, :) = randi([0 1], [1 Ntx]); txDataBpsk(i, :) = pskmod(txDataBin(it, :), 2); % Modulate the outer coded PRBS with the BPSK data payload pmcwSignal = outterCodedPRBS .* txDataBpsk(i, :); end % Transmit signal txSignal = transmitter(pmcwSignal); % Update target positions [targetPositions, targetVelocities] = targetMotion(blockDuration); % Simulate signal propagation through the radar channel - from % transmitter to the scatterers and back to the radar receiver radarChannelSignal = radarChannel(txSignal, [scattererPositions targetPositions],... [zeros(size(scattererPositions)) targetVelocities],... [scattererReflectionCoefficients targetReflectionCoefficients]); % Simulate signal propagation through the comm channel - from % transmitter to the scatterers and to the downlink user commChannelSignal = commChannel(txSignal, [scattererPositions targetPositions],... [zeros(size(scattererPositions)) targetVelocities],... [scattererReflectionCoefficients targetReflectionCoefficients]); % Add thermal noise at the receiver radarRxSignal(:, :, i) = radarReceiver(radarChannelSignal); commRxSignal(:, i) = downlinkReceiver(commChannelSignal); end

After `Nb`

iterations, due to the channel delay between the transmitter and the downlink user, a portion of the last transmitted block remains in the channel buffer. To fully receive the last transmitted symbol flush the communication channel buffer.

commChannelSignal = commChannel(zeros(size(txSignal)), [scattererPositions targetPositions],... [zeros(size(scattererPositions)) targetVelocities],... [scattererReflectionCoefficients targetReflectionCoefficients]); commRxSignal(:, end) = downlinkReceiver(commChannelSignal);

### Received Signal Processing

#### At Radar Receiver

The dimensions of the received base band signal at the radar receiver are `Nchip*Ntx`

-by-`Nrx`

-by-`Nb`

. Here, the first dimension is the fast-time dimension. It has a length of N`chip*Ntx`

corresponding to the `Nchip`

long PRBS repeated `Ntx`

times to implement the outer coding. The second dimension is the spatial dimension of length `Nrx`

equal to the number of receive antennas. Finally, the third dimension is the slow-time dimension of length `Nb`

equal to the number of transmitted blocks.

The following diagram shows the signal processing steps at the radar receiver.

The first step is to separate signals transmitted by different transmit antennas at each receiver. Use `helperDecodeMIMOPMCW`

helper function to decode the outer coded received sequences.

radarRxSignalDecoded = helperDecodeMIMOPMCW(radarRxSignal, H);

The dimension of the signal after decoding is `Nchip`

-by-`Ntx`

-by-`Nrx`

-by-`Nb.`

The next step is to remove the data payload. This is accomplished by multiplying the received signals with the corresponding transmitted BPSK symbols.

for i = 1:Nb radarRxSignalDecoded(:, :, :, i) = radarRxSignalDecoded(:, :, :, i) .* txDataBpsk(i, :); end

Once the communication data has been removed, form a radar data cube such that the channel dimension corresponds to a virtual array of `Ntx*Nrx `

elements created by convolving the transmit and the receive array apertures.

radarDataCube = reshape(radarRxSignalDecoded, Nchip, Ntx*Nrx, Nb);

Perform matched filtering in the frequency domain.

prbsDFT = fft(prbs); Z = fft(radarDataCube) .* conj(prbsDFT);

This example models a scenario with a very large number of radar targets. However, not all of the observed targets are targets of interest. If the targets of interest are the moving scatterers, the static scatterers can be filtered out in the Doppler domain since the Doppler shift from a static scatterer is equal to zero. Perform FFT over the slow-time dimension and zero out the DC component to remove static scatterers.

Y = fft(Z, [], 3); Y(:, :, 1) = 0; y = ifft(Y, Nb, 3);

To perform range-angle processing, first use `helperVirtualArray`

helper function to combine the transmit and the receive arrays into a MIMO virtual array. After that compute the range-angle response.

virtualArray = helperVirtualArray(txArray, rxArray); rangeAngleResponse = phased.RangeAngleResponse('SensorArray', virtualArray, 'RangeMethod', 'FFT', 'SampleRate', sampleRate,... 'SweepSlope', bandwidth/modulationPeriod, 'OperatingFrequency', carrierFrequency, 'ReferenceRangeCentered', false); [rar, r, theta] = rangeAngleResponse(conj(y)); theta = theta * (-1); % -1 to account for conj in the range-angle response

Combine range-angle responses computed from all received blocks using non-coherent integration, then plot the range-angle response.

rar_integ = sum(abs(rar), 3); figure; imagesc(theta, r, rar_integ); ax = gca; set(ax, 'YDir', 'normal') ; colorbar; xlabel('Azimuth Angle (deg)'); ylabel('Range (m)'); title('Range-Angle Response'); grid on; ylim(regionOfInterest(1, :)); hold on; plot(targetAzimuth, targetRange, 'o', 'LineWidth', 1, 'MarkerSize', 32, 'Color', '#D95319',... 'MarkerFaceColor', 'none', 'DisplayName', 'Targets of interest'); legend

Using signals received over multiple transmitted blocks compute the range-Doppler map.

rangeDopplerResponse = phased.RangeDopplerResponse('RangeMethod', 'FFT', 'DopplerOutput', 'Speed',... 'OperatingFrequency', carrierFrequency, 'SampleRate', sampleRate, 'SweepSlope', bandwidth/modulationPeriod,... 'PRFSource', 'Property', 'PRF', 1/blockDuration, 'ReferenceRangeCentered', false); [rdr, r, doppler] = rangeDopplerResponse(conj(y)); doppler = doppler * (-1); % -1 to account for conj in the range-do response

Combine signals from all transmit-receive paths using non-coherent integration and plot the range-doppler response.

figure; rdr_integ = squeeze(sum(abs(rdr), 2)); figure; imagesc(doppler, r, rdr_integ); ax = gca; set(ax, 'YDir', 'normal') ; colorbar; xlabel('Speed (m/s)'); ylabel('Range (m)'); title('Range-Doppler Response'); grid on; xlim([-50 50]); ylim(regionOfInterest(1, :)); hold on; plot(targetRadialVelocity, targetRange, 'o', 'LineWidth', 1, 'MarkerSize', 32, 'Color', '#D95319',... 'MarkerFaceColor', 'none', 'DisplayName', 'Targets of interest'); legend

#### At Downlink Receiver

This example simulates transmission of `Nb`

outer coded PMCW blocks with each block carrying Ntx BPSK symbols. The following diagram shows the signal processing steps at the downlink receiver.

Due to delay, the end of the i-th block arrives to the downlink user during the next (i+1)-st iteration. Hence, to process the received signal, the downlink receiver must first buffer two consecutive blocks, then estimate the starting position of the current block, and finally process `blockLength`

samples starting from that position.

Stack signals from the current and the following received blocks to simulate a buffer and then use `helperCommChannelDelay`

helper function to estimate the start of the current received block.

commRxBuffer = [commRxSignal(:, 1:Nb); commRxSignal(:, 2:(Nb+1))]; d = helperCommChannelDelay(commRxBuffer(1:Nchip, :), prbs);

Process `blockLength`

samples starting from the estimated start position.

idx = sub2ind(size(commRxBuffer), d + (0:blockLength-1).', repmat(1:Nb, blockLength, 1)); commRxBuffer = commRxBuffer(idx);

Separate received signals from different transmitters by removing the outer codes.

commRxSignalDecoded = helperDecodeMIMOPMCW(commRxBuffer, H);

Process each received block one at a time.

rxDataBpsk = zeros([Nb-numSoundBlocks Ntx]); ir = 0; for i = 1:Nb if mod(i - 1, M) == 0 % Estimate channel matrix if unmodulated PRBS was transmitted channelMatrix = fft(commRxSignalDecoded(:, :, i))./prbsDFT; else % Perform channel equalization commRxSignalEqualized = (fft(commRxSignalDecoded(:, :, i)) .* conj(prbsDFT))./channelMatrix; y = ifft(commRxSignalEqualized); % Demodulate the signal to obtain the BPSK symbols. [~, idx] = max(abs(y), [], 'linear'); ir = ir + 1; rxDataBpsk(ir, :) = y(idx)/Nchip; end end

Plot the BPSK constelation for the received data.

refconst = pskmod([0 1], 2); constellationDiagram = comm.ConstellationDiagram('NumInputPorts', 1, ... 'ReferenceConstellation', refconst, 'ChannelNames', {'Received QAM Symbols'}); constellationDiagram(rxDataBpsk(:));

Compute the bit error rate.

rxDataBin = pskdemod(rxDataBpsk(:), 2); [numErr,ratio] = biterr(txDataBin(:), rxDataBin(:))

numErr = 0

ratio = 0

### Conclusion

This example simulates a radar-centric ISAC system. It begins by defining a scenario where a monostatic radar system simultaneously senses the surrounding environment and transmits a data payload to a downlink user. The setup includes a signaling scheme based on PMCW waveform and outer coding to implement a MIMO radar. Communication data is embedded into the transmitted radar waveform by multiplying the sequences transmitted by each transmit antenna with the corresponding data bits. The example shows transmission, propagation and reception of the generated waveform, followed by signal processing steps at both the radar and downlink user receivers. At the radar receiver, range-angle and range-Doppler responses are estimated, while at the downlink receiver, the transmitted data payload is recovered from the received signal.

### References

de Oliveira, Lucas Giroto, Benjamin Nuss, Mohamad Basim Alabd, Axel Diewald, Mario Pauli, and Thomas Zwick. "Joint radar-communication systems: Modulation schemes and system design."

*IEEE Transactions on Microwave Theory and Techniques*70, no. 3 (2021): 1521-1551.Sturm, Christian, and Werner Wiesbeck. "Waveform design and signal processing aspects for fusion of wireless communications and radar sensing."

*Proceedings of the IEEE*99, no. 7 (2011): 1236-1259.Bourdoux, André, Ubaid Ahmad, Davide Guermandi, Steven Brebels, Andy Dewilde, and Wim Van Thillo. "PMCW waveform and MIMO technique for a 79 GHz CMOS automotive radar." In

*2016 IEEE Radar Conference (RadarConf)*, pp. 1-5. IEEE, 2016.

### Supporting Functions

function y = helperDecodeMIMOPMCW(xin, H) % Combine received signals in the columns of xin based on the Hadamard % matrix outer code in H [N, Nrx, Nb] = size(xin); Ntx = size(H, 1); L = N/Ntx; x = reshape(xin, L, Ntx, Nrx, Nb); y = zeros(L, Ntx, Nrx, Nb); for ntx = 1:Ntx h = repmat(H(ntx, :), L, 1, Nrx, Nb); y(:, ntx, :, :) = sum(x .* h, 2); end end function idx = helperCommChannelDelay(x, s) % Estimate delay using cross-correlation Nb = size(x, 2); idx = zeros(1, Nb); for i = 1:Nb [r, lags] = xcorr(x(:, i), s); r = r(lags >= 0); [~, idx(i)] = max(abs(r)); end end function vArray = helperVirtualArray(txArray, rxArray) % Combine txArray and rxArray into a virtual array by convolving their % apertures txElementPositions = getElementPosition(txArray); N = getNumElements(txArray); rxElementPositions = getElementPosition(rxArray); M = getNumElements(rxArray); vElemenetPositions = zeros(3, N*M); for m = 1:M vElemenetPositions(:, (m-1)*N+1:m*N) = rxElementPositions(:, m) + txElementPositions; end vArray = phased.ConformalArray('ElementPosition', vElemenetPositions); end