├── FreeSpace.m ├── MatchedFilter.m ├── MonostaticRadar_Example.m ├── README.md ├── Receiver.m ├── RectangularWave.m ├── Target.m ├── TimeVaryingGain.m ├── Transmitter.m ├── estimatePeakPower.m ├── helperRadarPulsePlot.m └── radarPlot.m /FreeSpace.m: -------------------------------------------------------------------------------- 1 | function y = FreeSpace(SampleRate,OperatingFrequency,x,endPos) 2 | % The freespace signal calculation takes into concideration that the signal 3 | % is propogating two ways 4 | 5 | numOfPropPaths = size(x,2); 6 | 7 | % Calculate Propogated Signal and the Delay 8 | [temp_output_signal,propdelay] = calculatePropagatedSignalOutput(x,numOfPropPaths,endPos,OperatingFrequency); 9 | nDelay = propdelay*SampleRate; 10 | 11 | % Check to see if delay can be divided by the sample rate with no remainder 12 | % -> If this is true the delayed signal output does not need to be 13 | % calculated for this channel 14 | isDelayIntSamples = (rem(propdelay,1/SampleRate) == 0); 15 | % For exact samples, round nDelay in case numerical error 16 | % exists 17 | nDelay(isDelayIntSamples) = round(nDelay(isDelayIntSamples)); 18 | tempDelay = nDelay; 19 | tempDelay(isDelayIntSamples) = 0; 20 | 21 | % Computes the fractional delay that cannot be expresses as an integer 22 | % shift in the freespace array 23 | FDF = dsp.VariableFractionalDelay; 24 | integer_delay = floor(tempDelay); 25 | fractional_delay = tempDelay-integer_delay; 26 | temp_output_signal = step(FDF,temp_output_signal,fractional_delay); 27 | 28 | % Shift the signal from the start of the frame through the freespace 29 | % proportionally to the distance that it is away as an integer now 30 | 31 | move_to = floor(nDelay); 32 | 33 | % Typically a circle buffer would be used here so that when a number of 34 | % pulses are being integrated and there is an object far enough to overflow 35 | % the pulse repetition frequency the signal from the current freespace 36 | % output will bleed into the next 37 | % In this case we assume that there is no overflow and everything is just 38 | % shifted and the previous signal bleeding in is not taken into account 39 | 40 | for m = 1:size(move_to,2) 41 | y_out(:,m) = circshift(temp_output_signal(:,m),move_to(1,m),1); 42 | end 43 | 44 | y = y_out; 45 | 46 | function [y,propagation_delay] = calculatePropagatedSignalOutput(x,numOfPropPaths,location,OperatingFrequency) 47 | % Add propagation loss and phase change 48 | propagation_speed = physconst('LightSpeed'); 49 | y = complex(zeros(size(x))); 50 | lambda = propagation_speed/OperatingFrequency; 51 | 52 | % propagation distance 53 | propagation_distance = location(1,:); 54 | propagation_delay = 2*propagation_distance/propagation_speed; 55 | 56 | free_space_path_loss = 4*pi*propagation_distance(:)*(1./lambda(:).'); 57 | free_space_path_loss = mag2db(free_space_path_loss); 58 | loss = 2*free_space_path_loss; 59 | 60 | loss_factor = sqrt(db2pow(loss)); 61 | for colum_index = 1:numOfPropPaths 62 | y(:,colum_index) = exp(-1i*2*pi*2*propagation_distance(colum_index)/lambda)/loss_factor(colum_index)*x(:,colum_index); 63 | end 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /MatchedFilter.m: -------------------------------------------------------------------------------- 1 | function [output_signal,g] = MatchedFilter(input_signals,fft_coeff) 2 | fft_length = size(input_signals,1)+1; 3 | pSignalIdx = [1 fft_length]; 4 | 5 | coefficient_fft = dsp.FFT('FFTLengthSource','Property','FFTLength',fft_length); 6 | 7 | fft_window_coeff = ones(fft_length,1); 8 | 9 | 10 | coeff_freq = step(coefficient_fft,fft_coeff) .* fft_window_coeff; 11 | coefficient_fft.release(); 12 | 13 | signal_fft = step(coefficient_fft,complex(input_signals)); 14 | 15 | % Multiple the two ffts together 16 | fft_multiple = zeros(size(signal_fft,1),size(signal_fft,2)); 17 | for i = 1:size(signal_fft,2) 18 | for j = 1:size(signal_fft,1) 19 | fft_multiple(j,i) = signal_fft(j, i) * coeff_freq(j,1); 20 | end 21 | end 22 | 23 | % Perform the inverse FFT to get the output signal 24 | inverse_fft_output = step(dsp.IFFT,fft_multiple); 25 | 26 | output_signal = inverse_fft_output(pSignalIdx(1):pSignalIdx(2),:); 27 | 28 | windowProcessingLoss = -pow2db(abs(sum(fft_window_coeff))^2/(fft_length*(fft_window_coeff'*fft_window_coeff))); 29 | 30 | gain = pow2db(real(fft_coeff'*fft_coeff)); 31 | 32 | output_signal = output_signal(1:size(input_signals,1),1:size(input_signals,2)); 33 | g = gain - windowProcessingLoss; 34 | 35 | % Shifts values into correct position after FFT and IFFT 36 | output_signal = buffer(output_signal(size(fft_coeff,1):end),size(output_signal,1)); 37 | 38 | -------------------------------------------------------------------------------- /MonostaticRadar_Example.m: -------------------------------------------------------------------------------- 1 | % Monstatic Pulse Radar System Example 2 | % Referenced from: 3 | % https://www.mathworks.com/help/phased/examples/designing-a-basic-monostatic-pulse-radar.html 4 | % Possible Expansion 5 | % https://www.mathworks.com/help/phased/examples/waveform-design-to-improve-performance-of-an-existing-radar-system.html 6 | % Design Specifications 7 | clc 8 | 9 | pd = 0.9; % Probability of detection 10 | pfa = 1e-6; % Probability of false alarm 11 | max_range = 5000; % Maximum unambiguous range 12 | range_res = 50; % Required range resolution 13 | tgt_rcs = 1; % Required target radar cross section 14 | 15 | % Monostatic Radar System Design 16 | % Waveform 17 | 18 | prop_speed = physconst('LightSpeed'); % Propagation speed 19 | pulse_bw = prop_speed/(2*range_res); % Pulse bandwidth 20 | pulse_width = 1/pulse_bw; % Pulse width 21 | prf = prop_speed/(2*max_range); % Pulse repetition frequency 22 | fs = 2*pulse_bw; % Sampling rate 23 | 24 | % A number of pulses are sent out to increase the signal to noise ratio and 25 | % decrease the total amount of power needed to send the signal 26 | num_pulse_integrations = 10; 27 | noise_bw = pulse_bw; 28 | 29 | % Calculating the minimum signal to noise ratio using the Albersheim 30 | % Method using the probability of detection and the probability of false 31 | % alarm 32 | snr_min_a = log(0.62/pfa); 33 | snr_min_b = log(pd/(1-pd)); 34 | snr_min = (1/sqrt(num_pulse_integrations))*(snr_min_a + 0.12*snr_min_a*snr_min_b + 1.7*snr_min_b)^((6.2+4.54/sqrt(num_pulse_integrations+0.44))/10); 35 | snr_min = pow2db(snr_min); 36 | 37 | tx_gain = 20; 38 | fc = 10e9; 39 | lambda = prop_speed/fc; 40 | 41 | % Example targets. Velocities not included due to everything in this 42 | % example having 0 constant velocity 43 | % tgtpos = [[2024.66;0;0],[3518.63;0;0],[3845.04;0;0]]; 44 | % tgtrcs = [1.6 2.2 1.05]; 45 | 46 | % Test Target Being Used 47 | tgtpos = [[1000;0;0],[1845.04;0;0],[2024.66;0;0],[3518.63;0;0],[3845.04;0;0]]; 48 | tgtrcs = [1 2 1.6 2.2 1.05]; 49 | 50 | PeakPower = estimatePeakPower(lambda,max_range,snr_min,pulse_width,tgt_rcs,tx_gain); 51 | 52 | segments = (1/prf)/(1/fs); 53 | fast_time_grid = zeros(1,segments); 54 | for i = 1:segments 55 | fast_time_grid(1,i) = (i-1)*(1/fs); 56 | end 57 | slow_time_grid = (0:num_pulse_integrations-1)/prf; 58 | 59 | rs = RandStream('mt19937ar','Seed',1000); 60 | % Pre-allocate array for improved processing speed 61 | receivedPulses = zeros(numel(fast_time_grid),num_pulse_integrations); 62 | 63 | % Update sensor and target positions 64 | % NOTE: In this demonstration both the target and the sensor are static 65 | % Calculate the target angles as seen by the sensor 66 | % NOTE: In this demonstration the target angles and ranges are constant 67 | % becuase the sensor and target positions are constant and the velocity is 68 | % 0. If there was a velocity this operaton would be done inside the loop 69 | for j = 0:size(tgtpos,2)-1 70 | tgtrng(1,1+j) = tgtpos(1,1+j); 71 | end 72 | 73 | for m = 1:num_pulse_integrations 74 | % Generate Wave 75 | wave = RectangularWave(pulse_width,fs,prf); 76 | % Generate Output of Transmitter using the Rectangular Wave (gives the 77 | % initial transmit signal and status as it leaves the transmitted 78 | [txsig,txstatus] = Transmitter(tx_gain,PeakPower,wave); 79 | % Generate Output of Radiator using the Transmit Sigature and the Target 80 | % Angle 81 | % In this case the txsig var is copied accross x number of channels 82 | % where x is the number of targets 83 | for j = 1:size(tgtrng,2)-1 84 | txsig(:,j+1) = txsig(:,1); 85 | end 86 | % Generate Output of the Channel (Free Space) between the radiator and 87 | % the target object using the transmit signature, sensor position, target 88 | % position, sensor velocity and target velocity 89 | % In this case the sensor position, target 90 | % position are all both constant because the sensor velocity and target 91 | % velocity are 0 92 | txsig = FreeSpace(fs,fc,txsig,tgtpos); 93 | % Generate Output of the wave reflecting off of the target using the 94 | % transmit signature 95 | tgtsig = Target(tgtrcs,fc,txsig); 96 | % Generate Output of the Collector using the target signature (Pushes 97 | % the induvidual reflections together 98 | g = ones(size(tgtsig,2),1); 99 | rxsig = tgtsig*g; 100 | % Generate the output from the Receiver using the transmit status and the 101 | % receiver signature and store it in an array for the number of pulses 102 | 103 | receivedPulses(:,m) = Receiver(fs,rxsig,~(txstatus>0),rs); 104 | end 105 | 106 | % Range Detection Section 107 | % Using the received pulses, the number of which defined by num_pulse_integrations 108 | % Several signal processing techniques are used to increase the power of 109 | % the components of the signal received through reflection vs. noise 110 | 111 | % Detection Threshold 112 | % The detection threshold is found through a function of the noise power 113 | % the probablilty of false alarm and the number of pulse integrations 114 | 115 | snr_min_b = physconst('Boltzmann'); 116 | % Calculate the noise power B * Temp * noise_bw 117 | npower = snr_min_b * 290 * noise_bw; 118 | threshold = npower * db2pow(mag2db(abs(sqrt(gammaincinv(1-pfa,num_pulse_integrations))))); 119 | 120 | % Matched Filter 121 | % Convolves the received signal with a time-reversed 122 | % conjugated copy of transmitted waveform. 123 | % This improves the detection threshold 124 | % Uses the transmitted waveform as ref 125 | 126 | % In this case the coefficients match the ones at the start of the waveform 127 | [receivedPulses, mfgain] = MatchedFilter(receivedPulses,[1;1]); 128 | % Update Threshold 129 | threshold = threshold * db2pow(mfgain); 130 | 131 | % Time Varying Gain 132 | % Increases gain over time (signals received quickly will have higher gain 133 | % than the signals recived later on) 134 | 135 | range_bins = prop_speed*fast_time_grid/2; 136 | fspl_range_bins = 20*log10(max((4*pi*range_bins/lambda),1)); 137 | fspl_max_range = 20*log10(max((4*pi*max_range/lambda),1)); 138 | receivedPulses = TimeVaryingGain(2*fspl_range_bins,2*fspl_max_range,receivedPulses); 139 | 140 | % Noncoherent Integration 141 | % Integrating the received pulses together showing one final signal 142 | % Takes the sum of the square of the received pulses (rows) 143 | 144 | sigout = sum(abs(receivedPulses).^2,2); 145 | receivedPulses = sqrt(sigout); 146 | 147 | % Result Plotting 148 | figure 149 | thresh = sqrt(threshold).*ones(numel(fast_time_grid),1); 150 | rpulse = abs(receivedPulses(:,1)); 151 | plot(fast_time_grid,pow2db(rpulse.^2),fast_time_grid,pow2db(thresh.^2),'r--'); 152 | ylabel("Power (dBw)"); 153 | xlabel("Time (s)"); 154 | title("Processed Radar Pulses"); 155 | grid on; 156 | axis tight; 157 | 158 | % Peak / Range Detection 159 | % Finds signal peaks above the detection threshold 160 | 161 | [~,range_detect] = findpeaks(receivedPulses,'MinPeakHeight',sqrt(threshold)); 162 | 163 | true_range = round(tgtrng) 164 | range_estimates = round(range_bins(range_detect)) 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monostatic Pulse Radar 2 | 3 | This project outlines a basic monostatic pulse radar system to detect non-fluctuating targets with at least one square meter radar cross section (RCS) at a distance up to 5000 meters from the radar with a range resolution of 50 meters. The desired performance index is a probability of detection (Pd) of 0.9 and probability of false alarm (Pfa) below 1e-6. 4 | 5 | The code is also designed so that the objects and sensor are at a fixed range (0 velocity) 6 | 7 | The project was designed following the guide under https://www.mathworks.com/help/phased/examples/designing-a-basic-monostatic-pulse-radar.html 8 | 9 | # Instructions 10 | 11 | To run the simulation clone the repository and add the folder to the Matlab path. Navigate to `MonostaticRadar_Example.m` and press run. 12 | 13 | The following targets are currently being used: 14 | ``` 15 | tgtpos = [[1000;0;0],[1845.04;0;0],[2024.66;0;0],[3518.63;0;0],[3845.04;0;0]]; 16 | tgtrcs = [1 2 1.6 2.2 1.05]; 17 | ``` 18 | More targets and their radar cross sections can be added or subtracted here. 19 | -------------------------------------------------------------------------------- /Receiver.m: -------------------------------------------------------------------------------- 1 | function y = Receiver(SampleRate,x,error_rx,rs) 2 | 3 | error_rx = logical(error_rx); 4 | x(~error_rx,:) = 0; 5 | LossFactor = 20; 6 | output_size = [size(x,1), size(x,2)]; 7 | 8 | B = physconst('Boltzmann'); 9 | NoiseSamplePower = B * 290 * SampleRate; 10 | noise = sqrt(NoiseSamplePower/2)*complex(randn(rs,output_size),randn(rs,output_size)); 11 | 12 | y = sqrt(db2pow(LossFactor))*x + noise; -------------------------------------------------------------------------------- /RectangularWave.m: -------------------------------------------------------------------------------- 1 | function y = RectangularWave(pulse_width,fs,pulse_repetition_frequency) 2 | 3 | % Creates the array of the pulse length size at the sampling rate 4 | pulse_length = round(fs/pulse_repetition_frequency); 5 | % Gets the width of the pulse in terms of the array being sampled at fs 6 | index = (pulse_width)/(1/fs); 7 | for n = 1:numel(index) 8 | if abs(index(n)-round(index(n))) <= 10*eps(index(n)) 9 | index(n) = round(index(n)); 10 | end 11 | end 12 | nonZeroLength = ceil(index) + 1; 13 | 14 | y = complex(zeros(pulse_length,1)); 15 | for i = 1:nonZeroLength 16 | y(i) = 1; 17 | end 18 | 19 | -------------------------------------------------------------------------------- /Target.m: -------------------------------------------------------------------------------- 1 | function y = Target(MeanRCS,OperatingFrequency,x) 2 | 3 | PropSpeed = physconst('LightSpeed'); 4 | lambda = PropSpeed/OperatingFrequency; 5 | gain = 4*pi*MeanRCS./(lambda^2); 6 | gain = pow2db(gain); 7 | gain = sqrt(db2pow(gain)); 8 | y = zeros(size(x,1),size(x,2)); 9 | for i = 1:size(x,2) 10 | for j = 1:size(x,1) 11 | y(j,i) = x(j, i) * gain(1,i); 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /TimeVaryingGain.m: -------------------------------------------------------------------------------- 1 | function yout = TimeVaryingGain(rng_loss,ref_loss,x) 2 | 3 | range_loss = rng_loss(:)-ref_loss; 4 | normal_vector = db2mag(range_loss); 5 | normal_vector = normal_vector(1:size(x,1)); 6 | yout = zeros(size(x,1),size(x,2)); 7 | for i = 1:size(x,2) 8 | for j = 1:size(x,1) 9 | yout(j,i) = x(j, i) * normal_vector(j,1); 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Transmitter.m: -------------------------------------------------------------------------------- 1 | function [yout,TxOn] = Transmitter(LossFactor,PeakPower,wave) 2 | 3 | Amplitude_Coeff = sqrt(PeakPower*db2pow(LossFactor)); 4 | yout = Amplitude_Coeff*wave; 5 | TxOn = wave~=0; 6 | -------------------------------------------------------------------------------- /estimatePeakPower.m: -------------------------------------------------------------------------------- 1 | function PeakPower = estimatePeakPower(lambda,RNG,SNRdb,tau,RCS,Gain) 2 | 3 | Loss = 0; 4 | Ts = 290; 5 | k = physconst('Boltzmann'); 6 | PeakPower = ((4*pi)^3*k*Ts*RNG^2*RNG^2*db2pow(Loss)*db2pow(SNRdb))/(tau*db2pow(Gain)*RCS*db2pow(Gain)*lambda^2); % Watts 7 | -------------------------------------------------------------------------------- /helperRadarPulsePlot.m: -------------------------------------------------------------------------------- 1 | function helperRadarPulsePlot(ReceivePulse,threshold,t,tp,pulseplotnum) 2 | % This function helperRadarPulsePlot is only in support of 3 | % RadarRangeEstimationExample. It may be removed in a future release. 4 | 5 | % Copyright 2007-2012 The MathWorks, Inc. 6 | 7 | thresh = sqrt(threshold).*ones(numel(t),1); 8 | for m = 1:pulseplotnum 9 | subplot(pulseplotnum,1,m); 10 | tnow = t+tp(m); 11 | rpulse = abs(ReceivePulse(:,m)); 12 | rpulse(rpulse == 0) = eps; % avoid log of 0 13 | plot(tnow,pow2db(rpulse.^2),tnow,pow2db(thresh.^2),'r--'); 14 | 15 | xlabel('Time (s)'); 16 | ylabel('Power (dBw)'); 17 | axis tight; 18 | ax = axis; 19 | ax(4) = ax(4)+0.05*abs(ax(4)); 20 | axis(ax); 21 | grid on; 22 | if pulseplotnum > 1 23 | title(sprintf('Pulse %d',m)); 24 | end 25 | end 26 | 27 | 28 | % [EOF] 29 | -------------------------------------------------------------------------------- /radarPlot.m: -------------------------------------------------------------------------------- 1 | function radarPlot(ReceivePulse,threshold,t) 2 | 3 | 4 | --------------------------------------------------------------------------------