Skip to content

Bistatic Example

Stephen Paine edited this page Nov 23, 2022 · 8 revisions

Getting Started

This is a starting point for those wanting to make use of FERS for radar projects. The goal is to be as simple and brief as possible, and to eliminate any tedious trial-and-error in getting a simulation up and running quickly.

Note: The simulation files can be found in the FERS_Examples folder on the main page.

What is FERS?

FERS is a simulator for radar systems.

Using FERS

FERS works from the the command line, and was designed to be used in a Linux environment. Some work has been started towards a GUI, but currently the command-line is still used mostly.

To run a FERS simulation, one simply types the following into the command line: $ fers [input_file.fersxml]

How FERS works

FERS takes as input:

  1. An xml file (with the extension ".fersxml") which describes the entire simulation.
  2. One or more files containing pulse waveform data. The fersxml file associates these with specific transmitters in the simulation.

It returns as output:

  1. One or more files representing the raw radar return at the terminals of each receiver in the simulation.
  2. An optional xml file containing additional information about the simulation.

The input and output data can be in one of two forms:

  1. CSV (comma-separated values), a text file2. HDF5 (Hierarchical data format), a more efficient binary format, in which the data must be organised in a specific way for FERS to make use of it.

Some notes on I/O:

  • The values in the files represent voltages across a 1 ohm resistor. Thus to calculate the power, one takes the square of the values in the data.
  • Note the returned data is normalised, and comes with a scaling factor. To obtain the actual values one must thus multiply the data by this scaling value.
  • All input and output signals are in base-band i.e. the carrier component is implicit. The Nyquist sampling rate (also specified in the fersxml input file) is thus lowered: you do not need to sample at twice the carrier frequency.

Creating FERS Input Data

Note: All of the work below is done using Matlab

The first step is creating the signal to be used by the transmitter. The script below generates a Gaussian noise signal and saves it as an HDF5 file.

sig = randn(1,500000)+j*randn(1,500000);
I = real(sig);
Q = imag(sig);
fprintf('Writing HDF5 data...\n');
hdf5write('waveform.h5', '/I/value', real(I), '/Q/value', imag(Q));
fprintf('Complete.\n');

This is now put in the same directory as a .fersxml script, and called from within it.

Creating Basic FERS XML File

1. Separate Reference and Surveillance Files

There are two ways that this simulation can be achieved. The first is to use two different simulation files, one for the reference channel and one for surveillance channel:

Reference File [ref.fersxml]

<!--Simulation of reference channel with Rx as (0,0) and height of 116m and Tx as (-6640m,-10763m) and height of 1056m. Flying target 
at (19018m,3204m) and height 5000m at t = 0s and at (19012m,3197m) and height 5000m at t = 1s-->
<!DOCTYPE simulation SYSTEM "../../fers-xml.dtd">
<simulation name="Sim1">

<parameters>
 <starttime>0</starttime>
 <endtime>1</endtime>
 <rate>500000</rate>
 <export binary="true" csvbinary="false" xml="false"/>
</parameters>

<pulse name="pulse1" type="file" filename="waveform.h5">
 <power>10e3</power>
 <carrier>89e6</carrier> <!-- VHF Band -->
</pulse>

<timing name="clock">
 <frequency>89e6</frequency>
</timing>

<antenna name="isotropic" pattern="isotropic">
</antenna>

<platform name="Transmitter">
 <motionpath>
  <positionwaypoint>
   <x>-6440</x>
   <y>-10760</y>
   <altitude>1056</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <transmitter name="Tx" type="pulsed" antenna="isotropic" pulse="pulse1" timing="clock">      
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
 </transmitter>
</platform>

<platform name="Reference_Rx">
 <motionpath>
  <positionwaypoint>
   <x>0.0</x>
   <y>0.0</y>
   <altitude>116.0</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <receiver name="ref" type="pulsed" antenna="isotropic" pulse="pulse1" timing="clock">      
  <window_skip>0</window_skip>
  <window_length>1</window_length> <!-- make this 10 for a 10s simulation--> 
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
  <noise_temp>100</noise_temp>
 </receiver>
</platform>
</simulation>

Surveillance File [surv.fersxml]

<!--Simulation surveillance channel with Rx as (0,0) and height of 116m and Tx as (-6640m,-10763m) and height of 1056m. Flying target 
at (19018m,3204m) and height 5000m at t = 0s and at (19012m,3197m) and height 5000m at t = 1s-->
<!DOCTYPE simulation SYSTEM "../../fers-xml.dtd">
<simulation name="sim1">

