Commit 2824f50d authored by Kirill Smelkov's avatar Kirill Smelkov

kpi: Calc: Add support for E-UTRAN IP Throughput KPI

This patch provides the final building block for E-UTRAN IP Throughput KPI.
It continues

    d102ffaa (drb: Start of the package)
    5bf7dc1c (amari.{drb,xlog}: Provide aggregated DRB statistics in the form of synthetic x.drb_stats message)
    499a7c1b (amari.kpi: Teach LogMeasure to handle x.drb_stats messages)

Quoting those patches

    The scheme to compute E-UTRAN IP Throughput is thus as follows: poll eNB at
    100Hz frequency for `ue_get[stats]` and retrieve information about per-UE/QCI
    streams and the number of transport blocks dl/ul-ed to the UE in question
    during that 10ms frame. Estimate `tx_time` taking into account
    the number of transmitted transport blocks. And estimate whether eNB is congested or
    not based on `dl_use_avg`/`ul_use_avg` taken from `stats`. For the latter we
    also need to poll for `stats` at 100Hz frequency and synchronize
    `ue_get[stats]` and `stats` requests in time so that they both cover the same
    time interval of particular frame.

    Then organize the polling process to provide aggregated statistics in the form of
    new `x.drb_stats` message, and teach `xamari xlog` to save that messages to
    `enb.xlog` together with `stats`.

    Then further adjust `amari.kpi.LogMeasure` and generic `kpi.Measurement`
    and `kpi.Calc` to handle DRB-related data.						<-- NOTE

So here we implement that last noted step:

We add Calc.eutran_ip_throughput() whose implementation is relatively
straightforward as the hard part is done by amari.drb and amari.kpi - in the
Calc we basically need to only divide provided DRB.IPVolDl / DRB.IPTimeDl.
parent 499a7c1b
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
information is emitted in the form of synthetic x.drb_stats message whose information is emitted in the form of synthetic x.drb_stats message whose
generation is integrated into amari.xlog package. generation is integrated into amari.xlog package.
Please see amari.kpi package that turns x.drb_stats data into Please see amari.kpi and xlte.kpi packages that turn x.drb_stats data into
measurements related to E-UTRAN IP Throughput KPI. final E-UTRAN IP Throughput KPI value.
See also the following related 3GPP standards references: See also the following related 3GPP standards references:
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
- Calc is KPI calculator. It can be instantiated on MeasurementLog and time - Calc is KPI calculator. It can be instantiated on MeasurementLog and time
interval over which to perform computations. Use Calc methods such as interval over which to perform computations. Use Calc methods such as
.erab_accessibility() to compute KPIs. .erab_accessibility() and .eutran_ip_throughput() to compute KPIs.
- MeasurementLog maintains journal with result of measurements. Use .append() - MeasurementLog maintains journal with result of measurements. Use .append()
to populate it with data. to populate it with data.
...@@ -58,6 +58,7 @@ from golang import func ...@@ -58,6 +58,7 @@ from golang import func
# following methods for computing 3GPP KPIs: # following methods for computing 3GPP KPIs:
# #
# .erab_accessibility() - TS 32.450 6.1.1 "E-RAB Accessibility" # .erab_accessibility() - TS 32.450 6.1.1 "E-RAB Accessibility"
# .eutran_ip_throughput() - TS 32.450 6.3.1 "E-UTRAN IP Throughput"
# TODO other KPIs # TODO other KPIs
# #
# Upon construction specified time interval is potentially widened to cover # Upon construction specified time interval is potentially widened to cover
...@@ -589,6 +590,71 @@ def _success_rate(calc, fini, init): # -> Interval in [0,1] ...@@ -589,6 +590,71 @@ def _success_rate(calc, fini, init): # -> Interval in [0,1]
return Interval(a,b) return Interval(a,b)
# eutran_ip_throughput computes "E-UTRAN IP Throughput" KPI.
#
# It returns the following:
#
# - IPThp[QCI][dl,ul] IP throughput per QCI for downlink and uplink (bit/s)
#
# All elements are returned as Intervals with information about confidence for
# computed values.
#
# NOTE: the unit of the result is bit/s, not kbit/s.
#
# 3GPP reference: TS 32.450 6.3.1 "E-UTRAN IP Throughput".
@func(Calc)
def eutran_ip_throughput(calc): # -> IPThp[QCI][dl,ul]
qdlΣv = np.zeros(nqci, dtype=np.float64)
qdlΣt = np.zeros(nqci, dtype=np.float64)
qdlΣte = np.zeros(nqci, dtype=np.float64)
qulΣv = np.zeros(nqci, dtype=np.float64)
qulΣt = np.zeros(nqci, dtype=np.float64)
qulΣte = np.zeros(nqci, dtype=np.float64)
for m in calc._miter():
τ = m['X.δT']
for qci in range(nqci):
dl_vol = m["DRB.IPVolDl.QCI"] [qci]
dl_time = m["DRB.IPTimeDl.QCI"] [qci]
dl_time_err = m["XXX.DRB.IPTimeDl_err.QCI"] [qci]
ul_vol = m["DRB.IPVolUl.QCI"] [qci]
ul_time = m["DRB.IPTimeUl.QCI"] [qci]
ul_time_err = m["XXX.DRB.IPTimeUl_err.QCI"] [qci]
if isNA(dl_vol) or isNA(dl_time) or isNA(dl_time_err):
# don't account uncertainty - here it is harder to do compared
# to erab_accessibility and the benefit is not clear. Follow
# plain 3GPP spec for now.
pass
else:
qdlΣv[qci] += dl_vol
qdlΣt[qci] += dl_time
qdlΣte[qci] += dl_time_err
if isNA(ul_vol) or isNA(ul_time) or isNA(ul_time_err):
# no uncertainty accounting - see ^^^
pass
else:
qulΣv[qci] += ul_vol
qulΣt[qci] += ul_time
qulΣte[qci] += ul_time_err
thp = np.zeros(nqci, dtype=np.dtype([
('dl', Interval._dtype),
('ul', Interval._dtype),
]))
for qci in range(nqci):
if qdlΣt[qci] > 0:
thp[qci]['dl']['lo'] = qdlΣv[qci] / (qdlΣt[qci] + qdlΣte[qci])
thp[qci]['dl']['hi'] = qdlΣv[qci] / (qdlΣt[qci] - qdlΣte[qci])
if qulΣt[qci] > 0:
thp[qci]['ul']['lo'] = qulΣv[qci] / (qulΣt[qci] + qulΣte[qci])
thp[qci]['ul']['hi'] = qulΣv[qci] / (qulΣt[qci] - qulΣte[qci])
return thp
# _miter iterates through [.τ_lo, .τ_hi) yielding Measurements. # _miter iterates through [.τ_lo, .τ_hi) yielding Measurements.
# #
# The measurements are yielded with consecutive timestamps. There is no gaps # The measurements are yielded with consecutive timestamps. There is no gaps
......
...@@ -439,6 +439,61 @@ def test_Calc_erab_accessibility(): ...@@ -439,6 +439,61 @@ def test_Calc_erab_accessibility():
_(InititialEPSBEstabSR, 100 * 2*3*4 / (7*8*9)) _(InititialEPSBEstabSR, 100 * 2*3*4 / (7*8*9))
# verify Calc.eutran_ip_throughput .
def test_Calc_eutran_ip_throughput():
# most of the job is done by drivers collecting DRB.IPVol{Dl,Ul} and DRB.IPTime{Dl,Ul}
# here we verify final aggregation, that eutran_ip_throughput does, only lightly.
m = Measurement()
m['X.Tstart'] = 10
m['X.δT'] = 10
m['DRB.IPVolDl.5'] = 55e6
m['DRB.IPVolUl.5'] = 55e5
m['DRB.IPTimeDl.5'] = 1e2
m['DRB.IPTimeUl.5'] = 1e2
m['DRB.IPVolDl.7'] = 75e6
m['DRB.IPVolUl.7'] = 75e5
m['DRB.IPTimeDl.7'] = 1e2
m['DRB.IPTimeUl.7'] = 1e2
m['DRB.IPVolDl.9'] = 0
m['DRB.IPVolUl.9'] = 0
m['DRB.IPTimeDl.9'] = 0
m['DRB.IPTimeUl.9'] = 0
for qci in {5,7,9}:
m['XXX.DRB.IPTimeDl_err.QCI'][qci] = 0
m['XXX.DRB.IPTimeUl_err.QCI'][qci] = 0
# (other QCIs are left with na)
for qci in set(range(nqci)).difference({5,7,9}):
assert isNA(m['DRB.IPVolDl.QCI'][qci])
assert isNA(m['DRB.IPVolUl.QCI'][qci])
assert isNA(m['DRB.IPTimeDl.QCI'][qci])
assert isNA(m['DRB.IPTimeUl.QCI'][qci])
assert isNA(m['XXX.DRB.IPTimeDl_err.QCI'][qci])
assert isNA(m['XXX.DRB.IPTimeUl_err.QCI'][qci])
mlog = MeasurementLog()
mlog.append(m)
calc = Calc(mlog, 10,20)
thp = calc.eutran_ip_throughput()
def I(x): return Interval(x,x)
assert thp[5]['dl'] == I(55e4)
assert thp[5]['ul'] == I(55e3)
assert thp[7]['dl'] == I(75e4)
assert thp[7]['ul'] == I(75e3)
assert thp[9]['dl'] == I(0)
assert thp[9]['ul'] == I(0)
for qci in set(range(nqci)).difference({5,7,9}):
assert thp[qci]['dl'] == I(0)
assert thp[qci]['ul'] == I(0)
# verify Σqci. # verify Σqci.
def test_Σqci(): def test_Σqci():
m = Measurement() m = Measurement()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment