The FMCW radar with the following parameters was implemented:

% System parameters Value

% ----------------------------------

% Operating frequency (GHz) 77

% Maximum target range (m) 15

% Range resolution (m) 0.037

% Maximum target speed (km/h) 30 for fall detection

% Sweep time (microseconds) 50

% Sweep bandwidth (GHz) 4

% Maximum beat frequency (MHz) 73

% Sample rate (GHz) 4.050

A target was simulated with the following parameters(static radar)

dist = 14;

speed = 10*1000/3600; ;%2.77km/h

rcs = 100;

and the Range Doppler image plotted using the phased array functions.

RangeFFTLength = 2048;

DopplerFFTLength = 512;

rngdopresp = phased.RangeDopplerResponse('PropagationSpeed',c,... 'DopplerOutput','Speed','OperatingFrequency',fc,'SampleRate',fs,... 'RangeMethod','FFT','SweepSlope',sweep_slope,... 'RangeFFTLengthSource','Property','RangeFFTLength',RangeFFTLength,... 'DopplerFFTLengthSource','Property','DopplerFFTLength',DopplerFFTLength);



[![enter image description here][1]][1]

The results are as expected.

Interested to get the same results implementing the 2DFFT manually.

For this purpose the following code was used:

Nr = RangeFFTLength;

Nd = DopplerFFTLength;

% 2D FFT using the FFT size for both dimensions.

sig_fft2 = fft2(xr,Nr,Nd);

% Taking just one side of signal from Range dimension.

sig_fft2 = sig_fft2(1:Nr/2,1:Nd);

sig_fft2 = fftshift (sig_fft2);

RDM = abs(sig_fft2);

RDM = 10*log10(RDM);

Yielding the following:

enter image description here

The index of the range and velocity are: [518 229].

This yields the following values:



range_max = cfb/(2sweep_slope);

distance = ((518-512)/512)*range_max

distance =


This is 3 times larger then the correct value. Why?


Converting the index to the abs value using the following, yields correct value:

vel_max = lambda/(4*tm);

sp = ((293-256)/256)*vel_max

sp =


Seems, however, that the velocity in this case is positive – why? The code can be seen below:


  • $\begingroup$ Is this all of your code? $\endgroup$
    – Envidia
    Sep 16, 2020 at 5:30
  • $\begingroup$ This is not all the code. The full code is now attached to the original message. $\endgroup$
    – SenSen
    Sep 17, 2020 at 3:10
  • $\begingroup$ Mind granting public access to the code? $\endgroup$
    – Envidia
    Sep 17, 2020 at 3:47
  • $\begingroup$ Sorry - opened up. $\endgroup$
    – SenSen
    Sep 17, 2020 at 17:04

1 Answer 1


So the problem is that when simulating FMCW signals, there is some ambiguity in the convention on the mixing order. MATLAB's documentation makes reference to it here:

"The mix operation reverses the Doppler shift embedded in x, because of the mixing order of xref and x. The mixing order affects the sign of the imaginary part of the output argument, y. There is no consistent convention in the literature about the mixing order. This function and the beat2range function use the same convention. If your program processes the output of dechirp in other ways, take the mixing order into account."

So you're amost there. MATLAB's functions account for this so you need to account for the change yourself when doing the manual range-Doppler map. You can do this by applying a complex exponential to each pulse that shifts the phase in the other direction so that it will produce the right Doppler shift.

For example, in the simulation loop right before you assign the dechirped signal to xr do something like the code below. I currently don't have the Phased Array Toolbox installed so I did some of the calculations manually:

for m = 1:Nsweep

    % After all the target sim stuff do your own Doppler calculations
    rangeToTarget = norm(tgt_pos - radar_pos);
    radialVel = dot(tgt_vel - radar_vel, tgt_pos - radar_pos)/rangeToTarget;

    % Negate Doppler so that closing targets produce positive frequencies
    fd = -2*radialVel/lambda;

    % De-chirp and apply phase shift for this pulse to reverse Doppler
    % to the correct value
    xr(:,m) = dechirpsig*exp(1i*2*pi*(2*fd)*(m - 1)*tm);


This uses the simple "stop and hop" model where the target moves in discrete time steps which are equal to the sweep time tm.

Addressing Range Issue

I totally to forgot to address the range part of your question. The reason this is happening is because when you use MATLAB's functions to generate the range-Doppler map, you are giving it a sampling rate $f_s = 4 \space GHz$, which in turn yields a range-bin (or range-cell) size $\delta R $ of

$$\delta R = \frac{c}{2B} = \frac{c}{2(4e9)} = 0.0375 \space m$$

If you had set RangeFFTLength = numel(waveform) when doing your own 2D FFT, you would have a HUGE number of samples in the range dimension, but it would be correct given the achieved range-bin resolution $\delta R$ and will give you the correct target ranges.

The problem now comes that when you use less range samples than what you started with by setting RangeFFTLength = 2048. This decimates the effective sampling rate, so your new range-bin size is now going to be artificially larger. If you take the ratio of the number of samples produced by using $f_s = 4 \space GHz$ and the size of the range FFT of 2048, your effective sampling rate is now 98 times worse! So your new range bin size becomes

$$\delta R_{new} = 98\frac{c}{2B} = 98\frac{c}{2(4e9)} = 3.675 \space m$$

Applying this range-bin size to the peak range index should yield the correct range in your range-Doppler map. However, note that this is still wrong. I say that because the whole point of putting that much bandwidth into a chirp is so that each range-bin in the range-Doppler map is equal to to 0.0375 m and NOT 3.675 m.

If you did it correctly, you would be able to sample at a much lower rate since your beat frequencies after mixing have lower bandwidth requirements, giving you a smaller and reasonable number of samples. Each range-bin size is still 0.0375 m, preserving the range resolution desired.

  • $\begingroup$ Thank you for the detailed response @Envidia. Though this explains the sign, I am still confused as to how the Range absolute value is to be calculated. $\endgroup$
    – SenSen
    Sep 20, 2020 at 1:33
  • $\begingroup$ @SenSen I updated to include the range stuff, I apologize for forgetting to include it. $\endgroup$
    – Envidia
    Sep 20, 2020 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.