From f20b75a05f9c0f88315e90193baef504b6b61d60 Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 11 Dec 2020 15:51:46 +0100 Subject: [PATCH] Re-structure enb metrics a bit. Create a generic mac metric struct and per ue mac metrics struct. --- .../srslte/interfaces/enb_metrics_interface.h | 7 +- srsenb/hdr/stack/mac/mac.h | 2 +- srsenb/hdr/stack/mac/mac_metrics.h | 16 +++- srsenb/hdr/stack/mac/ue.h | 12 +-- srsenb/src/metrics_csv.cc | 4 +- srsenb/src/metrics_stdout.cc | 45 +++++----- srsenb/src/stack/enb_stack_lte.cc | 2 +- srsenb/src/stack/mac/mac.cc | 8 +- srsenb/src/stack/mac/ue.cc | 42 +++++----- srsenb/test/enb_metrics_test.cc | 84 +++++++++---------- 10 files changed, 115 insertions(+), 107 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_metrics_interface.h b/lib/include/srslte/interfaces/enb_metrics_interface.h index c5247b218..ca3c25c0f 100644 --- a/lib/include/srslte/interfaces/enb_metrics_interface.h +++ b/lib/include/srslte/interfaces/enb_metrics_interface.h @@ -28,10 +28,9 @@ namespace srsenb { struct stack_metrics_t { - std::vector mac; - std::vector cc_rach_counter; - rrc_metrics_t rrc; - s1ap_metrics_t s1ap; + mac_metrics_t mac; + rrc_metrics_t rrc; + s1ap_metrics_t s1ap; }; struct enb_metrics_t { diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 0d1a3d711..e3e4beaf1 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -89,7 +89,7 @@ public: bool process_pdus(); - void get_metrics(std::vector& metrics, std::vector &detected_rachs); + void get_metrics(mac_metrics_t& metrics); void write_mcch(const srslte::sib2_mbms_t* sib2_, const srslte::sib13_t* sib13_, const srslte::mcch_msg_t* mcch_, diff --git a/srsenb/hdr/stack/mac/mac_metrics.h b/srsenb/hdr/stack/mac/mac_metrics.h index 7ec7df665..b055acd1b 100644 --- a/srsenb/hdr/stack/mac/mac_metrics.h +++ b/srsenb/hdr/stack/mac/mac_metrics.h @@ -13,11 +13,13 @@ #ifndef SRSENB_MAC_METRICS_H #define SRSENB_MAC_METRICS_H +#include +#include + namespace srsenb { -// MAC metrics per user - -struct mac_metrics_t { +/// MAC metrics per user +struct mac_ue_metrics_t { uint16_t rnti; uint32_t nof_tti; uint32_t cc_idx; @@ -35,6 +37,14 @@ struct mac_metrics_t { float phr; }; +/// Main MAC metrics. +struct mac_metrics_t { + /// RACH preamble counter per cc. + std::vector cc_rach_counter; + /// Per UE MAC metrics. + std::vector ues; +}; + } // namespace srsenb #endif // SRSENB_MAC_METRICS_H diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 4aee18bc8..7127c088b 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -76,7 +76,7 @@ public: void push_pdu(const uint32_t ue_cc_idx, const uint32_t tti, uint32_t len); void deallocate_pdu(const uint32_t ue_cc_idx, const uint32_t tti); - void metrics_read(srsenb::mac_metrics_t* metrics); + void metrics_read(mac_ue_metrics_t* metrics_); void metrics_rx(bool crc, uint32_t tbs); void metrics_tx(bool crc, uint32_t tbs); void metrics_phr(float phr); @@ -95,11 +95,11 @@ private: bool process_ce(srslte::sch_subh* subh); void allocate_ce(srslte::sch_pdu* pdu, uint32_t lcid); - uint32_t phr_counter = 0; - uint32_t dl_cqi_counter = 0; - uint32_t dl_ri_counter = 0; - uint32_t dl_pmi_counter = 0; - mac_metrics_t metrics = {}; + uint32_t phr_counter = 0; + uint32_t dl_cqi_counter = 0; + uint32_t dl_ri_counter = 0; + uint32_t dl_pmi_counter = 0; + mac_ue_metrics_t ue_metrics = {}; srslte::mac_pcap* pcap = nullptr; uint64_t conres_id = 0; diff --git a/srsenb/src/metrics_csv.cc b/srsenb/src/metrics_csv.cc index 447764934..9507dffd8 100644 --- a/srsenb/src/metrics_csv.cc +++ b/srsenb/src/metrics_csv.cc @@ -66,8 +66,8 @@ void metrics_csv::set_metrics(const enb_metrics_t& metrics, const uint32_t perio // Sum up rates for all UEs float dl_rate_sum = 0.0, ul_rate_sum = 0.0; for (size_t i = 0; i < metrics.stack.rrc.ues.size(); i++) { - dl_rate_sum += metrics.stack.mac[i].tx_brate / (metrics.stack.mac[i].nof_tti * 1e-3); - ul_rate_sum += metrics.stack.mac[i].rx_brate / (metrics.stack.mac[i].nof_tti * 1e-3); + dl_rate_sum += metrics.stack.mac.ues[i].tx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3); + ul_rate_sum += metrics.stack.mac.ues[i].rx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3); } // DL rate diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index 554a6d943..db05d0bf7 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -89,37 +89,36 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe for (size_t i = 0; i < metrics.stack.rrc.ues.size(); i++) { // make sure we have stats for MAC and PHY layer too - if (metrics.stack.mac.size() == 0 || metrics.phy.size() == 0 || i > metrics.stack.mac.size() || + if (metrics.stack.mac.ues.size() == 0 || metrics.phy.size() == 0 || i > metrics.stack.mac.ues.size() || i > metrics.phy.size()) { break; } - - if (metrics.stack.mac[i].tx_errors > metrics.stack.mac[i].tx_pkts) { - printf("tx caution errors %d > %d\n", metrics.stack.mac[i].tx_errors, metrics.stack.mac[i].tx_pkts); + if (metrics.stack.mac.ues[i].tx_errors > metrics.stack.mac.ues[i].tx_pkts) { + printf("tx caution errors %d > %d\n", metrics.stack.mac.ues[i].tx_errors, metrics.stack.mac.ues[i].tx_pkts); } - if (metrics.stack.mac[i].rx_errors > metrics.stack.mac[i].rx_pkts) { - printf("rx caution errors %d > %d\n", metrics.stack.mac[i].rx_errors, metrics.stack.mac[i].rx_pkts); + if (metrics.stack.mac.ues[i].rx_errors > metrics.stack.mac.ues[i].rx_pkts) { + printf("rx caution errors %d > %d\n", metrics.stack.mac.ues[i].rx_errors, metrics.stack.mac.ues[i].rx_pkts); } - cout << int_to_hex_string(metrics.stack.mac[i].rnti, 4) << " "; - cout << float_to_string(SRSLTE_MAX(0.1, metrics.stack.mac[i].dl_cqi), 1, 3); - cout << float_to_string(metrics.stack.mac[i].dl_ri, 1, 4); + cout << int_to_hex_string(metrics.stack.mac.ues[i].rnti, 4) << " "; + cout << float_to_string(SRSLTE_MAX(0.1, metrics.stack.mac.ues[i].dl_cqi), 1, 3); + cout << float_to_string(metrics.stack.mac.ues[i].dl_ri, 1, 4); if (not isnan(metrics.phy[i].dl.mcs)) { cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].dl.mcs), 1, 4); } else { cout << float_to_string(0, 2, 4); } - if (metrics.stack.mac[i].tx_brate > 0) { + if (metrics.stack.mac.ues[i].tx_brate > 0) { cout << float_to_eng_string( - SRSLTE_MAX(0.1, (float)metrics.stack.mac[i].tx_brate / (metrics.stack.mac[i].nof_tti * 1e-3)), 1); + SRSLTE_MAX(0.1, (float)metrics.stack.mac.ues[i].tx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3)), 1); } else { cout << float_to_string(0, 1, 6) << ""; } - cout << std::setw(5) << metrics.stack.mac[i].tx_pkts - metrics.stack.mac[i].tx_errors; - cout << std::setw(5) << metrics.stack.mac[i].tx_errors; - if (metrics.stack.mac[i].tx_pkts > 0 && metrics.stack.mac[i].tx_errors) { + cout << std::setw(5) << metrics.stack.mac.ues[i].tx_pkts - metrics.stack.mac.ues[i].tx_errors; + cout << std::setw(5) << metrics.stack.mac.ues[i].tx_errors; + if (metrics.stack.mac.ues[i].tx_pkts > 0 && metrics.stack.mac.ues[i].tx_errors) { cout << float_to_string( - SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].tx_errors / metrics.stack.mac[i].tx_pkts), 1, 4) + SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac.ues[i].tx_errors / metrics.stack.mac.ues[i].tx_pkts), 1, 4) << "%"; } else { cout << float_to_string(0, 1, 4) << "%"; @@ -132,29 +131,29 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe cout << float_to_string(0, 1, 4); } - cout << float_to_string(metrics.stack.mac[i].phr, 2, 5); + cout << float_to_string(metrics.stack.mac.ues[i].phr, 2, 5); if (not isnan(metrics.phy[i].ul.mcs)) { cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.mcs), 1, 4); } else { cout << float_to_string(0, 1, 4); } - if (metrics.stack.mac[i].rx_brate > 0) { + if (metrics.stack.mac.ues[i].rx_brate > 0) { cout << float_to_eng_string( - SRSLTE_MAX(0.1, (float)metrics.stack.mac[i].rx_brate / (metrics.stack.mac[i].nof_tti * 1e-3)), 1); + SRSLTE_MAX(0.1, (float)metrics.stack.mac.ues[i].rx_brate / (metrics.stack.mac.ues[i].nof_tti * 1e-3)), 1); } else { cout << float_to_string(0, 1) << ""; } - cout << std::setw(5) << metrics.stack.mac[i].rx_pkts - metrics.stack.mac[i].rx_errors; - cout << std::setw(5) << metrics.stack.mac[i].rx_errors; + cout << std::setw(5) << metrics.stack.mac.ues[i].rx_pkts - metrics.stack.mac.ues[i].rx_errors; + cout << std::setw(5) << metrics.stack.mac.ues[i].rx_errors; - if (metrics.stack.mac[i].rx_pkts > 0 && metrics.stack.mac[i].rx_errors > 0) { + if (metrics.stack.mac.ues[i].rx_pkts > 0 && metrics.stack.mac.ues[i].rx_errors > 0) { cout << float_to_string( - SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].rx_errors / metrics.stack.mac[i].rx_pkts), 1, 4) + SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac.ues[i].rx_errors / metrics.stack.mac.ues[i].rx_pkts), 1, 4) << "%"; } else { cout << float_to_string(0, 1, 4) << "%"; } - cout << float_to_eng_string(metrics.stack.mac[i].ul_buffer, 2); + cout << float_to_eng_string(metrics.stack.mac.ues[i].ul_buffer, 2); cout << endl; } diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index e402683ec..d076981ed 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -171,7 +171,7 @@ bool enb_stack_lte::get_metrics(stack_metrics_t* metrics) // use stack thread to query metrics auto ret = enb_task_queue.try_push([this]() { stack_metrics_t metrics{}; - mac.get_metrics(metrics.mac, metrics.cc_rach_counter); + mac.get_metrics(metrics.mac); rrc.get_metrics(metrics.rrc); s1ap.get_metrics(metrics.s1ap); pending_stack_metrics.push(metrics); diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 4a4e86f5a..0d6d9fb98 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -269,16 +269,16 @@ int mac::cell_cfg(const std::vector& cell_cfg_) return scheduler.cell_cfg(cell_config); } -void mac::get_metrics(std::vector& metrics, std::vector& _detected_rachs) +void mac::get_metrics(mac_metrics_t& metrics) { srslte::rwlock_read_guard lock(rwlock); int cnt = 0; - metrics.resize(ue_db.size()); - _detected_rachs = detected_rachs; + metrics.ues.resize(ue_db.size()); for (auto& u : ue_db) { - u.second->metrics_read(&metrics[cnt]); + u.second->metrics_read(&metrics.ues[cnt]); cnt++; } + metrics.cc_rach_counter = detected_rachs; } /******************************************************** diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index b2c596af6..44ae26200 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -80,7 +80,7 @@ ue::~ue() void ue::reset() { - metrics = {}; + ue_metrics = {}; nof_failures = 0; for (auto cc : softbuffer_rx) { @@ -519,75 +519,75 @@ uint8_t* ue::generate_mch_pdu(uint32_t harq_pid, } /******* METRICS interface ***************/ -void ue::metrics_read(mac_metrics_t* metrics_) +void ue::metrics_read(mac_ue_metrics_t* metrics_) { - metrics.rnti = rnti; - metrics.ul_buffer = sched->get_ul_buffer(rnti); - metrics.dl_buffer = sched->get_dl_buffer(rnti); + ue_metrics.rnti = rnti; + ue_metrics.ul_buffer = sched->get_ul_buffer(rnti); + ue_metrics.dl_buffer = sched->get_dl_buffer(rnti); // set PCell sector id std::array cc_list = sched->get_enb_ue_cc_map(rnti); auto it = std::find(cc_list.begin(), cc_list.end(), 0); - metrics.cc_idx = std::distance(cc_list.begin(), it); + ue_metrics.cc_idx = std::distance(cc_list.begin(), it); - memcpy(metrics_, &metrics, sizeof(mac_metrics_t)); + *metrics_ = ue_metrics; phr_counter = 0; dl_cqi_counter = 0; - metrics = {}; + ue_metrics = {}; } void ue::metrics_phr(float phr) { - metrics.phr = SRSLTE_VEC_CMA(phr, metrics.phr, phr_counter); + ue_metrics.phr = SRSLTE_VEC_CMA(phr, ue_metrics.phr, phr_counter); phr_counter++; } void ue::metrics_dl_ri(uint32_t dl_ri) { - if (metrics.dl_ri == 0.0f) { - metrics.dl_ri = (float)dl_ri + 1.0f; + if (ue_metrics.dl_ri == 0.0f) { + ue_metrics.dl_ri = (float)dl_ri + 1.0f; } else { - metrics.dl_ri = SRSLTE_VEC_EMA((float)dl_ri + 1.0f, metrics.dl_ri, 0.5f); + ue_metrics.dl_ri = SRSLTE_VEC_EMA((float)dl_ri + 1.0f, ue_metrics.dl_ri, 0.5f); } dl_ri_counter++; } void ue::metrics_dl_pmi(uint32_t dl_ri) { - metrics.dl_pmi = SRSLTE_VEC_CMA((float)dl_ri, metrics.dl_pmi, dl_pmi_counter); + ue_metrics.dl_pmi = SRSLTE_VEC_CMA((float)dl_ri, ue_metrics.dl_pmi, dl_pmi_counter); dl_pmi_counter++; } void ue::metrics_dl_cqi(uint32_t dl_cqi) { - metrics.dl_cqi = SRSLTE_VEC_CMA((float)dl_cqi, metrics.dl_cqi, dl_cqi_counter); + ue_metrics.dl_cqi = SRSLTE_VEC_CMA((float)dl_cqi, ue_metrics.dl_cqi, dl_cqi_counter); dl_cqi_counter++; } void ue::metrics_rx(bool crc, uint32_t tbs) { if (crc) { - metrics.rx_brate += tbs * 8; + ue_metrics.rx_brate += tbs * 8; } else { - metrics.rx_errors++; + ue_metrics.rx_errors++; } - metrics.rx_pkts++; + ue_metrics.rx_pkts++; } void ue::metrics_tx(bool crc, uint32_t tbs) { if (crc) { - metrics.tx_brate += tbs * 8; + ue_metrics.tx_brate += tbs * 8; } else { - metrics.tx_errors++; + ue_metrics.tx_errors++; } - metrics.tx_pkts++; + ue_metrics.tx_pkts++; } void ue::metrics_cnt() { - metrics.nof_tti++; + ue_metrics.nof_tti++; } void ue::tic() diff --git a/srsenb/test/enb_metrics_test.cc b/srsenb/test/enb_metrics_test.cc index a08f4277e..6b1372db9 100644 --- a/srsenb/test/enb_metrics_test.cc +++ b/srsenb/test/enb_metrics_test.cc @@ -38,20 +38,20 @@ public: // first entry metrics[0].rf.rf_o = 10; metrics[0].stack.rrc.ues.resize(1); - metrics[0].stack.mac.resize(metrics[0].stack.rrc.ues.size()); - metrics[0].stack.mac[0].rnti = 0x46; - metrics[0].stack.mac[0].tx_pkts = 1000; - metrics[0].stack.mac[0].tx_errors = 1000; - metrics[0].stack.mac[0].tx_brate = 0; - metrics[0].stack.mac[0].rx_pkts = 50; - metrics[0].stack.mac[0].rx_errors = 49; - metrics[0].stack.mac[0].rx_brate = 2; - metrics[0].stack.mac[0].ul_buffer = 100; - metrics[0].stack.mac[0].dl_buffer = 200; - metrics[0].stack.mac[0].dl_cqi = 15.9; - metrics[0].stack.mac[0].dl_ri = 1.5; - metrics[0].stack.mac[0].dl_pmi = 1.0; - metrics[0].stack.mac[0].phr = 12.0; + metrics[0].stack.mac.ues.resize(metrics[0].stack.rrc.ues.size()); + metrics[0].stack.mac.ues[0].rnti = 0x46; + metrics[0].stack.mac.ues[0].tx_pkts = 1000; + metrics[0].stack.mac.ues[0].tx_errors = 1000; + metrics[0].stack.mac.ues[0].tx_brate = 0; + metrics[0].stack.mac.ues[0].rx_pkts = 50; + metrics[0].stack.mac.ues[0].rx_errors = 49; + metrics[0].stack.mac.ues[0].rx_brate = 2; + metrics[0].stack.mac.ues[0].ul_buffer = 100; + metrics[0].stack.mac.ues[0].dl_buffer = 200; + metrics[0].stack.mac.ues[0].dl_cqi = 15.9; + metrics[0].stack.mac.ues[0].dl_ri = 1.5; + metrics[0].stack.mac.ues[0].dl_pmi = 1.0; + metrics[0].stack.mac.ues[0].phr = 12.0; metrics[0].phy.resize(1); metrics[0].phy[0].dl.mcs = 28.0; metrics[0].phy[0].ul.mcs = 20.2; @@ -60,20 +60,20 @@ public: // second metrics[1].rf.rf_o = 10; metrics[1].stack.rrc.ues.resize(1); - metrics[1].stack.mac.resize(metrics[1].stack.rrc.ues.size()); - metrics[1].stack.mac[0].rnti = 0xffff; - metrics[1].stack.mac[0].tx_pkts = 100; - metrics[1].stack.mac[0].tx_errors = 0; - metrics[1].stack.mac[0].tx_brate = 1e6; - metrics[1].stack.mac[0].rx_pkts = 50; - metrics[1].stack.mac[0].rx_errors = 10; - metrics[1].stack.mac[0].rx_brate = 1e3; - metrics[1].stack.mac[0].ul_buffer = 100; - metrics[1].stack.mac[0].dl_buffer = 200; - metrics[1].stack.mac[0].dl_cqi = 1.2; - metrics[1].stack.mac[0].dl_ri = 1.5; - metrics[1].stack.mac[0].dl_pmi = 1.0; - metrics[1].stack.mac[0].phr = 99.1; + metrics[1].stack.mac.ues.resize(metrics[1].stack.rrc.ues.size()); + metrics[1].stack.mac.ues[0].rnti = 0xffff; + metrics[1].stack.mac.ues[0].tx_pkts = 100; + metrics[1].stack.mac.ues[0].tx_errors = 0; + metrics[1].stack.mac.ues[0].tx_brate = 1e6; + metrics[1].stack.mac.ues[0].rx_pkts = 50; + metrics[1].stack.mac.ues[0].rx_errors = 10; + metrics[1].stack.mac.ues[0].rx_brate = 1e3; + metrics[1].stack.mac.ues[0].ul_buffer = 100; + metrics[1].stack.mac.ues[0].dl_buffer = 200; + metrics[1].stack.mac.ues[0].dl_cqi = 1.2; + metrics[1].stack.mac.ues[0].dl_ri = 1.5; + metrics[1].stack.mac.ues[0].dl_pmi = 1.0; + metrics[1].stack.mac.ues[0].phr = 99.1; metrics[1].phy.resize(1); metrics[1].phy[0].dl.mcs = 6.2; metrics[1].phy[0].ul.mcs = 28.0; @@ -82,20 +82,20 @@ public: // third entry metrics[2].rf.rf_o = 10; metrics[2].stack.rrc.ues.resize(1); - metrics[2].stack.mac.resize(metrics[2].stack.rrc.ues.size()); - metrics[2].stack.mac[0].rnti = 0x1; - metrics[2].stack.mac[0].tx_pkts = 9999; - metrics[2].stack.mac[0].tx_errors = 1; - metrics[2].stack.mac[0].tx_brate = 776; - metrics[2].stack.mac[0].rx_pkts = 50; - metrics[2].stack.mac[0].rx_errors = 0; - metrics[2].stack.mac[0].rx_brate = 1e3; - metrics[2].stack.mac[0].ul_buffer = 100; - metrics[2].stack.mac[0].dl_buffer = 200; - metrics[2].stack.mac[0].dl_cqi = 15.9; - metrics[2].stack.mac[0].dl_ri = 1.5; - metrics[2].stack.mac[0].dl_pmi = 1.0; - metrics[2].stack.mac[0].phr = 12.0; + metrics[2].stack.mac.ues.resize(metrics[2].stack.rrc.ues.size()); + metrics[2].stack.mac.ues[0].rnti = 0x1; + metrics[2].stack.mac.ues[0].tx_pkts = 9999; + metrics[2].stack.mac.ues[0].tx_errors = 1; + metrics[2].stack.mac.ues[0].tx_brate = 776; + metrics[2].stack.mac.ues[0].rx_pkts = 50; + metrics[2].stack.mac.ues[0].rx_errors = 0; + metrics[2].stack.mac.ues[0].rx_brate = 1e3; + metrics[2].stack.mac.ues[0].ul_buffer = 100; + metrics[2].stack.mac.ues[0].dl_buffer = 200; + metrics[2].stack.mac.ues[0].dl_cqi = 15.9; + metrics[2].stack.mac.ues[0].dl_ri = 1.5; + metrics[2].stack.mac.ues[0].dl_pmi = 1.0; + metrics[2].stack.mac.ues[0].phr = 12.0; metrics[2].phy.resize(1); metrics[2].phy[0].dl.mcs = 28.0; metrics[2].phy[0].ul.mcs = 20.2;