tbf: Add adaptive DL CS adjustment
To cope with transmission failures due to bad radio conditions, a different coding scheme with more redundance can be used. This commit adds an implemenation that is based on the Ack/Nack ratio per PACKET DOWNLINK ACK/NACK message received from the MS. Basically the CS level is decreased, if the block error rate goes above cs_adj_upper_limit (default 33%), and it is increased, if the rate drops below cs_adj_lower_limit (default 10%). Only blocks that have been encoded with the current CS are taken into account. Note that this approach doesn't measure the MS->BTS conditions and that the measurement values reported by the MS are not taken into account. Ticket: #1739 Sponsored-by: On-Waves ehf
This commit is contained in:
parent
f47f68a9d8
commit
1751c62c98
|
@ -142,6 +142,9 @@ struct gprs_rlcmac_bts {
|
||||||
uint8_t alpha, gamma;
|
uint8_t alpha, gamma;
|
||||||
uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */
|
uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */
|
||||||
uint32_t ms_idle_sec;
|
uint32_t ms_idle_sec;
|
||||||
|
uint8_t cs_adj_enabled;
|
||||||
|
uint8_t cs_adj_upper_limit;
|
||||||
|
uint8_t cs_adj_lower_limit;
|
||||||
|
|
||||||
/* TBF handling, make private or move into TBFController */
|
/* TBF handling, make private or move into TBFController */
|
||||||
/* list of uplink TBFs */
|
/* list of uplink TBFs */
|
||||||
|
|
|
@ -351,3 +351,39 @@ void GprsMs::set_ms_class(uint8_t ms_class_)
|
||||||
m_ms_class = ms_class_;
|
m_ms_class = ms_class_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
|
||||||
|
{
|
||||||
|
struct gprs_rlcmac_bts *bts_data;
|
||||||
|
|
||||||
|
OSMO_ASSERT(m_bts != NULL);
|
||||||
|
bts_data = m_bts->bts_data();
|
||||||
|
|
||||||
|
if (error_rate < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* TODO: Support different CS values for UL and DL */
|
||||||
|
|
||||||
|
if (error_rate > bts_data->cs_adj_upper_limit) {
|
||||||
|
if (m_current_cs_dl > 1) {
|
||||||
|
m_current_cs_dl -= 1;
|
||||||
|
m_current_cs_ul = m_current_cs_dl;
|
||||||
|
LOGP(DRLCMACDL, LOGL_INFO,
|
||||||
|
"MS (IMSI %s): High error rate %d%%, "
|
||||||
|
"reducing CS level to %d\n",
|
||||||
|
imsi(), error_rate, m_current_cs_dl);
|
||||||
|
}
|
||||||
|
} else if (error_rate < bts_data->cs_adj_lower_limit) {
|
||||||
|
if (m_current_cs_dl < 4) {
|
||||||
|
m_current_cs_dl += 1;
|
||||||
|
m_current_cs_ul = m_current_cs_dl;
|
||||||
|
LOGP(DRLCMACDL, LOGL_INFO,
|
||||||
|
"MS (IMSI %s): Low error rate %d%%, "
|
||||||
|
"increasing CS level to %d\n",
|
||||||
|
imsi(), error_rate, m_current_cs_dl);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGP(DRLCMACDL, LOGL_DEBUG,
|
||||||
|
"MS (IMSI %s): Medium error rate %d%%, ignored\n",
|
||||||
|
imsi(), error_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -86,6 +86,8 @@ public:
|
||||||
|
|
||||||
void detach_tbf(gprs_rlcmac_tbf *tbf);
|
void detach_tbf(gprs_rlcmac_tbf *tbf);
|
||||||
|
|
||||||
|
void update_error_rate(gprs_rlcmac_tbf *tbf, int percent);
|
||||||
|
|
||||||
bool is_idle() const {return !m_ul_tbf && !m_dl_tbf && !m_ref;}
|
bool is_idle() const {return !m_ul_tbf && !m_dl_tbf && !m_ref;}
|
||||||
|
|
||||||
void* operator new(size_t num);
|
void* operator new(size_t num);
|
||||||
|
|
|
@ -173,6 +173,9 @@ int main(int argc, char *argv[])
|
||||||
bts->n3105 = 8;
|
bts->n3105 = 8;
|
||||||
bts->alpha = 0; /* a = 0.0 */
|
bts->alpha = 0; /* a = 0.0 */
|
||||||
bts->ms_idle_sec = 60; /* slightly above T3314 (default 44s, 24.008, 11.2.2) */
|
bts->ms_idle_sec = 60; /* slightly above T3314 (default 44s, 24.008, 11.2.2) */
|
||||||
|
bts->cs_adj_enabled = 1;
|
||||||
|
bts->cs_adj_upper_limit = 33; /* Decrease CS if the error rate is above */
|
||||||
|
bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
|
||||||
|
|
||||||
msgb_set_talloc_ctx(tall_pcu_ctx);
|
msgb_set_talloc_ctx(tall_pcu_ctx);
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,8 @@ struct gprs_rlc_data {
|
||||||
uint8_t block[RLC_MAX_LEN];
|
uint8_t block[RLC_MAX_LEN];
|
||||||
/* block len of history */
|
/* block len of history */
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
|
|
||||||
|
uint8_t cs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -363,6 +363,7 @@ protected:
|
||||||
bool dl_window_stalled() const;
|
bool dl_window_stalled() const;
|
||||||
void reuse_tbf(const uint8_t *data, const uint16_t len);
|
void reuse_tbf(const uint8_t *data, const uint16_t len);
|
||||||
void start_llc_timer();
|
void start_llc_timer();
|
||||||
|
int analyse_errors(char *show_rbb, uint8_t ssn);
|
||||||
|
|
||||||
struct osmo_timer_list m_llc_timer;
|
struct osmo_timer_list m_llc_timer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -412,6 +412,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
|
||||||
/* now we still have untransmitted LLC data, so we fill mac block */
|
/* now we still have untransmitted LLC data, so we fill mac block */
|
||||||
rlc_data = m_rlc.block(bsn);
|
rlc_data = m_rlc.block(bsn);
|
||||||
data = rlc_data->prepare(block_data_len);
|
data = rlc_data->prepare(block_data_len);
|
||||||
|
rlc_data->cs = cs;
|
||||||
|
|
||||||
rh = (struct rlc_dl_header *)data;
|
rh = (struct rlc_dl_header *)data;
|
||||||
rh->pt = 0; /* Data Block */
|
rh->pt = 0; /* Data Block */
|
||||||
|
@ -669,6 +670,53 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
||||||
return dl_msg;
|
return dl_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn, uint16_t mod_sns)
|
||||||
|
{
|
||||||
|
return (ssn - 1 - bitnum) & mod_sns;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn)
|
||||||
|
{
|
||||||
|
gprs_rlc_data *rlc_data;
|
||||||
|
uint16_t lost = 0, received = 0, skipped = 0;
|
||||||
|
|
||||||
|
/* SSN - 1 is in range V(A)..V(S)-1 */
|
||||||
|
for (int bitpos = 0; bitpos < m_window.ws(); bitpos++) {
|
||||||
|
uint16_t bsn = bitnum_to_bsn(bitpos, ssn, m_window.mod_sns());
|
||||||
|
|
||||||
|
if (bsn == ((m_window.v_a() - 1) & m_window.mod_sns()))
|
||||||
|
break;
|
||||||
|
|
||||||
|
rlc_data = m_rlc.block(bsn);
|
||||||
|
if (!rlc_data)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (rlc_data->cs != current_cs()) {
|
||||||
|
/* This block has already been encoded with a different
|
||||||
|
* CS, so it doesn't help us to decide, whether the
|
||||||
|
* current CS is ok. Ignore it. */
|
||||||
|
skipped += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_rbb[m_window.ws() - 1 - bitpos] == 'R') {
|
||||||
|
if (!m_window.m_v_b.is_acked(bsn))
|
||||||
|
received += 1;
|
||||||
|
} else {
|
||||||
|
lost += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGP(DRLCMACDL, LOGL_DEBUG, "%s DL analysis, range=%d:%d, lost=%d, recv=%d, skipped=%d\n",
|
||||||
|
name(), m_window.v_a(), m_window.v_s(), lost, received, skipped);
|
||||||
|
|
||||||
|
if (lost + received == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return lost * 100 / (lost + received);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
|
int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
|
||||||
{
|
{
|
||||||
int16_t dist; /* must be signed */
|
int16_t dist; /* must be signed */
|
||||||
|
@ -676,6 +724,7 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
|
||||||
char show_rbb[65];
|
char show_rbb[65];
|
||||||
char show_v_b[RLC_MAX_SNS + 1];
|
char show_v_b[RLC_MAX_SNS + 1];
|
||||||
const uint16_t mod_sns = m_window.mod_sns();
|
const uint16_t mod_sns = m_window.mod_sns();
|
||||||
|
int error_rate;
|
||||||
|
|
||||||
Decoding::extract_rbb(rbb, show_rbb);
|
Decoding::extract_rbb(rbb, show_rbb);
|
||||||
/* show received array in debug (bit 64..1) */
|
/* show received array in debug (bit 64..1) */
|
||||||
|
@ -698,6 +747,11 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
|
||||||
return 1; /* indicate to free TBF */
|
return 1; /* indicate to free TBF */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bts_data()->cs_adj_enabled && ms()) {
|
||||||
|
error_rate = analyse_errors(show_rbb, ssn);
|
||||||
|
ms()->update_error_rate(this, error_rate);
|
||||||
|
}
|
||||||
|
|
||||||
m_window.update(bts, show_rbb, ssn,
|
m_window.update(bts, show_rbb, ssn,
|
||||||
&lost, &received);
|
&lost, &received);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue