diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd
index 8a855419e5a7d760841b55b188169abf6bbdbb71..c79b23ab4cf4021ac721c5007a7620173c127b20 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd
@@ -53,31 +53,17 @@ package sdp_bdo_pkg is
       (others => (others => '0')),
       (others => (others => '0')), 0, 0, 0 );
 
-  -- Select header destination MAC, IP, UDP field from data path, to support
-  -- BDO multiple destinations register
-  function func_sdp_bdo_cep_hdr_field_sel_dest(sl : std_logic) return std_logic_vector;
-
   -- Determine actual nof_destinations and actual nof_blocks_per_packet
   function func_sdp_bdo_parse_nof_destinations(nof_destinations : natural) return natural;
   function func_sdp_bdo_nof_blocks_per_packet_look_up_table return t_natural_arr;
 
   -- Determine nof_beamlets_per_block per destination
-  function func_sdp_nof_beamlets_per_block_look_up_table return t_natural_arr;
-  function func_sdp_nof_beamlets_per_block_look_up_matrix return t_natural_matrix;
+  function func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table return t_natural_arr;
+  function func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table return t_natural_arr;
+  function func_sdp_sdo_beamlet_index_per_destination_look_up_matrix return t_natural_matrix;
 end package sdp_bdo_pkg;
 
 package body sdp_bdo_pkg is
-  function func_sdp_bdo_cep_hdr_field_sel_dest(sl : std_logic) return std_logic_vector is
-    variable v_sel : std_logic_vector(c_sdp_cep_nof_hdr_fields - 1 downto 0) := c_sdp_cep_hdr_field_sel;
-  begin
-    -- Select header destination MAC, IP, UDP field from data path instead of
-    -- from MM in dp_offload_tx_v3
-    v_sel(38) := sl;  -- eth_dst_mac
-    v_sel(24) := sl;  -- ip_dst_addr
-    v_sel(22) := sl;  -- udp_dst_port
-    return v_sel;
-  end func_sdp_bdo_cep_hdr_field_sel_dest;
-
   function func_sdp_bdo_parse_nof_destinations(nof_destinations : natural) return natural is
   begin
     -- Parse input nof_destinations value
@@ -114,70 +100,112 @@ package body sdp_bdo_pkg is
     return v_arr;
   end func_sdp_bdo_nof_blocks_per_packet_look_up_table;
 
-  function func_sdp_nof_beamlets_per_block_look_up_table return t_natural_arr is
-    variable v_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max);
+  function func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table return t_natural_arr is
+    variable v_first_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max);
   begin
-    -- Determine nof_beamlets_per_block as function of number of destinations D. Use
-    -- look up table to precalculate the values as constants.
+    -- Determine nof_beamlets_per_block for the first 1:DN-1 destinations, as
+    -- function of number of destinations DN. Use look up table to precalculate
+    -- the values as constants.
     -- . In total there are c_sdp_S_sub_bf = 488 dual polarization beamlets to
-    --   distribute over D destinations, so ceil(488 / D) per destination yields:
-    --     D = 1:16 --> 488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31
-    for D in 1 to c_sdp_bdo_nof_destinations_max loop
-      v_arr(D) := ceil_div(c_sdp_S_sub_bf, D);
+    --   distribute over DN destinations, so ceil(488 / DN) yields the number of
+    --   blocks for the first 1:DN-1 destinations:
+    --     DN = 1:16 --> v_first_arr = 488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31
+    for DN in 1 to c_sdp_bdo_nof_destinations_max loop
+      v_first_arr(DN) := ceil_div(c_sdp_S_sub_bf, DN);
     end loop;
-    return v_arr;
-  end func_sdp_nof_beamlets_per_block_look_up_table;
+    return v_first_arr;
+  end func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table;
+
+  function func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table return t_natural_arr is
+    variable v_first_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) :=
+                             func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table;
+    variable v_last_arr  : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max);
+  begin
+    -- Determine nof_beamlets_per_block for the last destination with index DN,
+    -- as function of number of destinations DN. Use look up table to
+    -- precalculate the values as constants.
+    -- . In total there are c_sdp_S_sub_bf = 488 dual polarization beamlets to
+    --   distribute over DN destinations, so 488 - (DN-1) * ceil(488 / DN)
+    --   beamlets remain for the last destination:
+    --     DN = 1:16 --> v_first_arr = 488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31
+    --     DN = 1:16 --> v_last_arr  = 488, 244, 162, 122, 96, 78, 68, 61, 48, 47, 38, 37, 32, 33, 26, 23
+    --
+    -- Remark:
+    -- . The v_last_arr may be < v_first_arr - 1, so the last destination may
+    --   contain much less beamlets than the others. In combination with
+    --   dp_packet_unmerge it is not feasible to distribute the beamlets evenly
+    --   over all destinations, using v_hi beamlets for some first destinations
+    --   and v_lo = v_hi - 1 for the remaining destinations. This is because
+    --   dp_packet_unmerge can only unmerge the same packet length for N - 1
+    --   blocks and then unmerge the remaining data in the last block until the
+    --   eop.
+    --
+    for DN in 1 to c_sdp_bdo_nof_destinations_max loop
+      v_last_arr(DN) := c_sdp_S_sub_bf - (DN - 1) * v_first_arr(DN);
+    end loop;
+    return v_last_arr;
+  end func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table;
 
