diff --git a/applications/lofar2/doc/prestudy/station2_sdp_timing.py b/applications/lofar2/doc/prestudy/station2_sdp_timing.py new file mode 100644 index 0000000000000000000000000000000000000000..6ccf4022af17a6d0e8c8f2b8b5d5f8b72fb7ceb3 --- /dev/null +++ b/applications/lofar2/doc/prestudy/station2_sdp_timing.py @@ -0,0 +1,130 @@ +############################################################################### +# +# Copyright 2019 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +############################################################################### + +# Author: Eric Kooistra + +"""Show PPS and SDP timing grid information for LOFAR2.0 Station + +Usage: +> python station2_sdp_timing.py -h + +""" + +import argparse +import math + +figNr = 1 + +# Parse arguments to derive user parameters +_parser = argparse.ArgumentParser('station2_sdp_timing') +_parser.add_argument('-n', default=10, type=int, help='Number of seconds') +_parser.add_argument('-f', default=200, type=int, help='Sample frequency in [MHz]') +_parser.add_argument('-q', default=32, type=int, help='Oversampling rate 32/q') +args = _parser.parse_args() + +Nsec = args.n +fadc = args.f * 1000000 # ADC sample frequency in [Hz] +Tadc = 1000. / args.f # ADC sample period in [ns] +p = 32 +q = args.q # Subband oversampling rate for Ros = p / q, where p = 32 + +Nsub = 512 # Number of subbands +Ncomplex = 2 +Nfft = Nsub * Ncomplex # Subband filterbank FFT size +Nblk = Nfft * q / p # Subband period in [Tadc] +Tsub = Nblk * Tadc # Subband period in [ns] + +# Check that Tsub can be expressed as an integer number of ns +result = 'PASSED' +if int(Tsub) != Tsub: + print '' + result = 'WARNING' + print 'Warning: Tsub = %f ns, choose f such that Tsub is an integer number of ns' % Tsub + +print '' +print ' SSN | first ToD | | nof BSN' +print ' of PPS | BSN in PPS at first | offset | in PPS' +print ' grid | interval * Tsub = BSN | to PPS | interval' +print ' [s] | [ns] [ns] | [ns] [Tadc] | ' +print '--------+-----------------------------------+-----------------+---------' +# BSN = Block Sequence Number of first block in this PPS interval +BSN = 0 +nofBSN_hi = 0 +nofBSN_lo = 0 +prevToffset = 0 +for SSN in range(Nsec): + # SSN = Second Sequence Number of this PPS interval + + # Determine BSN of first block in next PPS interval + nextSSN = SSN + 1 + nextBSN = math.ceil((1.0 * nextSSN * fadc) / Nblk) + + # Determine timing for this PPS interval + # . Time of Day at BSN in [ns] + ToD_ns = BSN * Tsub + + # . Offset of ToD at BSN relative to PPS in [Tadc] + Toffset = BSN * Nblk - SSN * fadc + # Note: ToD_ns - SSN * 1000000000 yields Toffset in [ns], but first + # derive Toffset in [Tadc] units. to avoid the division (which could + # lead to integer truncation but not for f = 160 or f = 200) that is + # used to calculate ToD_ns. + + # . Number of blocks in this PPS interval + nofBSN = nextBSN - BSN + # . Maintain count of number of BSN intervals with 1 extra BSN + if SSN == 0: + nofBSN_H = nofBSN + nofBSN_L = nofBSN + nofHiBSN = 1 + nofLoBSN = 0 + else: + if nofBSN_H == nofBSN: + nofHiBSN += 1 + else: + nofBSN_L = nofBSN # nofBSN_H = nofBSN_L + 1 by design + nofLoBSN += 1 + # Print timing information + if Toffset == 0 and prevToffset != 0: + # insert divider row each time BSN grid coincides with PPS grid again + print ' | | | ' + print '%7d | %10d * %5d = %12d | %6d %8d | %8d' % (SSN, BSN, Tsub, ToD_ns, Toffset*Tadc, Toffset, nofBSN) + + + # Prepare for next PPS interval + BSN = nextBSN + prevToffset = Toffset + +print '' +if nofBSN_H != nofBSN_L: + print 'nofBSN = %d occured %d time' % (nofBSN_H, nofHiBSN) + print 'nofBSN = %d occured %d time' % (nofBSN_L, nofLoBSN) + timeBSN = (nofBSN_H * nofHiBSN + nofBSN_L * nofLoBSN) + timeBSN_ns = timeBSN * Tsub + timeSSN_ns = Nsec * 1000000000 + + print 'time SSN = %d [ns]' % timeSSN_ns + print 'time BSN = %d [ns] = %d * %d + %d * %d = %d [Tsub]' % (timeBSN_ns, nofBSN_H, nofHiBSN, nofBSN_L, nofLoBSN, timeBSN) + if timeBSN_ns != timeSSN_ns: + result = 'WARNING' + print 'Warning: not an integer number of BSN in n PPS intervals, choose n multiple of q' +print '' +print result +print ''