<parameters>
 <starttime>0</starttime>
 <endtime>1</endtime>
 <rate>500000</rate>
 <export binary="true" csvbinary="false" xml="false"/>
</parameters>

<pulse name="pulse1" type="file" filename="waveform.h5">
 <power>10e3</power>
 <carrier>89e6</carrier> <!-- VHF Band -->
</pulse>

<timing name="clock">
<frequency>89e6</frequency>
</timing>

<antenna name="isotropic" pattern="isotropic">
</antenna>

<platform name="Transmitter">
 <motionpath>
  <positionwaypoint>
   <x>-6440</x>
   <y>-10760</y>
   <altitude>1056</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <transmitter name="Tx" type="pulsed" antenna="isotropic" pulse="pulse1" timing="clock">      
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
 </transmitter>
</platform>

<platform name="Surveilance_Rx">
 <motionpath>
  <positionwaypoint>
   <x>0.0</x>
   <y>0.0</y>
   <altitude>116.0</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <receiver name="surv" type="pulsed" antenna="isotropic" pulse="pulse1" timing="clock">      
  <window_skip>0</window_skip>
  <window_length>1</window_length> <!-- make this 10 for a 10s simulation--> 
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
  <noise_temp>100</noise_temp>
 </receiver>
</platform>

<platform name="aeroplane">
 <motionpath interpolation="cubic">
  <positionwaypoint>
   <x>2000</x>
   <y>4300</y>
   <altitude>1600.0</altitude>
   <time>0</time>
  </positionwaypoint>
  <positionwaypoint>
   <x>2000</x>
   <y>4000</y>
   <altitude>1600.0</altitude>
   <time>1</time>
  </positionwaypoint>
 </motionpath>    
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0.0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <target name="wings">
  <rcs type="isotropic">
   <value>100</value>
  </rcs>
 </target>
</platform>

<platform name="helicopter">
 <motionpath interpolation="cubic">
  <positionwaypoint>
   <x>2000</x>
   <y>8900</y>
   <altitude>1600.0</altitude>
   <time>0</time>
  </positionwaypoint>
  <positionwaypoint>
   <x>2000</x>
   <y>9000</y>
   <altitude>1600.0</altitude>
   <time>1</time>
  </positionwaypoint>
 </motionpath>    
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0.0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <target name="wings">
  <rcs type="isotropic">
   <value>100</value>
  </rcs>
 </target>
</platform>
</simulation>

2. Combined Reference and Surveillance File

If you want to use a single file for a more realistic simulation, i.e. where the direct path interference is present in the surveillance channel, use a single reference and surveillance file as shown:

Single File [bistatic.fersxml]

<!--Simulation surveillance channel with Rx as (0,0) and height of 116m and Tx as (-6640m,-10763m) and height of 1056m. Flying target 
at (19018m,3204m) and height 5000m at t = 0s and at (19012m,3197m) and height 5000m at t = 1s-->
<!DOCTYPE simulation SYSTEM "../../fers-xml.dtd">
<simulation name="sim1">

<parameters>
 <starttime>0</starttime>
 <endtime>1</endtime>
 <rate>500000</rate>
 <adc_bits>16</adc_bits>
 <export binary="true" csvbinary="false" xml="false"/>
</parameters>

<pulse name="pulse1" type="file" filename="waveform.h5">
 <power>10e3</power>
 <carrier>89e6</carrier> <!-- VHF Band -->
</pulse>

<timing name="clock">
<frequency>89e6</frequency>
</timing>

<antenna name="isotropic" pattern="isotropic">
</antenna>

<antenna name="YagiAntenna" pattern="sinc">
 <efficiency>1</efficiency>
 <alpha>5.2481</alpha><!-- 7.2 dBi -->
 <beta>2</beta>
 <gamma>3.6</gamma>
</antenna>

<platform name="Transmitter">
 <motionpath>
  <positionwaypoint>
   <x>-6440</x>
   <y>-10760</y>
   <altitude>1056</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <transmitter name="Tx" type="pulsed" antenna="isotropic" pulse="pulse1" timing="clock">      
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
 </transmitter>
</platform>