-  function func_sdp_nof_beamlets_per_block_look_up_matrix return t_natural_matrix is
-    constant c_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) :=
-                       func_sdp_nof_beamlets_per_block_look_up_table;
-    variable v_mat : t_natural_matrix(1 to c_sdp_bdo_nof_destinations_max,
-                                      1 to c_sdp_bdo_nof_destinations_max);
-    variable v_hi  : natural;
-    variable v_lo  : natural;
+  function func_sdp_sdo_beamlet_index_per_destination_look_up_matrix return t_natural_matrix is
+    constant c_len_arr   : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) :=
+                             func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table;
+    variable v_index_mat : t_natural_matrix(1 to c_sdp_bdo_nof_destinations_max,
+                                            0 to c_sdp_bdo_nof_destinations_max - 1);
+    variable v_beamlet_index : natural;
+    variable v_step          : natural;
   begin
-    -- Determine nof_beamlets_per_block as function of number of destinations DN and
-    -- destination index DI. Use look up table to precalculate the values as constants.
+    -- Determine beamlet index of first beamlet in packet per destination with
+    -- index DN, as function of number of destinations DN. Use look up table to
+    -- precalculate the values as constants.
+    -- . Beamlet index for first destination starts at 0
+    -- . Beamlet index for the other destinations increments with number of
+    --   beamlets per previous destination given by c_len_arr.
     --
-    -- * vertical : nof_destinations DN
-    -- * horizontal : destination index DI
+    -- * rows: nof_destinations DN
+    -- * columns: destination index DI
     --
-    -- DI:   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16
+    -- DI:   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15
     -- DN:
-    --  1  488,   0,   .................................................................0
-    --  2  244, 244,   0                                                                .
-    --  3  163, 163, 162,   0                                                           .
-    --  4  122, 122, 122, 122,   0                                                      .
-    --  5   98,  98,  98,  97,  97,   0                                                 .
-    --  6   82,  82,  81,  81,  81,  81,   0                                            .
-    --  7   70,  70,  70,  70,  70,  69,  69,   0                                       .
-    --  8   61,  61,  61,  61,  61,  61,  61,  61,   0                                  .
-    --  9   55,  55,  57,  57,  57,  57,  57,  57,  57,   0                             .
-    -- 10   49,  49,  49,  49,  49,  49,  49,  49,  48,  48,   0                        .
-    -- 11   45,  45,  45,  45,  44,  44,  44,  44,  44,  44,  44,   0                   .
-    -- 12   41,  41,  41,  41,  41,  41,  41,  41,  40,  40,  40,  40,   0              .
-    -- 13   38,  38,  38,  38,  38,  38,  38,  37,  37,  37,  37,  37,  37,   0         .
-    -- 14   35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  35,  34,  34,   0    .
-    -- 15   33,  33,  33,  33,  33,  33,  33,  33,  32,  32,  32,  32,  32,  32,  32,   0
-    -- 16   31,  31,  31,  31,  31,  31,  31,  31,  30,  30,  30,  30,  30,  30,  30,  30
+    --  1    0,   0.....................................................................0
+    --  2    0, 244,   0                                                                .
+    --  3    0, 163, 326,   0                                                           .
+    --  4    0, 122, 244, 366,   0                                                      .
+    --  5    0,  98, 196, 294, 392,   0                                                 .
+    --  6    0,  82, 164, 246, 328, 410,   0                                            .
+    --  7    0,  70, 140, 210, 280, 350, 420,   0                                       .
+    --  8    0,  61, 122, 183, 244, 305, 366, 427,   0                                  .
+    --  9    0,  55, 110, 165, 220, 275, 330, 385, 440,   0                             .
+    -- 10    0,  49,  98, 147, 196, 245, 294, 343, 392, 441,   0                        .
+    -- 11    0,  45,  90, 135, 180, 225, 270, 315, 360, 405, 450,   0                   .
+    -- 12    0,  41,  82, 123, 164, 205, 246, 287, 328, 369, 410, 451,   0              .
+    -- 13    0,  38,  76, 114, 152, 190, 228, 266, 304, 342, 380, 418, 456,   0         .
+    -- 14    0,  35,  70, 105, 140, 175, 210, 245, 280, 315, 350, 385, 420, 455,   0    .
+    -- 15    0,  33,  66,  99, 132, 165, 198, 231, 264, 297, 330, 363, 396, 429, 462,   0
+    -- 16    0,  31,  62,  93, 124, 155, 186, 217, 248, 279, 310, 341, 372, 403, 434, 465
+    --
+    -- Equivalent Python code to produce matrix:
+    --
+    --   c_len_arr = [488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31]
+    --   for DN in range(16):
+    --       lineStr = '%2d ' % (DN + 1)
+    --       v_beamlet_index = 0
+    --       v_step = c_len_arr[DN]
+    --       for DI in range(16):
+    --           if v_beamlet_index < 488:
+    --               lineStr += '%4d,' % v_beamlet_index
+    --           v_beamlet_index += v_step
+    --       print(lineStr)
+    --
     for DN in 1 to c_sdp_bdo_nof_destinations_max loop
