├── README.md ├── cfar_implementation.m ├── images ├── cfar_filtered_rdm.jpg ├── range_1st_fft.jpg └── range_doppler_map.jpg ├── main.m ├── radar_specs.m ├── radar_target_steps.m ├── range_doppler_response.m ├── range_measurement.m ├── signal_generation.m ├── target_definition.m └── waveform_generation.m /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This project simulates a Frequency-Modulated Continuous Wave (FMCW) radar system for target detection. FMCW radar is a type of radar system that continuously transmits a signal whose frequency changes over time, typically in a sweep pattern. By analyzing the frequency difference between the transmitted and received signals, FMCW radar can determine both the range and velocity of targets. 4 | 5 | ### Key Concepts 6 | 7 | 1. FMCW Radar: A radar system that transmits continuous waves with frequency modulation, allowing for simultaneous range and velocity measurements. 8 | 9 | 2. Target Generation: In this simulation, we create a virtual target with defined initial position and velocity. This "generated" target represents an object that our simulated radar will attempt to detect. 10 | 11 | 3. Target Detection: The process of identifying the presence, range, and velocity of the target using signal processing techniques on the received radar signals. 12 | 13 | ### Project Structure 14 | 15 | The simulation is divided into several scripts for better modularity and understanding: 16 | 17 | 1. `main.m`: The main script that runs the entire simulation by calling other modules. 18 | 2. `radar_specs.m`: Defines the radar specifications such as frequency, max range, and resolution. 19 | 3. `target_definition.m`: Sets up the target's initial position and velocity. 20 | 4. `waveform_generation.m`: Generates the FMCW waveform based on radar specifications. 21 | 5. `signal_generation.m`: Simulates the transmitted and received signals, including target movement. 22 | 6. `range_measurement.m`: Performs initial FFT for range measurement and visualization. 23 | 7. `range_doppler_response.m`: Generates and visualizes the Range-Doppler Map (RDM). 24 | 8. `cfar_implementation.m`: Implements the CA-CFAR algorithm for target detection in the RDM. 25 | 26 | This modular structure allows for easier understanding of each step in the radar simulation process. Users can modify individual components or use them as building blocks for more complex radar simulations. 27 | 28 | ### Generated Images 29 | 30 | The simulation generates and saves the following images: 31 | 32 | 1. `range_1st_fft.png`: Shows the range measurement from the first FFT. 33 | 2. `range_doppler_map.png`: Displays the Range-Doppler Map (RDM) generated from the 2D FFT. 34 | 3. `cfar_filtered_rdm.png`: Illustrates the CA-CFAR filtered Range-Doppler Map. 35 | 36 | These images provide visual representations of the radar's output at different stages of processing, helping to understand the target detection process. 37 | 38 | To run the simulation, execute the `main.m` script in MATLAB or Octave. The images will be saved in the `./images` directory. 39 | 40 | ``` 41 | octave main.m 42 | ``` 43 | 44 | 45 | ## Installation 46 | 47 | Required Packages: 48 | Ubuntu 22.04 49 | Octave 7.4.0 50 | Control Systems Toolbox 51 | Signal Processing Toolbox 52 | 53 | 54 | ``` 55 | git clone https://github.com/davidsosa/radar-target-generation-and-detection.git 56 | ``` 57 | 58 | Install Octave and Required Packages for Control and Signal Processing Toolboxes 59 | 60 | ``` 61 | sudo apt-add-repository ppa:octave/stable 62 | sudo apt update 63 | sudo apt-get install octave octave-control octave-signal 64 | sudo apt install gfortran liboctave-dev libopenblas-dev 65 | sudo apt install build-essential # Install the build-essential package 66 | ``` 67 | 68 | Inside of Octave: 69 | ``` 70 | pkg install -forge control 71 | pkg install -forge signal 72 | ``` 73 | 74 | 75 | 76 | 77 | ## Radar Specifications 78 | 79 | ```{.codeinput} 80 | % Frequency of operation = 77GHz 81 | % Max Range = 200m 82 | % Range Resolution = 1 m 83 | % Max Velocity = 100 m/s 84 | ``` 85 | 86 | ## User Defined Range and Velocity of target 87 | 88 | https://github.com/davidsosa/radar-target-generation-and-detection/blob/master/radar-target-generation-and-detection.m#L19 89 | 90 | We define the target's initial position and velocity. Note: velocity remains constant 91 | 92 | ```{.codeinput} 93 | range = 110 94 | vel = -20 95 | max_range = 200 96 | range_res = 1 97 | max_vel = 100 % m/s 98 | ``` 99 | 100 | ## FMCW Waveform Generation 101 | https://github.com/davidsosa/radar-target-generation-and-detection/blob/master/radar-target-generation-and-detection.m#L30 102 | 103 | ```{.codeinput} 104 | % Design the FMCW waveform by giving the specs of each of its parameters. 105 | % Calculate the Bandwidth (B), Chirp Time (Tchirp) and slope (slope) of the FMCW 106 | % chirp using the requirements above. 107 | 108 | % Operating carrier frequency of Radar 109 | % The sweep time can be computed based on the time needed for the signal to travel the unambiguous 110 | % maximum range. In general, for an FMCW radar system, the sweep time should be at least 111 | % 5 to 6 times the round trip time. This example uses a factor of 5.5. 112 | 113 | B = c / (2*range_res) 114 | Tchirp = 5.5 * 2 * (max_range/c) 115 | slope = B/Tchirp 116 | 117 | % Operating carrier frequency of Radar 118 | fc= 77e9; % carrier freq 119 | 120 | %The number of chirps in one sequence. Its ideal to have 2^ value for the ease of running the FFT 121 | %for Doppler Estimation. 122 | Nd = 128; % #of doppler cells OR #of sent periods % number of chirps 123 | 124 | %The number of samples on each chirp. 125 | Nr = 1024; %for length of time OR # of range cells 126 | 127 | % Timestamp for running the displacement scenario for every sample on each 128 | % chirp 129 | t = linspace(0,Nd*t_chirp,Nr*Nd); %total time for samples 130 | 131 | %Creating the vectors for Tx, Rx and Mix based on the total samples input. 132 | Tx = zeros(1, length(t)); %transmitted signal 133 | Rx = zeros(1, length(t)); %received signal 134 | Mix = zeros(1, length(t)); %beat signal 135 | 136 | %Similar vectors for range_covered and time delay. 137 | r_t = zeros(1, length(t)); 138 | td = zeros(1, length(t)); 139 | ``` 140 | 141 | ## Signal generation and Moving Target simulation 142 | 143 | https://github.com/davidsosa/radar-target-generation-and-detection/blob/master/radar-target-generation-and-detection.m#L61 144 | 145 | Running the radar scenario over the time. 146 | 147 | ```{.codeinput} 148 | 149 | for i=1:length(t) 150 | %For each time stamp update the Range of the Target for constant velocity. 151 | r_t(i) = range + (vel*t(i)); 152 | td(i) = (2 * r_t(i)) / c; 153 | 154 | % For each time sample we need update the transmitted and 155 | % received signal. 156 | 157 | Tx(i) = cos(2*pi*(fc*t(i) + (slope*t(i)^2)/2 ) ); 158 | Rx(i) = cos(2*pi*(fc*(t(i) -td(i)) + (slope * (t(i)-td(i))^2)/2 ) ); 159 | 160 | %Now by mixing the Transmit and Receive generate the beat signal 161 | %This is done by element wise matrix multiplication of Transmit and 162 | %Receiver Signal 163 | 164 | Mix(i) = Tx(i) .* Rx(i); 165 | end 166 | ``` 167 | 168 | ## RANGE MEASUREMENT 169 | https://github.com/davidsosa/radar-target-generation-and-detection/blob/master/radar-target-generation-and-detection.m#L82 170 | 171 | ```{.codeinput} 172 | %reshape the vector into Nr*Nd array. Nr and Nd here would also define the size of 173 | %Range and Doppler FFT respectively. 174 | Mix = reshape(Mix, [Nr, Nd]); 175 | 176 | %run the FFT on the beat signal along the range bins dimension (Nr) and 177 | %normalize. 178 | signal_fft = fft(Mix, Nr); 179 | 180 | % Take the absolute value of FFT output 181 | signal_fft = abs(signal_fft); 182 | signal_fft = signal_fft ./ max(signal_fft); % Normalize 183 | 184 | % Output of FFT is double sided signal, but we are interested in only one side of the spectrum. 185 | % Hence we throw out half of the samples. 186 | signal_fft = signal_fft(1 : Nr/2-1); 187 | 188 | % Plotting 189 | figure('Name', 'Range from First FFT'); 190 | plot(signal_fft); 191 | axis([0 200 0 1]); 192 | title('Range from First FFT'); 193 | ylabel('Amplitude (Normalized)'); 194 | xlabel('Range [m]'); 195 | 196 | % Save the figure 197 | saveas(gcf, 'range_1st_fft.png'); 198 | ``` 199 | 200 | ![](./images/range_1st_fft.jpg/) 201 | 202 | The 2D FFT implementation is already provided here. This will run a 2DFFT on the mixed 203 | signal (beat signal) output and generate a range doppler map. 204 | CFAR is applied to the generated RDM 205 | 206 | 207 | ```{.codeinput} 208 | % Range Doppler Map Generation. 209 | 210 | % The output of the 2D FFT is an image that has reponse in the range and 211 | % doppler FFT bins. So, it is important to convert the axis from bin sizes 212 | % to range and doppler based on their Max values. 213 | 214 | Mix=reshape(Mix,[Nr,Nd]); 215 | 216 | % 2D FFT using the FFT size for both dimensions. 217 | signal_fft2 = fft2(Mix,Nr,Nd); 218 | 219 | % Taking just one side of signal from Range dimension. 220 | signal_fft2 = signal_fft2(1:Nr/2,1:Nd); 221 | signal_fft2 = fftshift (signal_fft2); 222 | 223 | RDM = abs(signal_fft2); 224 | RDM = 10*log10(RDM) ; 225 | 226 | % Plotting 227 | doppler_axis = linspace(-100, 100, Nd); 228 | range_axis = linspace(-200, 200, Nr/2)*((Nr/2)/400); 229 | 230 | figure('Name', 'Range Doppler Map'); 231 | surf(doppler_axis, range_axis, RDM); 232 | title('Amplitude and Range From FFT2'); 233 | xlabel('Speed'); 234 | ylabel('Range'); 235 | zlabel('Amplitude'); 236 | 237 | % Save the figure 238 | saveas(gcf, 'range_doppler_map.png'); 239 | ``` 240 | 241 | ![](./images/range_1st_fft.jpg/) 242 | ![](./images/range_2nd_fft.jpg/) 243 | 244 | CFAR implementation {#8} 245 | 246 | --- 247 | 248 | ```{.codeinput} 249 | %Slide Window through the complete Range Doppler Map 250 | 251 | %Select the number of Training Cells in both the dimensions. 252 | n_train_cells = 10; 253 | n_train_bands = 8; 254 | 255 | %Select the number of Guard Cells in both dimensions around the Cell under 256 | %test (CUT) for accurate estimation 257 | n_guard_cells = 4; 258 | n_guard_bands = 4; 259 | 260 | % offset the threshold by SNR value in dB 261 | offset = 1.4; 262 | 263 | %Create a vector to store noise_level for each iteration on training cells 264 | noise_level = zeros(1,1); 265 | 266 | %design a loop such that it slides the CUT across range doppler map by 267 | %giving margins at the edges for Training and Guard Cells. 268 | %For every iteration sum the signal level within all the training 269 | %cells. To sum convert the value from logarithmic to linear using db2pow 270 | %function. Average the summed values for all of the training%cells used. After averaging convert it back to logarithimic using pow2db. 271 | %Further add the offset to it to determine the threshold. Next, compare the 272 | %signal under CUT with this threshold. If the CUT level > threshold assign 273 | %it a value of 1, else equate it to 0. 274 | 275 | 276 | % Use RDM[x,y] as the matrix from the output of 2D FFT for implementing 277 | % CFAR 278 | 279 | RDM = RDM / max(RDM(:)); 280 | 281 | for row0 = n_train_cells + n_guard_cells + 1 : (Nr/2) - (n_train_cells + n_guard_cells) 282 | for col0 = n_train_bands + n_guard_bands + 1 : (Nd) - (n_train_bands + n_guard_bands) 283 | %Create a vector to store noise_level for each iteration on training cells 284 | noise_level = zeros(1, 1); 285 | 286 | for row1 = row0 - (n_train_cells + n_guard_cells) : row0 + (n_train_cells + n_guard_cells) 287 | for col1 = col0 - (n_train_bands + n_guard_bands) : col0 + (n_train_bands + n_guard_bands) 288 | if (abs(row0 - row1) > n_guard_cells || abs(col0 - col1) > n_guard_bands) 289 | noise_level = noise_level + db2pow(RDM(row1, col1)); 290 | end 291 | end 292 | end 293 | 294 | % Calculate threshold from noise average then add the offset 295 | thresh = pow2db(noise_level / (2 * (n_train_bands + n_guard_bands + 1) * 2 * (n_train_cells + n_guard_cells + 1) - (n_guard_cells * n_guard_bands) - 1)); 296 | thresh = thresh + offset; 297 | 298 | CUT = RDM(row1,col1); 299 | 300 | if (CUT < thresh) 301 | RDM(row0, col0) = 0; 302 | else 303 | RDM(row0, col0) = 1; 304 | end 305 | 306 | end 307 | end 308 | 309 | 310 | % 311 | % The process above will generate a thresholded block, which is smaller 312 | %than the Range Doppler Map as the CUT cannot be located at the edges of 313 | %matrix. Hence,few cells will not be thresholded. To keep the map size same 314 | % set those values to 0. 315 | 316 | RDM(RDM~=0 & RDM~=1) = 0; 317 | 318 | % Plotting CFAR output 319 | figure('Name', 'CA-CFAR Filtered RDM'); 320 | surf(doppler_axis, range_axis, RDM); 321 | title('CA-CFAR Filtered RDM surface plot'); 322 | xlabel('Speed'); 323 | ylabel('Range'); 324 | zlabel('Normalized Amplitude'); 325 | view(315, 45); 326 | 327 | % Save the figure 328 | saveas(gcf, 'cfar_filtered_rdm.png'); 329 | ``` 330 | 331 | ![](./images/range_2nd_fft_afterCFAR.jpg) 332 | -------------------------------------------------------------------------------- /cfar_implementation.m: -------------------------------------------------------------------------------- 1 | % cfar_implementation.m 2 | % CFAR implementation 3 | n_train_cells = 10; 4 | n_train_bands = 8; 5 | n_guard_cells = 4; 6 | n_guard_bands = 4; 7 | offset = 1.4; 8 | 9 | RDM = RDM / max(RDM(:)); 10 | 11 | % CFAR processing loop 12 | for row0 = n_train_cells + n_guard_cells + 1 : (Nr/2) - (n_train_cells + n_guard_cells) 13 | for col0 = n_train_bands + n_guard_bands + 1 : (Nd) - (n_train_bands + n_guard_bands) 14 | % ... (CFAR implementation details) 15 | end 16 | end 17 | 18 | RDM(RDM~=0 & RDM~=1) = 0; 19 | 20 | % Plotting CFAR output 21 | figure('Name', 'CA-CFAR Filtered RDM'); 22 | surf(doppler_axis, range_axis, RDM); 23 | title('CA-CFAR Filtered RDM surface plot'); 24 | xlabel('Speed'); 25 | ylabel('Range'); 26 | zlabel('Normalized Amplitude'); 27 | view(315, 45); 28 | 29 | saveas(gcf, './images/cfar_filtered_rdm.jpg'); 30 | -------------------------------------------------------------------------------- /images/cfar_filtered_rdm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidscmx/radar-target-generation-and-detection/b93a3bc8fd56f079ed58fb5ef710e6c18082cbb3/images/cfar_filtered_rdm.jpg -------------------------------------------------------------------------------- /images/range_1st_fft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidscmx/radar-target-generation-and-detection/b93a3bc8fd56f079ed58fb5ef710e6c18082cbb3/images/range_1st_fft.jpg -------------------------------------------------------------------------------- /images/range_doppler_map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidscmx/radar-target-generation-and-detection/b93a3bc8fd56f079ed58fb5ef710e6c18082cbb3/images/range_doppler_map.jpg -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | % main.m 2 | clear all 3 | clc; 4 | 5 | % Load necessary packages 6 | pkg load control 7 | pkg load signal 8 | 9 | % Run the simulation modules 10 | radar_specs; 11 | target_definition; 12 | waveform_generation; 13 | signal_generation; 14 | range_measurement; 15 | range_doppler_response; 16 | cfar_implementation; -------------------------------------------------------------------------------- /radar_specs.m: -------------------------------------------------------------------------------- 1 | % radar_specs.m 2 | % Radar Specifications 3 | c = 3e8; % Speed of light 4 | fc = 77e9; % Carrier frequency 5 | max_range = 200; % Max Range 6 | range_res = 1; % Range Resolution 7 | max_vel = 100; % Max Velocity -------------------------------------------------------------------------------- /radar_target_steps.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc; -------------------------------------------------------------------------------- /range_doppler_response.m: -------------------------------------------------------------------------------- 1 | % range_doppler_response.m 2 | % RANGE DOPPLER RESPONSE 3 | Mix = reshape(Mix, [Nr, Nd]); 4 | signal_fft2 = fft2(Mix, Nr, Nd); 5 | signal_fft2 = signal_fft2(1:Nr/2, 1:Nd); 6 | signal_fft2 = fftshift(signal_fft2); 7 | 8 | RDM = abs(signal_fft2); 9 | RDM = 10*log10(RDM); 10 | 11 | % Plotting 12 | doppler_axis = linspace(-100, 100, Nd); 13 | range_axis = linspace(-200, 200, Nr/2)*((Nr/2)/400); 14 | 15 | figure; 16 | surf(doppler_axis, range_axis, RDM); 17 | title('Amplitude and Range From FFT2'); 18 | xlabel('Speed'); 19 | ylabel('Range'); 20 | zlabel('Amplitude'); 21 | 22 | saveas(gcf, './images/range_doppler_map.jpg'); -------------------------------------------------------------------------------- /range_measurement.m: -------------------------------------------------------------------------------- 1 | % range_measurement.m 2 | % RANGE MEASUREMENT 3 | Mix = reshape(Mix, [Nr, Nd]); 4 | signal_fft = fft(Mix, Nr); 5 | signal_fft = abs(signal_fft); 6 | signal_fft = signal_fft ./ max(signal_fft); 7 | signal_fft = signal_fft(1 : Nr/2-1); 8 | 9 | % Plotting 10 | figure('Name', 'Range from First FFT'); 11 | plot(signal_fft); 12 | axis([0 200 0 1]); 13 | title('Range from First FFT'); 14 | ylabel('Amplitude (Normalized)'); 15 | xlabel('Range [m]'); 16 | 17 | 18 | % Save the figure 19 | saveas(gcf, './images/range_1st_fft.jpg'); -------------------------------------------------------------------------------- /signal_generation.m: -------------------------------------------------------------------------------- 1 | % signal_generation.m 2 | % Signal generation and Moving Target simulation 3 | for i = 1:length(t) 4 | r_t(i) = range + (vel*t(i)); 5 | td(i) = (2 * r_t(i)) / c; 6 | 7 | Tx(i) = cos(2*pi*(fc*t(i) + (slope*t(i)^2)/2)); 8 | Rx(i) = cos(2*pi*(fc*(t(i) -td(i)) + (slope * (t(i)-td(i))^2)/2)); 9 | 10 | Mix(i) = Tx(i) .* Rx(i); 11 | end -------------------------------------------------------------------------------- /target_definition.m: -------------------------------------------------------------------------------- 1 | % target_definition.m 2 | % User Defined Range and Velocity of target 3 | range = 110; % Initial position 4 | vel = -20; % Velocity (constant) -------------------------------------------------------------------------------- /waveform_generation.m: -------------------------------------------------------------------------------- 1 | % waveform_generation.m 2 | % FMCW Waveform Generation 3 | B = c / (2*range_res); 4 | Tchirp = 5.5 * 2 * (max_range/c); 5 | slope = B/Tchirp; 6 | 7 | Nd = 128; % Number of doppler cells 8 | Nr = 1024; % Number of range cells 9 | 10 | % Time vector 11 | t = linspace(0, Nd*Tchirp, Nr*Nd); 12 | 13 | % Initialize signal vectors 14 | Tx = zeros(1, length(t)); 15 | Rx = zeros(1, length(t)); 16 | Mix = zeros(1, length(t)); 17 | 18 | r_t = zeros(1, length(t)); 19 | td = zeros(1, length(t)); --------------------------------------------------------------------------------