<platform name="Reference_Rx">
 <motionpath>
  <positionwaypoint>
   <x>1.0</x>
   <y>0.0</y>
   <altitude>116.0</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <receiver name="ref" type="pulsed" antenna="YagiAntenna" pulse="pulse1" timing="clock">      
  <window_skip>0</window_skip>
  <window_length>1</window_length> <!-- make this 10 for a 10s simulation--> 
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
  <noise_temp>100</noise_temp>
 </receiver>
</platform>

<platform name="Surveilance_Rx">
 <motionpath>
  <positionwaypoint>
   <x>0.0</x>
   <y>0.0</y>
   <altitude>116.0</altitude>
   <time>0</time>
  </positionwaypoint>
 </motionpath>
 <fixedrotation>
  <startazimuth>0</startazimuth>
  <startelevation>0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <receiver name="surv" type="pulsed" antenna="YagiAntenna" pulse="pulse1" timing="clock">      
  <window_skip>0</window_skip>
  <window_length>1</window_length> <!-- make this 10 for a 10s simulation--> 
  <prf>1</prf> <!-- make this 0.1 for a 10s simulation-->
  <noise_temp>100</noise_temp>
 </receiver>
</platform>

<platform name="aeroplane">
 <motionpath interpolation="cubic">
  <positionwaypoint>
   <x>2000</x>
   <y>4300</y>
   <altitude>1600.0</altitude>
   <time>0</time>
  </positionwaypoint>
  <positionwaypoint>
   <x>2000</x>
   <y>4000</y>
   <altitude>1600.0</altitude>
   <time>1</time>
  </positionwaypoint>
 </motionpath>    
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0.0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <target name="wings">
  <rcs type="isotropic">
   <value>100</value>
  </rcs>
 </target>
</platform>

<platform name="helicopter">
 <motionpath interpolation="cubic">
  <positionwaypoint>
   <x>2000</x>
   <y>8900</y>
   <altitude>1600.0</altitude>
   <time>0</time>
  </positionwaypoint>
  <positionwaypoint>
   <x>2000</x>
   <y>9000</y>
   <altitude>1600.0</altitude>
   <time>1</time>
  </positionwaypoint>
 </motionpath>    
 <fixedrotation>
  <startazimuth>0.0</startazimuth>
  <startelevation>0.0</startelevation>
  <azimuthrate>0</azimuthrate>
  <elevationrate>0</elevationrate>
 </fixedrotation>
 <target name="wings">
  <rcs type="isotropic">
   <value>100</value>
  </rcs>
 </target>
</platform>
</simulation>

Note: You will need to provide an appropriate input file to do a 180 second simulation Note: We are using antenna patterns derived using the antenna scrip below:

Antenna Pattern Function

% <antenna name="YagiAntenna" pattern="sinc">
%  <efficiency>1</efficiency> <!-- See the antenna pattern calculator below -->
%  <alpha>5.2481</alpha><!-- 7.2 dBi -->
%  <beta>2</beta>
%  <gamma>3.6</gamma>
% </antenna>

% polar_dB makes plot of gdb=10*log10(g) versus phi
% phi       = polar angles over [0,2*pi]
% gain      = gain (gain is in absolute units)
% rangedb	= maximum range for the plot
% increments= increments for the gain circles
% rays      = number of rays default is 16  use series of 4
% examples: polar_dB(phi, gain);
%           polar_dB(phi, gain, 20, 2.5, 16)

% Hakan Cakmak 
% University of Duisburg-Essen,
% General and Theoretical Electrical Engineering
% [email protected]

function h = polar_dB(phi, gain, rangedb, increments, rays)

 if nargin < 5, rays = 16; end
 if nargin < 4, increments = 2.5; end
 if nargin < 3, rangedb = 20; end
 % phi=linspace(0,2*pi,1000); % test
 % gain=(sin(phi));
 if nargin < 2
   warning('myApp:argChk', 'Not enough input arguments.');
   help polar_dB; 
   return;
 end

gain1 = 10 * log10(abs(gain));        % test = (isinf(gain1)-1).*gain1;
gain1(gain1==-Inf) = -rangedb;        % avoids -Inf's
gain1 = gain1 .* (gain1 > -rangedb) + (-rangedb) * (gain1 <= -rangedb);      % lowest is rangedb dB
gain1 = (gain1 + rangedb)/rangedb;                                     % scale to unity max.

x = gain1 .* cos(phi);
y = gain1 .* sin(phi);

%R = 1.2; axis([-R, R, -R, R]);

N0 = 360;
phi0=linspace(0,2*pi,N0);
x0 = sin(phi0); % gain circles
y0 = cos(phi0); 

