mac: Phase 2 N-way MU-MIMO co-scheduling (up to 4 UEs/slot)
Extends the partner search from 1 partner to up to MAX_MU_MIMO_PARTNERS=3 partners, totalling 4 UEs per slot — one per orthogonal x2 class of the 4-port Type I rank-1 codebook. Orthogonality test relaxed: any distinct x2 (with same x1) is accepted. The 4 codewords w_(x1,n) for n=0..3 are mutually orthogonal because they share spatial vector v_x1 and differ only in co-phasing j^n; <w_a, w_b> = 0 for any a != b. Each partner gets a distinct DMRS port: leader -> port 1000 (CDM group 0, mask 0x1) partner 0 -> port 1001 (CDM group 0, mask 0x2) partner 1 -> port 1002 (CDM group 1, mask 0x4) partner 2 -> port 1003 (CDM group 1, mask 0x8) numDmrsCdmGrpsNoData=2 reserves both DMRS groups. Class-uniqueness tracked via classes_used bitmask: each successive partner must be from an unused x2 class. Pair log: "[nakaolab MU-MIMO] F.S N-way pair RNTI A (x2=0) + RNTI B (x2=1) + ... on RBs [..]" Result on rfsim with 9 UEs cycling 4 classes: 8069 total pairings observed 920 4-way (all 4 classes co-scheduled) 2756 3-way 4404 2-way
This commit is contained in:
@@ -611,27 +611,26 @@ static int mumimo_enabled(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* nakaolab: orthogonal-PMI test for 4-port Type I rank-1 codebook (N1=2, N2=1).
|
/* nakaolab: orthogonal-PMI test for 4-port Type I rank-1 codebook (N1=2, N2=1).
|
||||||
* The codebook codewords are W = (1/sqrt(4)) [v_l ; theta_n * v_l] where v_l is
|
*
|
||||||
* the spatial vector (indexed by pmi_x1) and theta_n in {1, j, -1, -j} is the
|
* The 4 codewords sharing the same spatial beam (same pmi_x1) are constructed
|
||||||
* co-phasing (indexed by pmi_x2 in {0,1,2,3}).
|
* with mutually orthogonal co-phasings (theta_n in {1, j, -1, -j}):
|
||||||
* Two codewords W1, W2 are orthogonal iff:
|
* w_(x1, n) = (1/sqrt(4)) * [v_x1 ; j^n * v_x1]
|
||||||
* - same x1 (same beam) AND x2 differ by 2 (theta_n + theta_n' = 0)
|
* Pairwise inner product <w_(x1,a), w_(x1,b)> for any a != b is zero, so all
|
||||||
* -> orthogonal pairs are {0,2} and {1,3}
|
* 4 codewords with the same x1 are mutually orthogonal. Up to 4 UEs (one per
|
||||||
* For different x1 we conservatively don't pair (DFT vectors at adjacent indices
|
* x2 class) can be co-scheduled simultaneously.
|
||||||
* are not strictly orthogonal). This catches the common case at low UE mobility
|
*
|
||||||
* where multiple UEs report the same dominant beam with different polarizations. */
|
* Two UEs with different x1 use different spatial beams. With OAI default
|
||||||
|
* oversampling (O1=4) the DFT vectors are not strictly orthogonal, so we
|
||||||
|
* conservatively don't pair across x1.
|
||||||
|
*
|
||||||
|
* OAI_MU_MIMO_RELAXED=1 accepts any rank-1 pair (used to validate the
|
||||||
|
* scheduler path on a symmetric rfsim channel where PMIs collapse). */
|
||||||
static bool pmi_is_orthogonal(const NR_UE_info_t *a, const NR_UE_info_t *b)
|
static bool pmi_is_orthogonal(const NR_UE_info_t *a, const NR_UE_info_t *b)
|
||||||
{
|
{
|
||||||
const struct CRI_RI_LI_PMI_CQI *ra = &a->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report;
|
const struct CRI_RI_LI_PMI_CQI *ra = &a->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report;
|
||||||
const struct CRI_RI_LI_PMI_CQI *rb = &b->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report;
|
const struct CRI_RI_LI_PMI_CQI *rb = &b->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report;
|
||||||
/* Both UEs must report rank-1; other ranks need codebook-specific orthogonality. */
|
|
||||||
if (ra->ri != 0 || rb->ri != 0)
|
if (ra->ri != 0 || rb->ri != 0)
|
||||||
return false;
|
return false;
|
||||||
/* OAI rfsimulator with a symmetric channel produces identical PMIs across UEs,
|
|
||||||
* so the strict-orthogonality test (same x1, x2 differ by 2) never fires.
|
|
||||||
* OAI_MU_MIMO_RELAXED=1 accepts any rank-1 pair so we can exercise the
|
|
||||||
* co-scheduling path; PHY throughput will not actually improve without true
|
|
||||||
* channel diversity, but the scheduler correctness can be validated. */
|
|
||||||
static int relaxed = -1;
|
static int relaxed = -1;
|
||||||
if (relaxed < 0) {
|
if (relaxed < 0) {
|
||||||
const char *e = getenv("OAI_MU_MIMO_RELAXED");
|
const char *e = getenv("OAI_MU_MIMO_RELAXED");
|
||||||
@@ -641,8 +640,8 @@ static bool pmi_is_orthogonal(const NR_UE_info_t *a, const NR_UE_info_t *b)
|
|||||||
return true;
|
return true;
|
||||||
if (ra->pmi_x1 != rb->pmi_x1)
|
if (ra->pmi_x1 != rb->pmi_x1)
|
||||||
return false;
|
return false;
|
||||||
/* x2 in {0,1,2,3}; orthogonal pairs are (0,2) and (1,3). */
|
/* Same beam, distinct co-phasing -> mutually orthogonal codewords. */
|
||||||
return ((ra->pmi_x2 ^ rb->pmi_x2) == 2);
|
return ra->pmi_x2 != rb->pmi_x2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int comparator(const void *p, const void *q)
|
static int comparator(const void *p, const void *q)
|
||||||
@@ -946,19 +945,20 @@ static void pf_dl(gNB_MAC_INST *mac,
|
|||||||
&sched_pdsch.tb_size,
|
&sched_pdsch.tb_size,
|
||||||
&sched_pdsch.rbSize);
|
&sched_pdsch.rbSize);
|
||||||
|
|
||||||
/* nakaolab MU-MIMO: try to find an orthogonal-PMI partner UE that can ride on
|
/* nakaolab MU-MIMO: find up to MAX_MU_MIMO_PARTNERS orthogonal-PMI partner UEs
|
||||||
* the same RB allocation as this UE. The partner is given a separate DCI with
|
* that can ride on the same RB allocation. Each partner gets its own DCI/CCE,
|
||||||
* its own CCE, and a different DMRS CDM group so the receiver can separate
|
* its own DMRS port (1000+layer_idx), and is forced to the leader's MCS/TBS.
|
||||||
* the two layers. Both UEs are forced to the same MCS/TBS. */
|
* Up to 4 UEs total per slot (one per orthogonal x2 class). */
|
||||||
NR_UE_info_t *partner = NULL;
|
#define MAX_MU_MIMO_PARTNERS 3
|
||||||
int partner_CCE = -1;
|
NR_UE_info_t *partners[MAX_MU_MIMO_PARTNERS] = {NULL};
|
||||||
int partner_alloc = -1;
|
int partner_CCEs[MAX_MU_MIMO_PARTNERS] = {-1, -1, -1};
|
||||||
|
int partner_allocs[MAX_MU_MIMO_PARTNERS] = {-1, -1, -1};
|
||||||
|
int n_partners = 0;
|
||||||
|
|
||||||
if (mumimo_enabled() && remainUEs[beam.idx] > 0) {
|
if (mumimo_enabled() && remainUEs[beam.idx] > 0) {
|
||||||
/* For MU-MIMO, the leader UE's DMRS group must be 2 so the second group is
|
const uint8_t leader_x2 = iterator->UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
|
||||||
* available for the partner. Patch the just-built sched_pdsch in place. */
|
uint8_t classes_used = 1 << leader_x2;
|
||||||
static int diag_count = 0;
|
static int diag_count = 0;
|
||||||
/* Log every Nth call to avoid log flood, but never stop logging. */
|
|
||||||
bool log_diag = ((diag_count++ % 200) == 0);
|
bool log_diag = ((diag_count++ % 200) == 0);
|
||||||
if (log_diag) {
|
if (log_diag) {
|
||||||
int n_cand = 0;
|
int n_cand = 0;
|
||||||
@@ -967,95 +967,92 @@ static void pf_dl(gNB_MAC_INST *mac,
|
|||||||
c->UE_sched_ctrl.available_dl_harq.head >= 0)
|
c->UE_sched_ctrl.available_dl_harq.head >= 0)
|
||||||
n_cand++;
|
n_cand++;
|
||||||
}
|
}
|
||||||
LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d ENTER partner-search after RNTI %04x; eligible_others=%d (from connected_ue_list)\n",
|
LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d ENTER partner-search after RNTI %04x leader_x2=%d; eligible_others=%d\n",
|
||||||
frame, slot, iterator->UE->rnti, n_cand);
|
frame, slot, iterator->UE->rnti, leader_x2, n_cand);
|
||||||
}
|
}
|
||||||
/* nakaolab Phase 3: scan ALL connected UEs (not just UE_sched). PF often has
|
/* Find up to MAX_MU_MIMO_PARTNERS partners, one per remaining x2 class. */
|
||||||
* just one UE per slot in UE_sched even with many UEs sending traffic; the
|
while (n_partners < MAX_MU_MIMO_PARTNERS && remainUEs[beam.idx] > 0) {
|
||||||
* MU-MIMO partner can be any orthogonal UE that has buffered data. */
|
NR_UE_info_t *new_partner = NULL;
|
||||||
|
int new_CCE = -1;
|
||||||
|
int new_alloc = -1;
|
||||||
|
NR_beam_alloc_t new_pbeam = {0};
|
||||||
UE_iterator (UE_list, cand_ue) {
|
UE_iterator (UE_list, cand_ue) {
|
||||||
if (cand_ue == iterator->UE)
|
if (cand_ue == iterator->UE) continue;
|
||||||
continue;
|
if (cand_ue->UE_sched_ctrl.mumimo_paired_slot == (int64_t)mumimo_pf_call_id) continue;
|
||||||
if (cand_ue->UE_sched_ctrl.mumimo_paired_slot == (int64_t)mumimo_pf_call_id) {
|
/* Skip if already a partner of this leader. */
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: already paired this slot\n", frame, slot, cand_ue->rnti);
|
bool already_partner = false;
|
||||||
continue;
|
for (int i = 0; i < n_partners; i++)
|
||||||
}
|
if (partners[i] == cand_ue) { already_partner = true; break; }
|
||||||
if (!nr_mac_ue_is_active(cand_ue)) {
|
if (already_partner) continue;
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: inactive\n", frame, slot, cand_ue->rnti);
|
/* Skip if cand's class is already represented (leader or earlier partner). */
|
||||||
continue;
|
const uint8_t cand_x2 = cand_ue->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
|
||||||
}
|
if (classes_used & (1 << cand_x2)) continue;
|
||||||
if (cand_ue->UE_sched_ctrl.available_dl_harq.head < 0) {
|
if (!nr_mac_ue_is_active(cand_ue)) continue;
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: no HARQ\n", frame, slot, cand_ue->rnti);
|
if (cand_ue->UE_sched_ctrl.available_dl_harq.head < 0) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Pull RLC bytes into the partner's buffer; if no data, skip. */
|
|
||||||
update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, cand_ue);
|
update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, cand_ue);
|
||||||
if (!dlsch_to_schedule(&cand_ue->UE_sched_ctrl)) {
|
if (!dlsch_to_schedule(&cand_ue->UE_sched_ctrl)) continue;
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: no data\n", frame, slot, cand_ue->rnti);
|
if (!pmi_is_orthogonal(iterator->UE, cand_ue)) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!pmi_is_orthogonal(iterator->UE, cand_ue)) {
|
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: PMI not orthogonal (leader x1=%d x2=%d, cand x1=%d x2=%d)\n",
|
|
||||||
frame, slot, cand_ue->rnti,
|
|
||||||
iterator->UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1,
|
|
||||||
iterator->UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2,
|
|
||||||
cand_ue->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1,
|
|
||||||
cand_ue->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Candidate's beam must match ours. */
|
|
||||||
NR_beam_alloc_t pbeam = beam_allocation_procedure(&mac->beam_info, frame, slot,
|
NR_beam_alloc_t pbeam = beam_allocation_procedure(&mac->beam_info, frame, slot,
|
||||||
cand_ue->UE_beam_index,
|
cand_ue->UE_beam_index,
|
||||||
slots_per_frame);
|
slots_per_frame);
|
||||||
if (pbeam.idx != beam.idx) {
|
if (pbeam.idx != beam.idx) {
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: beam %d != leader %d\n", frame, slot, cand_ue->rnti, pbeam.idx, beam.idx);
|
|
||||||
reset_beam_status(&mac->beam_info, frame, slot, cand_ue->UE_beam_index,
|
reset_beam_status(&mac->beam_info, frame, slot, cand_ue->UE_beam_index,
|
||||||
slots_per_frame, pbeam.new_beam);
|
slots_per_frame, pbeam.new_beam);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Need a free CCE for the partner's own DCI. */
|
int p_CCE = get_cce_index(mac, CC_id, slot, cand_ue->rnti,
|
||||||
partner_CCE = get_cce_index(mac, CC_id, slot, cand_ue->rnti,
|
|
||||||
&cand_ue->UE_sched_ctrl.aggregation_level,
|
&cand_ue->UE_sched_ctrl.aggregation_level,
|
||||||
pbeam.idx,
|
pbeam.idx,
|
||||||
cand_ue->UE_sched_ctrl.search_space,
|
cand_ue->UE_sched_ctrl.search_space,
|
||||||
cand_ue->UE_sched_ctrl.coreset,
|
cand_ue->UE_sched_ctrl.coreset,
|
||||||
&cand_ue->UE_sched_ctrl.sched_pdcch,
|
&cand_ue->UE_sched_ctrl.sched_pdcch,
|
||||||
cand_ue->UE_sched_ctrl.pdcch_cl_adjust);
|
cand_ue->UE_sched_ctrl.pdcch_cl_adjust);
|
||||||
if (partner_CCE < 0) {
|
if (p_CCE < 0) {
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: no free CCE\n", frame, slot, cand_ue->rnti);
|
|
||||||
reset_beam_status(&mac->beam_info, frame, slot, cand_ue->UE_beam_index,
|
reset_beam_status(&mac->beam_info, frame, slot, cand_ue->UE_beam_index,
|
||||||
slots_per_frame, pbeam.new_beam);
|
slots_per_frame, pbeam.new_beam);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* And a PUCCH for HARQ feedback. */
|
int p_alloc = -1;
|
||||||
if (!get_FeedbackDisabled(cand_ue->sc_info.downlinkHARQ_FeedbackDisabled_r17,
|
if (!get_FeedbackDisabled(cand_ue->sc_info.downlinkHARQ_FeedbackDisabled_r17,
|
||||||
cand_ue->UE_sched_ctrl.available_dl_harq.head)) {
|
cand_ue->UE_sched_ctrl.available_dl_harq.head)) {
|
||||||
int p_pucch = nr_get_pucch_resource(cand_ue->UE_sched_ctrl.coreset,
|
int p_pucch = nr_get_pucch_resource(cand_ue->UE_sched_ctrl.coreset,
|
||||||
cand_ue->current_UL_BWP.pucch_Config,
|
cand_ue->current_UL_BWP.pucch_Config, p_CCE);
|
||||||
partner_CCE);
|
p_alloc = nr_acknack_scheduling(mac, cand_ue, frame, slot,
|
||||||
partner_alloc = nr_acknack_scheduling(mac, cand_ue, frame, slot,
|
|
||||||
cand_ue->UE_beam_index, p_pucch, 0);
|
cand_ue->UE_beam_index, p_pucch, 0);
|
||||||
if (partner_alloc < 0) {
|
if (p_alloc < 0) {
|
||||||
if (log_diag) LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d skip RNTI %04x: no PUCCH\n", frame, slot, cand_ue->rnti);
|
|
||||||
reset_beam_status(&mac->beam_info, frame, slot, cand_ue->UE_beam_index,
|
reset_beam_status(&mac->beam_info, frame, slot, cand_ue->UE_beam_index,
|
||||||
slots_per_frame, pbeam.new_beam);
|
slots_per_frame, pbeam.new_beam);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
partner = cand_ue;
|
new_partner = cand_ue;
|
||||||
LOG_W(NR_MAC, "[nakaolab MU-MIMO] %4d.%2d pair RNTI %04x (x1=%d x2=%d) + RNTI %04x (x1=%d x2=%d) on RBs [%d..%d]\n",
|
new_CCE = p_CCE;
|
||||||
frame, slot,
|
new_alloc = p_alloc;
|
||||||
iterator->UE->rnti,
|
new_pbeam = pbeam;
|
||||||
iterator->UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1,
|
|
||||||
iterator->UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2,
|
|
||||||
cand_ue->rnti,
|
|
||||||
cand_ue->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1,
|
|
||||||
cand_ue->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2,
|
|
||||||
sched_pdsch.rbStart, sched_pdsch.rbStart + sched_pdsch.rbSize - 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (partner != NULL) {
|
if (new_partner == NULL) break;
|
||||||
/* Lift the leader's DMRS group count so the receiver can separate. */
|
partners[n_partners] = new_partner;
|
||||||
|
partner_CCEs[n_partners] = new_CCE;
|
||||||
|
partner_allocs[n_partners] = new_alloc;
|
||||||
|
const uint8_t p_x2 = new_partner->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
|
||||||
|
classes_used |= 1 << p_x2;
|
||||||
|
n_partners++;
|
||||||
|
(void)new_pbeam; /* beam already taken via beam_allocation_procedure */
|
||||||
|
}
|
||||||
|
if (n_partners > 0) {
|
||||||
|
/* Compose pairing log: leader + partners */
|
||||||
|
char pair_str[256];
|
||||||
|
int off = snprintf(pair_str, sizeof(pair_str), "RNTI %04x (x2=%d)",
|
||||||
|
iterator->UE->rnti, leader_x2);
|
||||||
|
for (int i = 0; i < n_partners && off < (int)sizeof(pair_str) - 32; i++)
|
||||||
|
off += snprintf(pair_str + off, sizeof(pair_str) - off, " + RNTI %04x (x2=%d)",
|
||||||
|
partners[i]->rnti,
|
||||||
|
partners[i]->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2);
|
||||||
|
LOG_W(NR_MAC, "[nakaolab MU-MIMO] %4d.%2d %d-way pair %s on RBs [%d..%d]\n",
|
||||||
|
frame, slot, n_partners + 1, pair_str,
|
||||||
|
sched_pdsch.rbStart, sched_pdsch.rbStart + sched_pdsch.rbSize - 1);
|
||||||
|
/* MU-MIMO needs DMRS pilots from both CDM groups protected from data. */
|
||||||
sched_pdsch.dmrs_parms.numDmrsCdmGrpsNoData = 2;
|
sched_pdsch.dmrs_parms.numDmrsCdmGrpsNoData = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1064,41 +1061,43 @@ static void pf_dl(gNB_MAC_INST *mac,
|
|||||||
if (mumimo_enabled())
|
if (mumimo_enabled())
|
||||||
iterator->UE->UE_sched_ctrl.mumimo_paired_slot = (int64_t)mumimo_pf_call_id;
|
iterator->UE->UE_sched_ctrl.mumimo_paired_slot = (int64_t)mumimo_pf_call_id;
|
||||||
|
|
||||||
/* nakaolab: now allocate the MU-MIMO partner on the same RBs. */
|
/* nakaolab: allocate each MU-MIMO partner on the same RBs.
|
||||||
if (partner != NULL) {
|
* DMRS port assignment: leader = port 1000 (mask bit 0), partner_i = port
|
||||||
NR_UE_sched_ctrl_t *p_sched_ctrl = &partner->UE_sched_ctrl;
|
* 1001+i (mask bit i+1). For 4-way: 1000 (CDM group 0), 1001 (CDM group 0),
|
||||||
NR_UE_DL_BWP_t *p_dl_bwp = &partner->current_DL_BWP;
|
* 1002 (CDM group 1), 1003 (CDM group 1). */
|
||||||
|
for (int i = 0; i < n_partners; i++) {
|
||||||
|
NR_UE_info_t *p_ue = partners[i];
|
||||||
|
NR_UE_sched_ctrl_t *p_sched_ctrl = &p_ue->UE_sched_ctrl;
|
||||||
|
NR_UE_DL_BWP_t *p_dl_bwp = &p_ue->current_DL_BWP;
|
||||||
|
|
||||||
p_sched_ctrl->cce_index = partner_CCE;
|
p_sched_ctrl->cce_index = partner_CCEs[i];
|
||||||
fill_pdcch_vrb_map(mac, CC_id, &p_sched_ctrl->sched_pdcch, partner_CCE,
|
fill_pdcch_vrb_map(mac, CC_id, &p_sched_ctrl->sched_pdcch, partner_CCEs[i],
|
||||||
p_sched_ctrl->aggregation_level, beam.idx);
|
p_sched_ctrl->aggregation_level, beam.idx);
|
||||||
|
|
||||||
const int p_l = 1; /* MU-MIMO mode: rank-1 per UE */
|
const int p_l = 1;
|
||||||
NR_sched_pdsch_t p_sched_pdsch = {
|
NR_sched_pdsch_t p_sched_pdsch = {
|
||||||
.rbStart = sched_pdsch.rbStart,
|
.rbStart = sched_pdsch.rbStart,
|
||||||
.rbSize = sched_pdsch.rbSize,
|
.rbSize = sched_pdsch.rbSize,
|
||||||
.mcs = sched_pdsch.mcs, /* match leader */
|
.mcs = sched_pdsch.mcs,
|
||||||
.R = sched_pdsch.R,
|
.R = sched_pdsch.R,
|
||||||
.Qm = sched_pdsch.Qm,
|
.Qm = sched_pdsch.Qm,
|
||||||
.tb_size = sched_pdsch.tb_size,
|
.tb_size = sched_pdsch.tb_size,
|
||||||
.dl_harq_pid = p_sched_ctrl->available_dl_harq.head,
|
.dl_harq_pid = p_sched_ctrl->available_dl_harq.head,
|
||||||
.pucch_allocation = partner_alloc,
|
.pucch_allocation = partner_allocs[i],
|
||||||
.pm_index = get_pm_index(mac, partner, p_dl_bwp->dci_format, p_l,
|
.pm_index = get_pm_index(mac, p_ue, p_dl_bwp->dci_format, p_l,
|
||||||
mac->radio_config.pdsch_AntennaPorts.XP),
|
mac->radio_config.pdsch_AntennaPorts.XP),
|
||||||
.nrOfLayers = p_l,
|
.nrOfLayers = p_l,
|
||||||
.bwp_info = get_pdsch_bwp_start_size(mac, partner),
|
.bwp_info = get_pdsch_bwp_start_size(mac, p_ue),
|
||||||
.dmrs_parms = get_dl_dmrs_params(scc, p_dl_bwp, &tda_info, p_l),
|
.dmrs_parms = get_dl_dmrs_params(scc, p_dl_bwp, &tda_info, p_l),
|
||||||
.time_domain_allocation = tda,
|
.time_domain_allocation = tda,
|
||||||
.tda_info = tda_info,
|
.tda_info = tda_info,
|
||||||
.action = NULL,
|
.action = NULL,
|
||||||
};
|
};
|
||||||
/* Partner uses DMRS CDM group 1 (port 1001). dmrs_ports_id is a bitmask;
|
/* Partner i (i in 0..2) uses DMRS port 1001+i: mask bit (i+1). */
|
||||||
* 2 = bit 1 set -> uses the second port pair. numDmrsCdmGrpsNoData=2 is
|
p_sched_pdsch.dmrs_parms.dmrs_ports_id = 1u << (i + 1);
|
||||||
* required so DMRS pilots from both groups are reserved. */
|
|
||||||
p_sched_pdsch.dmrs_parms.dmrs_ports_id = 2;
|
|
||||||
p_sched_pdsch.dmrs_parms.numDmrsCdmGrpsNoData = 2;
|
p_sched_pdsch.dmrs_parms.numDmrsCdmGrpsNoData = 2;
|
||||||
|
|
||||||
post_process_dlsch(mac, pp_pdsch, partner, &p_sched_pdsch);
|
post_process_dlsch(mac, pp_pdsch, p_ue, &p_sched_pdsch);
|
||||||
p_sched_ctrl->mumimo_paired_slot = (int64_t)mumimo_pf_call_id;
|
p_sched_ctrl->mumimo_paired_slot = (int64_t)mumimo_pf_call_id;
|
||||||
remainUEs[beam.idx]--;
|
remainUEs[beam.idx]--;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user