Skip to content
Snippets Groups Projects
Commit bf1f35cb authored by Daniel van der Schuur's avatar Daniel van der Schuur
Browse files

Copied Matlab dir from SVN. Added readme.md

parents
Branches
No related tags found
No related merge requests found
Showing
with 1268 additions and 0 deletions
%% BF weights for TABs ARTS
%
% This script implements the equation on the third line on slide 16 of the
% presentation "Beamforming for ARTS" given by Stefan Wijnholds during an
% ARTS project meeting on April 4, 2018. The script produces a matrix
% containing the phases of the beamformer weights of size Ndish x NTAB,
% where Ndish is the number of dishes and NTAB is the number of TABs. It is
% assumed that the dishes for a Uniform Linear Array and that the TABs are
% equidistantly spaced between center of the compound beam and the first
% grating response. It is also assumed that the delay is already
% compensated for the center of the compound beam.
%
% SJW, 4 April 2018
%% start with a clean workspace
clear
close all
%% calculate phases
Ndish = 10;
NTAB = 12;
phase = zeros(Ndish, NTAB);
% determine beta, taking into account the TAB indexing conventions for ARTS
TABidx = -floor(NTAB/2):floor((NTAB-1)/2);
beta = TABidx / NTAB;
% define dish locations measured in integer multiples of the common
% quotient baseline
n = 0:(Ndish-1);
% calculate phases
phase = 2 * pi * n.' * beta;
phase_n = n.' * beta;
% show result
imagesc(phase_n)
colorbar
title(['BF weight phases * 2*pi [rad]'])
xlabel(['TABs']);
ylabel(['Dishes']);
%-----------------------------------------------------------------------------
%
% Copyright (C) 2016
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: R. de Wild, 2015 (Original)
% E. Kooistra, 2016
%
% Purpose : Calculate FIR filter coefficients for Apertif channel
% filterbank using fircls1.
% Description :
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% workspace initiation
clear all
close all
fig=0;
% preset FIR-filter parameters
K = 64; % Number of channels
Taps = 8; % Number of taps, even 4 could be sufficient (erko)
M = Taps*K; % Number of filter coefficients (taps)
h_ix = 1:M; % coefficient index
nbit = 9; % bits/coefficient = 1 sign + (nbit-1) mantissa
fs = 781250; % sampling clock = 800.0 MHz / 1024
f_nyq = fs/2; % Nyquist frequency
f_pb = fs/K/2; % end of passband
f_chan = fs/K;
% normalized frequency axis & normalized amplitude axis
w_pb = f_pb/f_nyq; % = f_chan
% The fircls1 pass band deviation and stop band deviation are positive
% fractions of 1. The ripple in dB needs to be divided by 10 to get from
% dB = 10*log10() the log10() and divided by 2 because it is a relative
% voltage value (instead of a relative power value).
% When the pass band ripple in dB is positive then the linear factor is
% sligthly larger than 1, so subtract 1 to get the pass band deviation.
% The pass band deviation defines the +- fraction around 1. The stop band
% 'ripple' in dB is negative and defines the attenuation. The stop band
% deviation is the fraction of 1 that remains in the stop band. Therefore
% both the pass band ripple and the stop band attenuation result both in
% linear deviations that are close to 0.
% The fircls1 description defines DEVP is the maximum passband deviation
% or ripple (in linear units) from 1, and DEVS is the maximum stopband
% deviation or ripple (in linear units) from 0.
r_pb = 10^(0.025)-1; % passband ripple = 0.5 dB
r_sb = 10^(-3.0); % stopband ripple = -60.0 dB
% compute M filter-coefficients
h = fircls1(M-1, w_pb, r_pb, r_sb);
hfs_abs = abs(fftshift(fft(h ,M)));
% compute quantized filter coefficients
hmax = max(h);
hq = double( uencode(h, nbit, hmax, 'signed') );
hqfs_abs = abs(fftshift (fft( hq ,M))) * sum(h)/sum(hq); % normalize to response for DC
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Print FIR-filter parameters
sprintf([ ...
' fs = sample rate = %6.2f [Hz] \n' , ...
' f_chan = channel bandwidth = %6.2f [Hz]\n' , ...
' r_pb = pass band deviation = %9.7f = %6.2f dB_W ripple\n' , ...
' r_sb = stop band deviation = %9.7f = %6.2f dB_W attenuation\n' , ...
' M = number of coefficients = %d'], ...
fs, f_chan, r_pb, 20*log10(1+r_pb), r_sb, 20*log10(r_sb), M)
% Save FIR-filter-coefficients
% N.B. - read '.txt'-file with 'wordpad' or use \r\n !!!
file_name = ['FIR_LPF_ApertifCF.txt'];
FIRtable = [ h(h_ix) ] ;
fid = fopen(file_name , 'w');
fprintf(fid ,'%14.10f \n', FIRtable);
fclose(fid);
% Plot FIR-filter coefficients
fig=fig+1;
figure('position', [300+fig*20 200-fig*20 1000 800]);
figure(fig);
plot(hq);
title(['FIR filter coefficients (', num2str(nbit), ' bits)'] );
grid on;
% Plot FIR-filter amplitude characteristic
fig=fig+1;
figure('position', [300+fig*20 200-fig*20 1000 800]);
figure(fig);
f = (h_ix - M/2-1) * fs/M / f_chan;
plot ( f, 20.0 * log10 ( hfs_abs ), 'r-', ...
f, 20.0 * log10 ( hqfs_abs ), 'k-') ;
xlo = f(1);
xhi = f(M);
xlo = -3;
xhi = 3;
xlim( [xlo xhi] );
grid on;
zoom on;
title('FIR filter transfer function');
text( xlo, -5, ['sampling rate = ', num2str(fs), ' [Hz]']);
text( xlo, -10, ['channel bandwidth = ', num2str(f_chan), ' [Hz]']);
text( xlo, -15, ['number of taps = ', num2str(Taps)]);
text( xlo, -20, ['number of channels = ', num2str(K)]);
text( xlo, -25, ['number of coefficients = ', num2str(M)]);
text( xlo, -30, ['number of bits/coefficient = ', num2str(nbit)]);
xlabel('Frequency [channels]');
ylabel('Power [dB]');
print -dpng 'arts_fir';
File added
This diff is collapsed.
File added
This directory contains Matlab code for modelling DSP aspects of Apertif:
- Functions are used in scripts.
- Scripts can run in Matlab
- Figure files are saved figure plots of scripts
- Data files are input read by a scripts, or output saved by a the script
1) Fringe stopping:
fringe.m Script Plot the fringe due to the varying difference in geometrical delay.
fringe.jpg Figure Fringe plot saved by fringe.m (figure in ASTRON-MEM-199)
phase_tracking.m Script Plot the phase tracking (PT) phase and phase error as function of the
varying geometrical delay (see ASTRON-MEM-199).
phase_tracking_phases.txt Data Input reference data (the PT piecewise linear coefficients) for HDL
simulation saved by phase_tracking.m
phase_tracking_coefficients.txt Data Output reference data (the PT expected phases) for HDL simulation
saved by phase_tracking.m
phase_lookup.m Script Plot and save lookup table for conversion from phi to pair of re, im
2) Quantization
try_uencode.m Script Try Matlab uencode to determine optimum quantisation, better use
quantize.m
quantize.m Function Quantize signed input data
try_quantize.m Script Run quantize.m
compensation_and_selection_gain.m Script Determine gain_w and gain value for optimum requantisation
try_power_requantize.py Python Investigate requantization of data and auto power for e.g. Stokes I
and IQUV in Arts
apertif_arts_firmware_model.py Python Model fixed point signal levels in Apertif and Arts, see
../doc/ASTRON_RP_010888_Apertif_Arts_firmware_model.pdf
3) Low pass FIR filter coefficients
See also:
- $RADIOHDL/libraries/dsp/doc/filterbank.txt
- $RADIOHDL/libraries/dsp/filter/src/python/ for diff* FIR filter files and recreate* FIR files from dat
to mif/hex format
Fsub original from LOFAR:
- data/Coeffs16384Kaiser-quant.dat Data Original PFIR filter coefficients from LOFAR 1.0 subband filterbank
(16 tap, 1024 point FFT), the script that created these PFIR
coefficients is not available anymore (Erko looked in old
repositories back to 2005 of Lofar software and Station firmware
but could not find it.)
- data/Coeffs16384Kaiser-quant-withdc.dat = data/Coeffs16384Kaiser-quant.dat
Fsub adjusted to have no DC in PFIR coefficients per polyphase
- data/Coeffs16384Kaiser-quant-nodc.dat = Used in Apertif Fsub obtained from data/Coeffs16384Kaiser-quant.dat
using run_pfir_coeff.m -r 18333 as commited, so with application =
'lofar_subband', which selects:
. config.hp_adjust = false
. config.dc_adjust = true
Fsub bypass (equivalent to not having a PFIR section, useful to isolate issues between PFB and only FFT)
- data/run_pfir_coeff_m_bypass_16taps_1024points_16b.dat
Fsub bypass per polyphase, used to diagnose quantization and spurious issues per polyphase, but probably not
so useful
- data/run_pfir_coeff_m_bypass_16taps_1024points_16b_polyphase0.dat -- only polyphase 0 has coeff != 0
- data/run_pfir_coeff_m_bypass_16taps_1024points_16b_polyphase1.dat -- only polyphase 1 has coeff != 0
- data/run_pfir_coeff_m_bypass_16taps_1024points_16b_polyphase2.dat -- only polyphase 2 has coeff != 0
- data/run_pfir_coeff_m_bypass_16taps_1024points_16b_polyphase3.dat -- only polyphase 3 has coeff != 0
Fchan bypass (equivalent to not having a PFIR section, useful to isolate issues between PFB and only FFT)
- data/run_pfir_coeff_m_bypass_8taps_32points_9b.dat = for Arts SC4: N = 32, L = 8, coeff_w = 9.
- data/run_pfir_coeff_m_bypass_8taps_64points_9b.dat = for Apertif
bypass PFIR for Fchan using ones at tap 0 and zeros at other taps.
Obtained using run_pfir_coeff.m -r 18333, but with application =
'test_bypass' which selects N = 64, L = 8, coeff_w = 9.
Fchan with half power at +-fchan/2
- data/run_pfir_coeff_m_flat_hp_fircls1_8taps_32points_9b.dat = for Arts SC4
- data/run_pfir_coeff_m_flat_hp_fircls1_8taps_64points_9b.dat = for Apertif
PFIR for Fchan in Apertif obtained using run_pfir_coeff.m -r 18333
but with application = 'apertif_channel' which selects:
. config.hp_adjust = true
. config.dc_adjust = false
Fchan with half power at +-fchan/2 and no DC in PFIR coefficients per polyphase
- data/run_pfir_coeff_m_flat_hp_no_dc_fircls1_8taps_32points_9b.dat = for Arts SC4
- data/run_pfir_coeff_m_flat_hp_no_dc_fircls1_8taps_64points_9b.dat = for Apertif
PFIR for Fchan in Apertif obtained using run_pfir_coeff.m -r 18746
but with application = 'apertif_channel' which for -r 18746
selects:
. config.hp_adjust = true
. config.dc_adjust = true (was false in -r 18333)
FIR_LPF_ApertifCF.m Script Calculate FIR filter coefficients for Apertif channel filterbank
using fircls1 (original by Ronald de Wild).
FIR_LPF_ApertifCF.txt Data Floating point FIR coefficients saved by FIR_LPF_ApertifCF.m
arts_fir.png Figure FIR filter transfer function plot saved by FIR_LPF_ApertifCF.m
pfir_coeff.m Function Compute polyphase filterbank coefficients (same purpose as
FIR_LPF_ApertifCF.m but with more options)
pfir_coeff_adjust.m Function Compute polyphase filterbank coefficients with optionbal half power
bandwidth adjustment (calls pfir_coeff.m)
pfir_coeff_dc_adjust.m Function Apply DC adjustment to polyphase filterbank coefficients
run_pfir_coeff.m Script Run pfir_coeff_adjust.m and pfir_coeff.m to show filter response in
time and frequency domain, and optionally calls pfir_coeff_dc_adjust.m
4) FFT
sinusoids_and_fft_frequency_bins.m Script Code on DFT and DTFT from Matlab blog on internet
fft_sinus_noise_scaling.m Script to investigate sinus and noise levels of FFT input and output
try_fft.m Script Try DFT and DTFT
clk_spectrum Script Investigate EMI of clock and random data toggling
5) Data path functions
wg.m Function Waveform generator per block of data
dt.m Function Delay tracking per block of data
bsn_source.m Function Block Sequence Number source per block of data
pfir.m Function Polyphase FIR filter per block of data
pfft.m Function FFT per block of data
ds.m Function Doppler frequency shift per block of data
reorder_serial.m Function Select data from block of data
corner_turn.m Function Collect M blocks of in_data(1:K) and then transpose [M] and [K] for
corner turn
6) Polyphase filterbank
lofar/polyphase_demo_unquantized.m Script original by Jan Stemerdink
one_pfb.m Script Run data path model with subband polyphase filterbank (real input)
delay_tracking_pfb.m Script Based on one_pfb.m to simulate polyphase filterbank response on a delay step
psk_pfb.m Script Based on one_pfb.m to simulate polyphase filterbank response on PSK input
two_pfb.m Script Run data path model with subband polyphase filterbank followed by a channel
polyphase filterbank
7) HDL reference data
run_pfir.m Script Run the PFIR with real input to create HDL reference data (based on one_pfb.m)
run_pfft.m Script Run the PFFT with real input to create HDL reference data (based on one_pfb.m)
run_pfb.m Script Run the PFB with real input to create HDL reference data (based on one_pfb.m)
run_pfft_complex.m Script Run the PFFT with complex input to create HDL reference data (based on one_pfb.m)
run_pfb_complex.m Script Run the PFB with complex input to create HDL reference data (based on one_pfb.m)
8) Correlator
correlator_null_clip_or_wrap.m Script Investigate impact of input nulling, clipping or wrapping on correlator output
9) Beamformer
BFweights.m Script BF weights for TABs ARTS (original by Stefan Wijnholds).
beamformer_wrap_clip.m Script Compare wrapping or clipping of intermediate beamformer sum
\ No newline at end of file
%-----------------------------------------------------------------------------
%
% Copyright (C) 2019
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: E. Kooistra, 2019
%
% Purpose : Model wrapping in the beamformer
%
% The internal beamformer sum can have significant bit growth. With 14 bit
% input at the ADC, log2(sqrt(1024)) = 5 bit extra for the PFB processing
% gain and log2(96) = 6.6 bit extra for the BF gain, the maximum internal
% beamformer sum is about 25 bit.
% For the final beamformer sum only w = 8 bits will be output. Therefor
% it seems a waste to still have to internally use 25 bits that require
% logic resources and IO resources on the ring. If the wrapped sum is used
% then less bits need to be used. Some extra bits are still needed to be
% able to distinguish wrapped final sums from correct final sums. Instead
% of 25 bits, e.g. use and transport 16 bit beamlet sums within the
% beamformer.
%
% The suppression of the beamformer outside the main beam makes that RFI
% outside the main beam may still fit in the w = 8 bit final sum.
% However intermediate beamformer sums can exceed this w = 8 bit output
% range. If the intermediate sum is clipped, then the output will be
% corrupted, because the clipping also flattens the weak astronomical
% signal that is on top of the RFI. If the intermediate sums are wrapped,
% then the information of the astronomical signal is preserved. In the
% final sum the RFI is then still attenuated and the astronomical signal
% remains undisturbed.
%
% The astronomical signal is weak in the sense that without RFI it fits
% in the w = 8 bit intermediate sum and final beamlet sum. The RFI signal
% is strong in the sense that it causes intermediate beamlet sums to
% overflow, but it is weak enough to still fits in the w = 8 bit beamlet
% output sum, provided that the RFI is not in the direction of the main
% beam.
clear all;
close all;
fig=0;
%% Settings
c = 3e8; % speed of light
N_theta= 1000; % Number of beam angles to evaluate over 90 degrees
N_ant = 96; % Number of antennas in array
f = 50e6; % RF frequency in LBA band
L = c/f; % RF wave length
b = 0.8*L; % distance between antennas, choose < L to have one main lobe
w = 8; % number of bits in beamlet
A = 3; % amplitude of weak astronomical signal, choose A << R
R = 30; % amplitude of strong RFI signal, choose R < 2**(w-1)
disp(sprintf(['. RF frequency = %5.1f MHz\n', ...
'. RF wave length = %5.1f m\n', ...
'. Antenna distance = %5.1f m\n', ...
'. Number of antennas = %d\n'], ...
f/1e6, ...
L, ...
b, ...
N_ant));
%% Random logic signal toggling at clock frequency fclk
s_period = 2^w;
s_mod = 2^(w-1);
s_max = s_mod-1;
s_min = -s_mod;
thetas = 90 * (0:N_theta-1)/N_theta;
DTs = b / c * sin(thetas*2*pi/360);
phis = 2*pi*f*DTs;
ants = 0:N_ant-1;
bf_sums_maxs = zeros(1, N_theta);
bf_sums = zeros(1, N_theta);
bf_sum_wraps = zeros(1, N_theta);
bf_sum_clips = zeros(1, N_theta);
d_wraps = zeros(1, N_theta);
d_clips = zeros(1, N_theta);
for I = 1:N_theta
% Calculate beamformer sum, using intermediate wrapping or clipping
phi = phis(I);
kphis = phi*ants;
% Sort kphis to have worst case order where the BF inputs first add
% all up constructively and then all down constructively, to have
% the largest intermediate BF sum results.
kphis = sort(mod(phi*ants, 2*pi));
s = 0;
s_wrap = 0;
s_clip = 0;
for k = 1:N_ant
a = round(A + R*cos(kphis(k)));
%a = round(A + R*sin(kphis(k)));
s = s + a;
if abs(s) > bf_sums_maxs(I)
bf_sums_maxs(I) = abs(s);
end
s_wrap = wrap(s_wrap + a, s_period);
s_clip = clip(s_clip + a, s_min, s_max);
end
bf_sums(I) = s;
bf_sum_wraps(I) = s_wrap;
bf_sum_clips(I) = s_clip;
% Derive difference with full range final beamformwer sum
d_final_wraps(I) = s - s_wrap;
d_final_clips(I) = s - s_clip;
% Derive difference with w bit output beamformwer sum
d_output_wraps(I) = wrap(s, s_period) - s_wrap;
d_output_clips(I) = clip(s, s_min, s_max) - s_clip;
end
%% Plots
xfig = 300;
yfig = 200;
xfigw = 1000;
yfigw = 800;
dfig = 20;
%% Plot final beamformer sums
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(thetas, bf_sums, 'k', thetas, bf_sum_wraps, 'r--', thetas, bf_sum_clips, 'b--');
title('Final beamformer sums');
xlabel('Beam angle [degrees]');
ylabel('Final sum');
grid on;
%% Plot abs maximum of intermediate beamformer sums
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(thetas, bf_sums_maxs, 'r');
title('Maximum of intermediate beamformer sums');
xlabel('Beam angle [degrees]');
ylabel('Intermediate maximum sum');
grid on;
%% Plot differences between final sum and wrapped sum, clipped sum
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(thetas, d_final_wraps, 'r', thetas, d_final_clips, 'b--');
title('Difference final beamformer sums');
xlabel('Beam angle [degrees]');
ylabel('Difference of final sum');
grid on;
%% Plot differences between output sum and wrapped sum, clipped sum
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(thetas, d_output_wraps, 'r', thetas, d_output_clips, 'b--');
title('Difference output beamformer sums');
xlabel('Beam angle [degrees]');
ylabel('Difference of final sum');
grid on;
%-----------------------------------------------------------------------------
%
% Copyright (C) 2016
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: E. Kooistra, 2016
%
% Purpose : BSN source per block of data
% Description : Increment ctrl.bsn for every block.
function [state] = bsn_source(ctrl)
% Increment BSN for next call
state = ctrl;
state.bsn = ctrl.bsn + 1;
\ No newline at end of file
%-----------------------------------------------------------------------------
%
% Copyright (C) 2019
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%--------------------------------------------------------------------------
% Author: E. Kooistra, 2019
%
% Purpose : Clip input s into range [clip_min, clip_max]
function [s_clip] = clip(s, clip_min, clip_max)
s_clip = s;
if s > clip_max
s_clip = clip_max;
elseif s < clip_min
s_clip = clip_min;
end
end
%-----------------------------------------------------------------------------
%
% Copyright (C) 2019
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: E. Kooistra, 2019
%
% Purpose : Spectrum of random toggling at certain clock frequency
clear all;
close all;
fig=0;
%% Settings
mode = 'square';
%mode = 'random';
mode = 'combine';
if strcmp(mode, 'square')
M = 1; % Number of spectra to sum
else
M = 1000; % Number of spectra to sum
end
N = 1024; % FFT size
fs = 800; % sample frequency
fclk = 25; % clock frequency
%fclk = 125; % clock frequency
t =(0:N-1)/fs; % time axis
f = (0:N/2-1)/N * fs; % positive frequency axis
%% Random logic signal toggling at clock frequency fclk
clk = sin(2*pi*fclk*t);
clk = (clk>0) * 2 - 1; % clock square wave
prev_clk = clk(N);
sq = zeros(size(clk));
data = zeros(size(clk));
YYsum = zeros(1, N/2);
for m = 1:M
prev_sq = (rand>0.5)*2-1;
prev_data = (rand>0.5)*2-1;
for r = 1:N
if clk(r) == 1 && prev_clk == -1 % detect clock rising edge
sq(r) = -prev_sq; % logic square wave toggling (independent of M)
data(r) = (rand>0.5)*2-1; % logic random toggling (use M >= 1)
else
sq(r) = prev_sq;
data(r) = prev_data;
end
prev_clk = clk(r);
prev_sq = sq(r);
prev_data = data(r);
end
if strcmp(mode, 'square')
Y = abs((fft(sq, N)));
elseif strcmp(mode, 'random')
Y = abs((fft(data, N)));
else
Y = abs((fft(sq + data, N)));
end
YY = Y .* Y;
YY = YY(1:N/2);
YYsum = YYsum + YY;
end
YYsum = YYsum / M;
%% Plots
xfig = 300;
yfig = 200;
xfigw = 1000;
yfigw = 800;
dfig = 20;
%% Plot clock
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(t, 1.2*clk, 'r', t, data, 'b')
grid on;
%ylim([-1.5, 1.5])
%% Plot spectrum
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(f, 10*log10(YYsum))
grid on;
xlim([0, fs/2])
%-----------------------------------------------------------------------------
%
% Copyright (C) 2017
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: Eric Kooistra, 30 mar 2017
%
% Purpose : Model requantization compensation gain and selection gain
%
% Description :
% When a gain is applied to an input value then the output value has
% bit growth: out_dat_w = in_dat_w + gain_w. In addition the output
% value may also be requantized to req_dat_w. The script has two aims:
%
% 1 Compensate for some input loss by scaling the output back to the
% nominal output level using a gain = 1/loss. The loss may occur e.g.
% in case one or more inputs in a beamformer are switched off. If
% nominal the beamformer has 8 inputs, but now it has 7, then the
% gain = 8/7 to compensate the loss of 7/8 and thus preserve the
% nominal level of 8/8 = 1.
%
% 2 Determine how much gain_w is needed to support selecting the
% appropriate range of out_dat bits for fixed requantisation from
% in_dat_w via out_dat_w to to req_dat_w.
%
% Using compensation gain = 1/loss (1) and selection gain (2) the
% in_dat is scaled such that the fixed requantization can be set for
% the nominal input level (1) and has the optimum balance between
% dynamic range and resolution (2).
%
clear all;
close all;
plot_enable = false;
%% (1) Compensation gain to restore nominal input level
% The gain can be also used to scale the input data to compensate for
% some input loss = 7/8, e.g. gain = 1/loss = 8/7 = 1.143. In this case
% the number of bits for the requantized data remains the same as for
% the input data, the gain is used to restore the nominal input level.
% If this compensation gain (1) is combined with the selection gain (2),
% then it is sufficient to consider only compensation gain < 2.
%
% Suppose:
% in_dat_w = 4
% req_dat_w = 4 = in_dat_w (consider only scaling here, no change in
% number of bits.)
% Choose:
% gain_w = 5
% out_dat_w = 8 = gain_w + in_dat_w - 1 (-1 to skip doub le sign bit)
% The fixed requantization setting for out_dat selects range:
% lsb_w = 3 = gain_w - 2
% msb_w = 1 = out_dat_w -(req_dat_w+lsb_w)
% = (gain_w + in_dat_w - 1) - req_dat_w-lsb_w
% = gain_w + req_dat_w - 1 - req_dat_w-(gain_w-2)
% = 1 (fixed)
% so:
% req_dat = out_dat[req_dat_w+lsb_w-1:lsb_w]
% = out_dat[6:3]
% Hence the out_dat already skips the double sign bit, then from out_dat
% msb_w = 1 MSbit get truncated and lsb_w = gain_w - 2 get rounded, as
% shown by:
%
% [3 2 1 0]
% in_dat = s i j k
%
% [4 3 2 1 0]
% gain 2**( 0) = 1 s 1 0 0 0
% gain 2**(-1) = 0.5 s 0 1 0 0
% gain 2**(-2) = 0.25 s 0 0 1 0
% gain 2**(-3) = 0.125 s 0 0 0 1
%
% [7 6 5 4 3 2 1 0]
% out_dat 2**( 0) = 1 s s i j k 0 0 0 0 0 0
% out_dat 2**(-1) = 0.5 s s s i j k 0 0 0 0 0
% out_dat 2**(-2) = 0.25 s s s s i j k 0 0 0 0
% out_dat 2**(-3) = 0.125 s s s s s i j k 0 0 0
% out_dat 2**(-4) = 0.0625 s s s s s s i j k 0 0
% out_dat 2**(-5) = 0.03125 s s s s s s s i j k 0
%
% req_dat = s i j k
%
% A compensation gain of 1 yields req_dat = in_dat. The compensation
% gain can be set between 0.5 and 2. The gain_w should be >= req_dat_w.
% From the simulation it follows that in fact the gain_w should be
% about 3 bits more to avoid too much requantization noise, so choose
% compensation gain_w = req_dat_w + 3.
%
% The compensation gain of 1 corresponds to [s 1 ...], independent of
% gain_w, and gain_w >= 2 (because lsb_w >= 0).
in_dat_w = 8;
N = 1000;
t = 0:N-1;
in_full_scale = 1;
loss = 0.99;
loss = 7/8;
%loss = 1;
if loss<=1
ampl = loss;
else
ampl = 1/loss; % avoid input overflow
end
in_dat = ampl * rand(1, N);
q_in_dat = quantize(in_dat, in_full_scale, in_dat_w);
q_in_dat_snr = 10*log10(sum(abs(in_dat).^2) / sum(abs(in_dat - q_in_dat).^2));
disp(sprintf('. ampl = %f', ampl));
disp(sprintf('. in_dat_w = %d', in_dat_w));
disp(sprintf('. q_in_dat SNR = %6.3f (theoretical %6.3f)', q_in_dat_snr, in_dat_w * db(2)));
in_dat_loss = in_dat * loss;
q_in_dat_loss = quantize(in_dat_loss, in_full_scale, in_dat_w);
q_in_dat_loss_snr = 10*log10(sum(abs(in_dat_loss).^2) / sum(abs(in_dat_loss - q_in_dat_loss).^2));
gain = 1/loss;
gain_full_scale = 2;
disp(sprintf('. loss = %f', loss));
disp(sprintf('. gain = 1/loss = %f', gain));
disp(sprintf('. q_in_dat_loss SNR = %f', q_in_dat_loss_snr));
for gain_w = floor(in_dat_w/2):2*in_dat_w
q_gain = quantize(gain, gain_full_scale, gain_w);
q_in_dat_recovered = q_in_dat_loss * q_gain;
q_in_dat_recovered_snr = 10*log10(sum(abs(in_dat).^2) / sum(abs(in_dat - q_in_dat_recovered).^2));
disp(sprintf('. q_in_dat_recovered SNR = %6.3f (gain_w = %2d, q_gain = %f)', q_in_dat_recovered_snr, gain_w, q_gain));
end
%% (2) Selection gain to fit fixed requantization to less bits
% The input data needs to be requantized into less bits. By means of a
% gain it is possible to scale the input such that either the MSbit or
% the LSbits of in_dat are preserved, or somewhere in between. More
% MSbits means more dynamic range, more LSbits mean more resolution.
%
% The output data width grows due to the product of gain and input
% data. Choose out_dat_w = gain_w + in_dat_w - 1. This skips the
% double sign bit of the product and assumes that full scale amplitude
% of the complex gain = full scale real = full scale imag to not cause
% overflow. The output data is requantization to req_dat_w.
%
% Suppose:
% in_dat_w = 6 nof bits in the input data
% req_dat_w = 4 nof bits after requantization
% then choose:
% reduce_w = 2 = in_dat_w - req_dat_w
% gain_w = 4 = reduce_w + 2, +1 for sign bit and +1 to fit +2**reduce_w
% out_dat_w = 9 = gain_w + in_dat_w - 1
% such that:
% gain = 2**0 = 1 : keep the MSbits and round 2 LSbits from in_dat
% gain = 2**1 = 2 : truncate 1 MSbits and round 1 LSbits from in_dat
% gain = 2**2 = 4 : truncate 2 MSbits and keep the LSbits from in_dat
% the fixed requantization setting for req_dat selects range:
% lsb_w = 2 = reduce_w
% msb_w = 3 = out_dat_w - (req_dat_w+reduce_w)
% = (gain_w + in_dat_w - 1) - req_dat_w-reduce_w
% = gain_w + in_dat_w - 1 - req_dat_w-(in_dat_w-req_dat_w)
% = gain_w + in_dat_w - 1 - req_dat_w- in_dat_w+req_dat_w
% = gain_w-1
% so:
% req_dat = out_dat[req_dat_w+reduce_w-1:reduce_w] = out_dat[5:2]
% so gain_w-1 = reduce_w + 1 = 3 MSbits get truncated and gain_w-2 =
% reduce_w = 2 LSbits get rounded, as shown by:
%
% [5 4 3 2 1 0]
% in_dat = s a b c d e
%
% [3 2 1 0]
% gain 2**2 = 4 = s 1 0 0
% gain 2**1 = 2 = s 0 1 0
% gain 2**0 = 1 = s 0 0 1
%
% [8 7 6 5 4 3 2 1 0]
% out_dat 2**2 = 4 = s s a b c d e 0 0
% out_dat 2**1 = 2 = s s s a b c d e 0
% out_dat 2**0 = 1 = s s s s a b c d e
%
% [ 3 2 1 0]
% req_dat = s c d e gain = 2**2 = 4
% req_dat = s b c d gain = 2**2 = 2
% req_dat = s a b c gain = 2**0 = 1
%
% The selection gain is 2^0 = 1 to preserve the MSbits and 2^reduce_w
% to preserve the LSbits. The selection gain of 1 corresponds to
% [s ... 1], independent of gain_w, and gain_w >= 2 (because reduce_w
% >= 0).
%% Combining compensation gain (1) with selection gain (2)
%
% The compensation gain and selection gain can be implemented as two
% seperate stages, but the aim is to implement them together in one
% stage. All selection gains maps to compensation gain = 1. The corner
% case is selection gain = 1, because then the compensation gain cannot
% reuse the LSBits of the selection gain. From (1) and (2) above it
% followed that:
%
% 1) The compensation gain of 1 corresponds to [s 1 ...], independent
% of gain_w, and gain_w >= 2 (because lsb_w >= 0).
% 2) The selection gain of 1 corresponds to [s ... 1], independent
% of gain_w, and gain_w >= 2 (because reduce_w >= 0).
%
% Therefore the gain_w for the combination becomes:
%
% gain_w = sel_gain_w + comp_gain_w - 2
%
% where -2 is due to that s 1 from the compensation gain can reuse the
% sign bit and one LSBit of the selection gain.
%
% For example:
% in_dat_w = 12 nof bits in the input data
% req_dat_w = 8 nof bits after requantization
% then choose:
% reduce_w = 4 = in_dat_w - req_dat_w
% sel_gain_w = 6 = reduce_w + 2, +1 for sign bit and +1 to fit +2**reduce_w
% comp_gain_w = 11 = req_dat_w + 3, +3 based on this simulation
%
% The assumption is that the compensation gain must also preserve the
% resolution when the selection gain 1 to select the MSbits.
%
% gain_w = 15 = sel_gain_w + comp_gain_w - 2 = in_dat_w + 3
% out_dat_w = 26 = gain_w + in_dat_w - 1 = 2*in_dat_w + 2
%
% The fixed requantization setting for req_dat selects range:
% lsb_w = 13 = reduce_w + comp_gain_w - 2
% msb_w = 5 = sel_gain_w-1
% req_dat = out_dat[req_dat_w+lsb_w-1:lsb_w]
% = out_dat[20:13]
%
% The out_dat range is [25:0], so lsb_w = 13 LSbits get rounded and
% msb_w = 5 bits get truncated.
% In an implementation these truncated bits could be ommitted from the
% start.
if plot_enable
%% Plot results
fig=0;
xfig = 300;
yfig = 200;
xfigw = 1000;
yfigw = 800;
dfig = 20;
%% Plot data
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(t, q_in_dat_recovered)
title(sprintf('Input data'));
grid on;
end
%-----------------------------------------------------------------------------
%
% Copyright (C) 2016
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: E. Kooistra, 2016
%
% Purpose : Collect M blocks of in_data(1:K) and then transpose [M] and [K].
% Description :
%
% The corner turn can also include the last L blocks from the previous
% interval, so then tranpsose [L+M] and [K].
%
% M=nof_block
% K=block_size
% L=tail_nof_block
%
% Tail previous buffer at in_sync:
%
% M-L+1 in_data(1:K)
% M-L+2 in_data(1:K)
% ...
% M-L+L in_data(1:K)
%
% Buffer at in_sync (i.e. when bI == 1):
% 1 in_data(1:K)
% 2 in_data(1:K)
% ...
% M in_data(1:K)
%
% Output at in_sync when output_type = 'matrix':
%
% 1 in_data(1)(1:L,1:M)
% 2 in_data(2)(1:L,1:M)
% ...
% K in_data(K)(1:L,1:M)
%
% Output at in_sync when output_type = 'serial':
%
% in_data(1)(1:L,1:M),in_data(2)(1:L,1:M), ..., in_data(K)(1:L,1:M)
%
% The in_data blocks are collected into the buffer. The out_data is the
% transposed buffer and output at the in_sync. The out_data is
% optionally prependend with L blocks from the previous buffer.
% Typically these L tail blocks can be used to reinitialize the delay
% elements in a FIR filter. The sync interval should typically match M
% in_data blocks.
%
function [state, out_data] = corner_turn(ctrl, in_data, in_sync)
L = ctrl.tail_nof_block;
M = ctrl.nof_block;
K = ctrl.block_size;
% Keep state for next call
state = ctrl;
% Corner turn output data at in_sync
out_data = [];
if in_sync
if ctrl.tail_nof_block==0
out_data = state.buffer;
else
out_data = [state.tail_buffer; state.buffer]; % prepend tail blocks from previous buffer
end
if strcmp(ctrl.output_type, 'serial')
out_data = out_data(:)'; % transpose output into 1 row for serial transport
else
out_data = out_data.'; % transpose output into K rows for processing
end
% Start new buffer
state.tail_buffer = state.buffer(M-L+1:M, :); % preserve tail
state.bI = 1;
end
% Collect input data
state.buffer(state.bI, :) = in_data; % Store new input data
% Next bI
state.bI = ctrl.bI + 1;
if state.bI>M
state.bI = 1; % missed in_sync, no output, just continue
end
%-----------------------------------------------------------------------------
%
% Copyright (C) 2017
% ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
% P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
%
%-----------------------------------------------------------------------------
% Author: Eric Kooistra, 20 apr 2017
%
% Purpose : Compare correlator input nulling, clipping or wrapping
%
% Description :
% Clipping seems preferrable because it does still contribute somewhat
% constuctive to the correlation. Clipping preserves the phase
% information (zero crossings) of the signal and a clipped signal still
% resembles the original overflow signal.
% Even a little bit (ampl = 1.1) of wrapping already gives seemingly
% random output. For severe overflow (ampl > 2) the wrapping cause extra
% zero crossings. If the wrapped signal becomes sufficiently random
% then the contribution of wrapped parts of the signal to the
% correlation will be close to zero.
% Using noise input it shows that for clipped input the correlator
% output still follows the correlator output of the full scale input
% that is used as reference (ref).
% Another option is to null the input in case of overflow. The
% correlator output can be normalized by N or by the number of non-zero
% contributions N-cnt. The plots show that nulling and scaling yield
% somewhat destructive correlator output.
% Even without RFI the signal may occasionally (e.g. ampl = 1.01)
% overflow due to the variation of the noise. For this clipping seems
% the most graceful choice.
%
% Conclusion: best choose input clipping for a correlator.
%
% Remarks:
% . This model does not investigate the effect of the channel filterbank
% on the data.
% . Delay tracking and fringe stopping will take care that the input
% b will be in phase with input a, so should we in the plots only
% look at the correlator output for phase difference close to 0 or
% should we look over the whole range? Probably look at the whole
% range, because RFI in a side lobe or little of bore sight will
% appear with a larger phase difference at input b.
% . Is the sinus input relevant or should we only look at the noise
% input? Probably the sinus input is relevant, because that is a crude
% model of RFI.
%
% Usage:
% . Try ampl = 1.001, 1.01, 1.1, 1.3, 2.3, 5, 100 for sinus input, to
% vary the amount of overflow
% . Note that for sinus input the correlator output plot is symmetrical
% around 180 degrees.
clear all;
close all;
%rng(0); % random seed for repeatable result
% Try different amplitudes
ampl = 8; % for input rand() or sin() use > 1 for overflow
% for input randn() ampl = sigma, so use >~ 0.3 for overflow
N = 1000;
rad = [0:N-1]*2*pi/N;
deg = [0:N-1]*360/N;
% Try noise or sinus inputs
input = ampl*randn(1,N); % Gaussian with sigma = ampl
input = ampl*(2*rand(1,N)-1); % Uniform full scale ampl range
input = ampl*sin(rad); % Sinus with amplitude = ampl
% Determine correlator output for the input and the phase shifted input
% for reference, null, null_scaled, clip and wrap.
in_ref = zeros(1,N);
in_null = zeros(1,N);
in_null_scaled = zeros(1,N);
in_clip = zeros(1,N);
in_wrap = zeros(1,N);
corr_ref = zeros(1,N);
corr_null = zeros(1,N);
corr_null_scaled = zeros(1,N);
corr_clip = zeros(1,N);
corr_wrap = zeros(1,N);
for d = 0:N-1
dI = d+1;
cnt = 0;
for p = 0:N-1
pI = p+1;
pd = mod(p+d, N);
pdI = pd+1;
% reference (full scale)
in_a = input(pI);
in_b = input(pdI);
if d==0
in_ref(pI) = in_a;
end
corr_ref(dI) = corr_ref(dI) + in_a * in_b;
% null
in_a = input(pI);
in_b = input(pdI);
if in_a > 1 | in_a < -1 | in_b > 1 | in_b < -1
cnt = cnt+1;
end
if in_a > 1
in_a = 0;
end
if in_a < -1
in_a = 0;
end
if in_b > 1
in_b = 0;
end
if in_b < -1
in_b = 0;
end
if d==0
in_null(pI) = in_a;
end
corr_null(dI) = corr_null(dI) + in_a * in_b;
% clip
in_a = input(pI);
in_b = input(pdI);
if in_a > 1
in_a = 1;
end
if in_a < -1
in_a = -1;
end
if in_b > 1
in_b = 1;
end
if in_b < -1
in_b = -1;
end
if d==0
in_clip(pI) = in_a;
end
corr_clip(dI) = corr_clip(dI) + in_a * in_b;
% wrap
in_a = input(pI);
in_b = input(pdI);
while in_a > 1
in_a = in_a - 2;
end
while in_a < -1
in_a = in_a + 2;
end
while in_b > 1
in_b = in_b - 2;
end
while in_b < -1
in_b = in_b + 2;
end
if d==0
in_wrap(pI) = in_a;
end
corr_wrap(dI) = corr_wrap(dI) + in_a * in_b;
end
if ampl > 1
%corr_ref(dI) = corr_ref(dI)/(ampl^2);
end
in_null_scaled = in_null;
corr_ref(dI) = corr_ref(dI)/N;
corr_null(dI) = corr_null(dI)/N;
corr_null_scaled(dI) = corr_null(dI) * N/(N-cnt); % divide by 0 will yield NaN which is fine and plots nothing
corr_clip(dI) = corr_clip(dI)/N;
corr_wrap(dI) = corr_wrap(dI)/N;
end
sum_corr_ref = sum(abs(corr_ref));
disp(sprintf('. corr_ref = %f', sum(abs(corr_ref)) /sum_corr_ref));
disp(sprintf('. corr_clip = %f', sum(abs(corr_clip)) /sum_corr_ref));
disp(sprintf('. corr_wrap = %f', sum(abs(corr_wrap)) /sum_corr_ref));
disp(sprintf('. corr_null = %f', sum(abs(corr_null)) /sum_corr_ref));
disp(sprintf('. corr_null_scaled = %f', sum(abs(corr_null_scaled))/sum_corr_ref));
%% Plot results
fig=0;
xfig = 300;
yfig = 200;
xfigw = 1000;
yfigw = 800;
dfig = 20;
%% Plot input as function of p
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(deg, in_ref, 'b', deg, in_null, 'c', deg, in_null_scaled, 'm', deg, in_clip, 'g', deg, in_wrap, 'r')
legend('reference', 'null', 'null scaled', 'clip', 'wrap');
xlabel('input period [degrees]');
ylabel('input level');
xlim([0 360]);
ylim([-1.1 1.1]*ampl);
title(sprintf('Input (ampl = %5.3f)', ampl));
grid on;
%% Plot correlator output as function of d
fig=fig+1;
figure('position', [xfig+fig*dfig yfig-fig*dfig xfigw yfigw]);
figure(fig);
plot(deg, corr_ref, 'b', deg, corr_null, 'c', deg, corr_null_scaled, 'm', deg, corr_clip, 'g', deg, corr_wrap, 'r')
legend('reference', 'null', 'null scaled', 'clip', 'wrap');
xlabel('phase difference between input a and input b [degrees]');
ylabel('correlator output');
xlim([0 360]);
title(sprintf('Correlator output (ampl = %5.3f)', ampl));
grid on;
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment