From d9eec25e7b2ade839a3120a070c01cc12148affd Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Fri, 14 Aug 2020 16:58:34 +0200
Subject: [PATCH] Update beamlet header format.

---
 .../lofar2/doc/prestudy/station2_sdp_icd.txt  | 113 +++++++++++-------
 1 file changed, 72 insertions(+), 41 deletions(-)

diff --git a/applications/lofar2/doc/prestudy/station2_sdp_icd.txt b/applications/lofar2/doc/prestudy/station2_sdp_icd.txt
index d970017427..96c60c81f1 100755
--- a/applications/lofar2/doc/prestudy/station2_sdp_icd.txt
+++ b/applications/lofar2/doc/prestudy/station2_sdp_icd.txt
@@ -127,7 +127,18 @@ UDP link control
   24 Byte, Flags (0-23, 1 bit per pol/dish)
   
   --> Total 40 Bytes
+  
+# Arts SC1
+  1 Byte, Marker byte
+  1 Byte, Format version
+  2 Byte, Source id
+  2 Byte, Number of channels per block (N channel )
+  2 Byte, Number of blocks per packet (N block )
+  8 Byte, Timestamp
+ 24 Byte, Flags
 
+  --> Total 40 Bytes
+  
 # Arts SC2
 
   1 Byte, Marker (= 120)
@@ -268,7 +279,6 @@ The FPGA has 2713 M20k, so this is 128/2713 ~= 5% of the internal BRAM resources
 The total number of streams to CEP then becomes NOF_BEAMSETS * NOF_LANES.
 
 
-
 - 1 Byte, MARKER
   . Like in APERTIF and ARTS, may be useful to quickly recognize the data packet.
   . Beamlets: 98 = 0x62 = 'b'
@@ -290,57 +300,78 @@ The total number of streams to CEP then becomes NOF_BEAMSETS * NOF_LANES.
 
 - 2 Byte, STATION_ID (idem as LOFAR1)
   ==> or 8b because there are only ~50 stations
-  ==> use 16b to fit number from station name (e.g. CS001, LV614, see list of stations at
-      https://proxy.lofar.eu/array_status/STATIONS/HTML/cs011/index.html)
-
-- 4 Byte, SOURCE_INFO
-    Only include info that can be inserted by SDP, without explicit write by SC. Therefore e.g. RCU mode,
-    Nyquist zone, nof antenna in array are not included.
-    The packet header does not contain all info to derive the RF frequency, because it does not contain the
-    subband-beamlet mapping R_bsub. Therefore it is not necessary to include the Nyquist zone information in 
-    the header. However, just for information the Nyquist zone is useful to have in the header. 
-  . 1b f_adc, sample clock frequency of the ADC, 0 = 160 MHz, 1 = 200 MHz
-  . 2b nyuist_zone
-  . 1b pfb_type, 0 = critically PFB, 1 = oversampled PFB (rather than p, q for R_os = p/q)
-       - The f_adc and t_pfb are in the header, because this information is sufficent to know the subband
-         frequency grid (f_sub = f_adc / N_fft = 195312.5 or 156250 Hz) and the subband sample rate
-         (R_os * f_sub). 
-  . 1b payload_error, 0 payload ok, 1 one or more blocks in payload have data errors
+  ==> Use 16b to fit number from station name (e.g. 1 = CS001, 614 = LV614). The STATION_ID also indirectly reveals whether it is a core, remote or international station.
+      see list of stations at https://proxy.lofar.eu/array_status/STATIONS/HTML/cs011/index.html)
+
+- 2 Byte, SOURCE_INFO
+    Only include info that can be inserted by SDP, without explicit write by SC. The packet header does
+    not contain all info to derive the RF frequency, because it does not contain:
+    . the subband-beamlet mapping R_bsub, because that requires many bytes
+    . the frequency_band: 0 = 10-90, 1 = 30-90, 2 = 110-190, 3 = 170-230, 4 = 210-240, 5 = 210-250 MHz,
+      because these may differ per RCU2 (= RCU modes)
+    . the Nyquist zone information, because that is an implementation detail that is redundant with the
+      frequency_band information
+    . the number nof antenna in array, because that that depends on the beam control which may differ per
+      beamlet.
+    Try use same fields as for statistics
+      
+  . 1b antenna_band: 0 = LBAS, 1 = HBAS [LOFAR2-3098, 6996]
+  . 1b f_adc, sample clock frequency of the ADC, 0 = 160 MHz, 1 = 200 MHz [LOFAR2-3578]
+  . 1b fsub_type: 0 = critically sampled PFB , 1 = oversampled PFB [LOFAR2-2278]
+       - rather than transporting p, q for R_os = p/q
+       - the f_adc and fsub_type are in the header, because this information is sufficent to know the subband
+         frequency grid (f_sub = f_adc / N_fft = 195312.5 or 156250 Hz) and the subband sample rate (R_os * f_sub).
+  . 1b data_flag: 0 = data ok, 1 = data disturbed, due to repositioning of beam [LOFAR2-3123]
+    1b payload_error, 0 = payload data is ok, 1 one or more blocks in payload have data errors, indicating
+       some problem at Station (purpose: fault analysis)
        - a single payload error bit means that all blocks in the payload get discarded if only only block
          has an error.
        - no need for indicator bit per block, assuming errors are rare and will result in loss of
          multiple blocks anyway
-  . 5b beamlet_width in number of bits
-       - Instead of BM = beamlet mode
-       - Default 8 for W_beamlet = 8 bit
-       - Use 5 bit to even fit 16b mode like in LOFAR1)
-  . 6b pn_id = UniBoard2 FPGA ID
+  . 6b reserved (= 0)
+  . 5b pn_id, index of the PN FPGA on UniBoard2 in Station SDP that offloaded the data (purpose: fault analysis)
        - Instead of RSP_ID in LOFAR1
-       - 16 FPGAs for LBA, 16 for HBA in International Station, so maximum 32, but use one bit extra
+       - 16 FPGAs for LBA, 16 for HBA in International Station, so maximum index 31 fits in 5 bits
        - The PN ID is useful for fault diagnoses, to know the PN in SDP from which the data originated.
-       - The pn_id implicitly also reveals the antenna array ID (core station 1 LBA, 2 HBAS, 3 HBA0, 4 HBA1, ...)
-         Therefore it is not necessary to define an explicit antenna ARRAY_ID field that would need to be
-         filled in by SC.
+
+- 2 Byte, BEAMLET_INFO
+  . 4b beamlet_width in number of bits
+       - Instead of BM = beamlet mode
+       - Default 8 for W_beamlet = 8 bit
+       - Use 0 bit to represent 16b mode like in LOFAR1, if necessary
   . 12b beamlet_scale
-    - 18b --> 8b, beamlet_scale = 1 yields lowest bits, beamlet_scale = 1024 (= 11b) yields highest bits
-    - 18b --> 4b, beamlet_scale = 1 yields lowest bits, beamlet_scale = 4096 (= 13b) yields highest bits
-    - beamlet_scale = 1 --> suitable if only one antenna input was used for the beamlet
-    - beamlet_scale = 12, 24, 48, 96 --> to account for number of antennas in beam 
-    - beamlet_scale > 96 --> to have more dynamic range, but less sensitivity. More dynamic range only makes
-                     sense in 8b mode (or 16b mode, but not in 4b or 2b mode), therefore given the
-                     18b beamlet sum the maximum beamlet_scale = 1024.
+    - try to fit beamlet_width and beamlet_scale in 2 Bytes
     - In SDP the beamlet beamlet_scale function extracts the lowest 8b from the 18b beamlet sum, after having
-      multiplied the beamlet sum by 1/beamlet_scale. Internally the beamlet beamlet_scale function uses an 18b 
-      unsigned representation of the 1/beamlet_scale fraction, so 2**18 / beamlet_scale. This yields:
-      beamlet_scale = 1    --> 262144
-      beamlet_scale = 96   -->   2731
-      beamlet_scale = 1024 -->    256
+      multiplied the beamlet sum by 1/beamlet_scale. Same value for all beamlets.
+    - norm = 2**12 / 1024 = 4 to support beamlet_scale values with a resolution of 1/norm = 0.25
+    - 18b --> 8b, beamlet_scale = 1 * norm yields lowest bits, beamlet_scale = 1024 (-1 = 10b) yields highest bits
+    - 18b --> 4b, beamlet_scale = 1 * norm yields lowest bits, beamlet_scale = 4096 (-1 = 12b) yields highest bits
+    - beamlet_scale is typically proportional to sqrt(nof antenna in beam) to maintain sensistivity
+    - larger beamlet_scale values provide more dynamic range, but less sensitivity. More dynamic range only makes
+          sense in 8b mode (or 16b mode, but not in 4b or 2b mode), therefore given the 18b beamlet sum the maximum
+          beamlet_scale = 1024 * norm = 2**10 * 2**2 = 2**12. In practise the dynamic range of beamlet_scale can
+          be less to have more resolution for the norm. The beamlet_scale needs at to be at least sqrt(192) = 13.4
+          to support scaling beamlets for a beam with all antenna inputs. For RFI the beam add coherently, so then
+          beamlet_scale needs to be at least 192. Therefore use 8b.4b for beamlet scale, so norm = 16
+    - beamlet_scale = sqrt  12 * norm = 1    * norm =  16 --> suitable if only one antenna input was used for the beamlet
+                      sqrt  12 * norm = 3.46 * norm =  55
+                      sqrt  24 * norm = 4.9  * norm =  78
+                      sqrt  48 * norm = 6.93 * norm = 111
+                      sqrt  96 * norm = 9.8  * norm = 157
+                      sqrt 192 * norm = 13.4 * norm = 222 --> to account for number of antennas in beam
+    - Internally the beamlet beamlet_scale function uses an 18b unsigned representation of the 1/beamlet_scale fraction,
+      so 2**18 / beamlet_scale. This yields:
+        beamlet_scale = 1       * norm --> 16384
+        beamlet_scale = sqrt 96 * norm -->  1670
+        beamlet_scale = 256     * norm -->    64
+      After mutliplying the 18b.0b beamlet_sum by 1b.12b 1/beamlet_scale the result is a 24b.12b value that is rounded and 
+      clipped to output the 8b beamlets.
+        
 
 - 1 Byte, reserved (= 0)
 
-- 2 Byte, BEAMLET_INDEX = beamset_index * nof_beamlets_per_set
-  . nof_beamlets_per_set = S_sub_bf = 488
-  . nof_beamsets = 1, fixed for LOFAR2.0 stage 1 one beamset per antenna array
+- 2 Byte, BEAMLET_INDEX of first beamlet in the payload
+  . sdp_beamset_index * nof_beamlets_per_set
   . beamset_index = 0 in range(nof_beamsets).
   . global beamlet index of first beamlet in block
     -   0: 487 for beamset 0
-- 
GitLab