-      v_hi := c_arr(DN);
-      v_lo := v_hi - 1;
-      for DI in 1 to c_sdp_bdo_nof_destinations_max loop
-        -- Default initialize to zero for unused elements
-        v_mat(DN, DI) := 0;
-        -- Determine number of destinations in DN with v_hi value and with
-        -- v_lo value, to distribute in total c_sdp_S_sub_bf beamlets to DN
-        -- destinations.
-        if DI * v_hi + (DN - DI) * v_lo <= c_sdp_S_sub_bf then
-          -- Use v_hi for first destinations DI
-          v_mat(DN, DI) := v_hi;
-        else
-          -- Use v_lo for remaining destinations, if there are any remaining
-          v_mat(DN, DI) := v_lo;
+      v_beamlet_index := 0;
+      v_step := c_len_arr(DN);
+      for DI in 0 to c_sdp_bdo_nof_destinations_max - 1 loop
+        if v_beamlet_index < c_sdp_S_sub_bf then
+          v_index_mat(DN, DI) := v_beamlet_index;
         end if;
+        v_beamlet_index := v_beamlet_index + v_step;
       end loop;
     end loop;
-    return v_mat;
-  end func_sdp_nof_beamlets_per_block_look_up_matrix;
+    return v_index_mat;
+  end func_sdp_sdo_beamlet_index_per_destination_look_up_matrix;
 end sdp_bdo_pkg;
diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd
index 101842bae736d26bef4f1eac777280004e182a07..78cb5f8062d474f82d96b6f2b64dcf9407f3be91 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd
@@ -685,6 +685,9 @@ package sdp_pkg is
   function func_sdp_map_stat_header(hdr_fields_raw : std_logic_vector) return t_sdp_stat_header;
   function func_sdp_map_cep_header(hdr_fields_raw : std_logic_vector) return t_sdp_cep_header;
 
+  -- Select header destination MAC, IP, UDP fields from DP (sl = 0) or from MM (sl = '1') in dp_offload_tx_v3
+  function func_sdp_cep_hdr_field_sel_dst(sl : std_logic) return std_logic_vector;
+
   function func_sdp_map_stat_data_id(g_statistics_type : string; data_id_slv : std_logic_vector) return t_sdp_stat_data_id;
   function func_sdp_map_stat_data_id(g_statistics_type : string; data_id_rec : t_sdp_stat_data_id) return std_logic_vector;
 
@@ -948,6 +951,16 @@ package body sdp_pkg is
     return v;
   end func_sdp_map_cep_header;
 
+  function func_sdp_cep_hdr_field_sel_dst(sl : std_logic) return std_logic_vector is
+    variable v_sel : std_logic_vector(c_sdp_cep_nof_hdr_fields - 1 downto 0) := c_sdp_cep_hdr_field_sel;
+  begin
+    -- Select header destination MAC, IP, UDP field from DP or from MM in dp_offload_tx_v3
+    v_sel(38) := sl;  -- eth_dst_mac
+    v_sel(24) := sl;  -- ip_dst_addr
+    v_sel(22) := sl;  -- udp_dst_port
+    return v_sel;
+  end func_sdp_cep_hdr_field_sel_dst;
+
   function func_sdp_map_stat_data_id(g_statistics_type : string; data_id_slv : std_logic_vector) return t_sdp_stat_data_id is
     variable v_rec : t_sdp_stat_data_id;
   begin