patch('xdata',x0,'ydata',y0, ...
      'edgecolor','black','facecolor','w');
hold on

%changed coordinates
h = plot( y, x,'LineStyle','-','color','blue');  %,'LineWidth', 2 

title({'Linear Scale',...
  sprintf('Range:      %3.2fdB',rangedb),...
  sprintf('Increments: %3.2fdB',increments)},'horizontalalignment','left');%

c_log=(-rangedb:increments:0);
c = (c_log)/-rangedb;  

for k=2:length(c_log) %gain circles
  plot(x0*c(k), y0*c(k),'LineStyle',':','color','black');
end

for k=1:length(c_log) %gain circles markers 
  text(0,c(k), sprintf('%.3g dB',c_log(length(c_log)-k+1)),...
       'horiz', 'center', 'vert', 'middle'); %,'fontsize', 13 
end

phi_s=linspace(0,2*pi,rays+1);
x_s = sin(phi_s); % rays
y_s = cos(phi_s);

for k=1:rays
  line([x_s(k)/rangedb*increments,x_s(k)],...
    [y_s(k)/rangedb*increments,y_s(k)],'LineStyle',':','color','black');
  text(1.1*x_s(k),1.1*y_s(k),...
    sprintf('%.3g%c',phi_s(k)/pi*180, char(176)),...
      'horiz', 'center', 'vert', 'middle','Interpreter','None'); %,'fontsize', 15 
end

axis square;
axis off

Visualising Antenna Pattern

%% For visualising sinc antenna pattern
% G(thetha) = alpha * ( sin(beta .* theta) / (beta .* theta)) ^ gamma

clear;
addpath('polar_dB')

%currentCharacterEncoding = slCharacterEncoding();
%slCharacterEncoding('ISO-8859-1');

% Parameters:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
alpha = 1; %5.2481; %7.2 dBi
beta = 2;
gamma = 3.6;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

theta = -pi:0.01:pi;

G = alpha * ( sin(beta .* theta) ./ (beta .* theta)) .^ gamma;

polar_dB(theta, G, 40, 2.5, 24);

Running a FERS Simulation

Now that we have the simulation files, we can run the simulation. Go to the folder where you have saved the .fersxml file(s) and call FERS: $ fers ref.fersxml and $ fers surv.fersxml or if you run with a single file, use bistatic.fersxml

This will produce an HDF5 file containing the return received by our antennas is produced as output. These two files will be called "ref.h5" and "surv.h5".

Post-Processing

Read Simulation Data and Plot Range-Doppler Map

clc; clear all; close all;

% h5Import
[Ino Qno scale_no] = loadfersHDF5('direct.h5');
[Imov Qmov scale_mov] = loadfersHDF5('echo.h5');
I_Qmov = Imov + j*Qmov;
I_Qmov = I_Qmov.*scale_mov;
I_Qno = Ino + j*Qno;
I_Qno = I_Qno.*scale_no;
I_Qmov=I_Qmov-I_Qno;

% run_ard
fs = 500000;
dopp_bins = 200;
delay = 133e-6;

s1 = I_Qmov;
s2 = I_Qno;

y = ard_plot(s1,s2,fs,dopp_bins,delay);

** Note:

  • The parameters need to be adjusted based on the simulation parameters
  • You need to use the plot and read functions below **

Read data into Matlab

The data contained in the HDF5 file can be read in using the Matlab script below:

% Load an HDF5 file produced by FERS
function [I Q scale] = loadfersHDF5(name)
  hinfo = hdf5info(name);
  count = round(size(hinfo.GroupHierarchy.Datasets,2)/2);
  numelements = hinfo.GroupHierarchy.Datasets(1).Dims;

  I = zeros(numelements*count,1);
  Q = zeros(numelements*count,1);

  scale = hinfo.GroupHierarchy.Datasets(1).Attributes(3).Value;

  for k = 1:count
      Itemp = hdf5read(hinfo.GroupHierarchy.Datasets(2*k-1));
      Qtemp = hdf5read(hinfo.GroupHierarchy.Datasets(2*k));
       
      I(1+(k-1)*numelements:k*numelements,1) = Itemp;
      Q(1+(k-1)*numelements:k*numelements,1) = Qtemp;
  end
end

ard_plot function

To visualize the results, a simple matched filter process could be implemented as follows:

%Generates an ARD plot for the reference and scattered signals using the
%frequency domain implementation.

