-
Notifications
You must be signed in to change notification settings - Fork 14
Bistatic Example
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.
FERS is a simulator for radar systems.
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]
FERS takes as input:
- An xml file (with the extension ".fersxml") which describes the entire simulation.
- One or more files containing pulse waveform data. The fersxml file associates these with specific transmitters in the simulation.
It returns as output:
- One or more files representing the raw radar return at the terminals of each receiver in the simulation.
- An optional xml file containing additional information about the simulation.
The input and output data can be in one of two forms:
- 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.
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.
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:
<!--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>
<!--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>
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:
<?xml version="1.0"?>
<!--Simulation of Tx, Rx, and Target flying in straight line using single .fersxml-->
<!--Run 'xmllint --format --recover SingleTarget.fersxml --output SingleTarget.fersxml' to indent file-->
<!DOCTYPE simulation SYSTEM "../../fers-xml.dtd">
<simulation name="SingleTaget">
<parameters>
<starttime>0</starttime>
<endtime>180</endtime> <!-- This is a 180 second simulation -->
<c>299792458</c>
<rate>204800</rate> <!-- Baseband sample rate of 204.8 KHz -->
<adc_bits>16</adc_bits>
<interprate>1000</interprate>
<oversample>1</oversample>
<export binary="true" csv="false" xml="false"/>
</parameters>
<pulse name="TxWaveform" type="file" filename="../../../Waveforms/txWaveFormNormalised.h5">
<power>16400</power> <!-- 10 kW * 2.15 dB (to create EIRP of dipole type pattern) -->
<carrier>89e6</carrier>
</pulse>
<timing name="TxClock">
<frequency>204800</frequency> <!-- Sampling at 204.8 KHz -->
</timing>
<timing name="RxClock">
<frequency>204800</frequency> <!-- Sampling at 204.8 KHz -->
<random_freq_offset>0.01</random_freq_offset><!-- Approximately 50 ppb, typical for good OCXO -->
</timing>
<antenna name="RxYagiAntenna" 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>
<antenna name="TxIsoAntenna" pattern="isotropic">
<efficiency>1</efficiency>
</antenna>
<!-- TxRxBaseLine is 74460m for Tx to Rx-->
<platform name="TxPlatform">
<motionpath interpolation="static">
<positionwaypoint>
<x>258804.41</x>
<y>6228720.84</y>
<altitude>397</altitude>
<time>0</time>
</positionwaypoint>
</motionpath>
<fixedrotation>
<startazimuth>0</startazimuth>
<startelevation>0</startelevation>
<azimuthrate>0</azimuthrate>
<elevationrate>0</elevationrate>
</fixedrotation>
<transmitter name="Tx" type="continuous" antenna="TxIsoAntenna" pulse="TxWaveform" timing="TxClock">
<prf>0.001</prf>
</transmitter>
</platform>
<platform name="RefRxPlatform">
<motionpath interpolation="static">
<positionwaypoint>
<x>287942.01</x>
<y>6297267.09</y>
<altitude>241</altitude>
<time>0</time>
</positionwaypoint>
</motionpath>
<fixedrotation>
<startazimuth>204.2</startazimuth><!-- towards Tx -->
<startelevation>0</startelevation><!-- horizontal -->
<azimuthrate>0</azimuthrate>
<elevationrate>0</elevationrate>
</fixedrotation>
<receiver name="RefRx" type="continuous" antenna="RxYagiAntenna" timing="RxClock">
<prf>0.001</prf>
<window_skip>0</window_skip>
<window_length>180</window_length>
<noise_temp>438.4</noise_temp><!--4 dB NF as per the minimal frontend -->
</receiver>
</platform>
<platform name="SurvRxPlatform">
<motionpath interpolation="static">
<positionwaypoint>
<x>287946.01</x><!-- 6m East of ref antenna (to be pedantic) -->
<y>6297267.09</y>
<altitude>241</altitude>
<time>0</time>
</positionwaypoint>
</motionpath>
<fixedrotation>
<startazimuth>125</startazimuth><!-- towards middle of flight path -->
<startelevation>10</startelevation><!-- slight upwards -->
<azimuthrate>0</azimuthrate>
<elevationrate>0</elevationrate>
</fixedrotation>
<receiver name="SurvRx" type="continuous" antenna="RxYagiAntenna" timing="RxClock">
<prf>0.001</prf>
<window_skip>0</window_skip>
<window_length>180</window_length>
<noise_temp>438.4</noise_temp><!--4 dB NF as per the minimal frontend -->
</receiver>
</platform>
<platform name="target1Platform">
<motionpath interpolation="linear">
<positionwaypoint>
<x>331995.77</x>
<y>6291261.10</y>
<altitude>10000.00</altitude>
<time>0</time>
</positionwaypoint>
<positionwaypoint>
<x>305242.56</x>
<y>6267172.40</y>
<altitude>5000.00</altitude>
<time>180</time>
</positionwaypoint>
</motionpath>
<fixedrotation>
<startazimuth>0.0</startazimuth>
<startelevation>0.0</startelevation>
<azimuthrate>0</azimuthrate>
<elevationrate>0</elevationrate>
</fixedrotation>
<target name="Target1">
<rcs type="isotropic">
<value>200</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:
% 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
%% 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);
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".
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
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
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
%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);