function y = ard_plot(s1,s2,fs,fd_max,td_max)

  %Corresponds to:
  %1.  The dot-product of the reference and scattered signals
  %2.  Windowing the results to minimize the sidelobes in Doppler
  %3.  The FFT of the above dot-product
  %4.  Discarding frequency bins not of interest
  %5.  Delaying the reference signal by one sample and repeating the above process
  %6.  An ARD plot is then generated and displayed

  %Author:  Sebastiaan Heunis, Yoann paichard

  %function ard(s1,s2,fs,fd_max,Td)
  %s1:  Scattered signal, N samples in column [s1(1,1;...;s(N,1)]
  %s2:  Reference signal, N samples in column [s1(1,1;...;s(N,1)]
  %fs:  Sampling frequency
  %fd_max:  Maximum Doppler shift: fd_max < fs
  %td_max:  Maximum time delay: td_max < N/fs

  % Limits and resolution for computation :
  % Doppler  fd : range  = [-fd_max : fd_max], resolution = fs/N
  % Tau : range  = [0 : td_max], resolution = 1/fs  

  c = 3e8;                    %speed of the light
  N=length(s1);               %number of points
  Ndelay = floor(td_max*fs)   %number of points corresponding to td_max
  Ndop = ceil(N*fd_max/fs)    %number of points corresponding to fd_max

  %initialisation of temporary variables
  temp = zeros(N,1);
  temp2 = zeros(N,1);
  s2_pad = [zeros(Ndelay,1);s2];
  y1=zeros(Ndelay+1,2*fd_max+1);

  tic
  for k = 1:Ndelay+1
      temp = s1.*conj(s2_pad(Ndelay+2-k:N+Ndelay+1-k));       %dot-product of the reference and scattered signals
      temp = temp.*hanning(N);                                %windowing the result 
      temp2 = fftshift(fft(temp,N));                          %FFT of the above dot-product
      y1(k,:) = temp2(floor(N/2)+1-Ndop:floor(N/2)+1+Ndop);   %Discarding frequency bins not of interest
  end
  display('Range-Doppler computation')
  toc

  y = abs(y1).^2;             %Power conversion
  y =y./max(max(abs(y)));     %Normalizing max to 1

  %Time and frequency axis
  time = 0:1/fs:Ndelay/fs;
  range = time*c;
  frequency = -fd_max:1:fd_max;
  Dyn_dB = 40;                %Dynamic range (dB)
  max_dB = 10*log10(max(max(abs(y))));

  tic
  figure('Name','Contour plot');
  contourf(time,frequency,10*log10(y.'));
  colormap jet;
  colorbar;
  grid on;
  xlabel('Bistatic delay [s]','Fontsize',10);
  ylabel('Doppler frequency [Hz]','Fontsize',10);
  title('Range-Doppler response')
  display('contour plot computation')
  toc

  tic
  figure('Name','2D image');
  imagesc(time,frequency,10*log10(y.'),[max_dB-100 max_dB]);
  axis xy;
  colorbar;
  xlabel('Bistatic delay [s]','Fontsize',10);
  ylabel('Doppler frequency [Hz]','Fontsize',10);
  grid on;
  title('Range-Doppler response')
  display('imagesc plot computation')
  toc

Run all together

%Remove previous data
clear; clc; close all;

ref = 'ref.fersxml'
fprintf('Done')
surv = 'surv.fersxml'
fprintf('Done')

% Run the simulation for direct signal
fprintf('\nSimulating Reference Signal\n\n')
strCommand = sprintf('export LD_LIBRARY_PATH="" && fers %s',ref);
system(strCommand, '-echo');
fprintf('Done')

% Run the simulation for echo signal
fprintf('\nSimulating Surveilance Signal\n\n')
strCommand = sprintf('export LD_LIBRARY_PATH="" && fers %s',surv);
system(strCommand, '-echo');
fprintf('Done')

% h5Import
[Ino Qno scale_no] = loadfersHDF5('ref.h5');
[Imov Qmov scale_mov] = loadfersHDF5('surv.h5');
I_Qmov = Imov + j*Qmov;
I_Qmov = I_Qmov.*scale_mov;
I_Qno = Ino + j*Qno;
I_Qno = I_Qno.*scale_no;
I_Qmov=I_Qmov-I_Qno;

% run_ard
fs = 500000;
dopp_bins = 200;
delay = 133e-6;

s1 = I_Qmov;
s2 = I_Qno;

y = ard_plot(s1,s2,fs,dopp_bins,delay);