Commit 4b2c8c21 authored by Kirill Smelkov's avatar Kirill Smelkov

demo/kpidemo.*: Add support for E-UTRAN IP Throughput KPI + demonstrate it in the notebook

Show how to compute that KPI, add corresponding plotting routines, and
teach kpidemo.py to display both E-RAB Accessibility and E-UTRAN IP
Throughput simultaneously in the same window.

Add corresponding demonstration into demo notebook with data from
throughput experiment showcasing several scenarious and how E-UTRAN IP
Throughput implementation handles them.
parent 51785980
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -11,6 +11,7 @@ from golang import func, defer ...@@ -11,6 +11,7 @@ from golang import func, defer
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.dates as mdates import matplotlib.dates as mdates
from matplotlib import ticker
from datetime import datetime, timedelta from datetime import datetime, timedelta
import sys import sys
...@@ -58,10 +59,9 @@ def main(): ...@@ -58,10 +59,9 @@ def main():
mlog = load_measurements(alogm) mlog = load_measurements(alogm)
# Step 3. Compute E-RAB Accessibility KPI over MeasurementLog with # Step 3. Compute KPIs over MeasurementLog with specified granularity
# specified granularity period. We partition entries in the measurement log # period. We partition entries in the measurement log by specified time
# by specified time period, and further use kpi.Calc to compute the KPI # period, and further use kpi.Calc to compute the KPIs over each period.
# over each period.
# calc_each_period partitions mlog data into periods and yields kpi.Calc for each period. # calc_each_period partitions mlog data into periods and yields kpi.Calc for each period.
def calc_each_period(mlog: kpi.MeasurementLog, tperiod: float): # -> yield kpi.Calc def calc_each_period(mlog: kpi.MeasurementLog, tperiod: float): # -> yield kpi.Calc
...@@ -77,6 +77,7 @@ def main(): ...@@ -77,6 +77,7 @@ def main():
vτ = [] vτ = []
vInititialEPSBEstabSR = [] vInititialEPSBEstabSR = []
vAddedEPSBEstabSR = [] vAddedEPSBEstabSR = []
vIPThp_qci = []
for calc in calc_each_period(mlog, tperiod): for calc in calc_each_period(mlog, tperiod):
vτ.append(calc.τ_lo) vτ.append(calc.τ_lo)
...@@ -85,13 +86,18 @@ def main(): ...@@ -85,13 +86,18 @@ def main():
vInititialEPSBEstabSR.append(_[0]) vInititialEPSBEstabSR.append(_[0])
vAddedEPSBEstabSR .append(_[1]) vAddedEPSBEstabSR .append(_[1])
_ = calc.eutran_ip_throughput() # E-UTRAN IP Throughput
vIPThp_qci.append(_)
vτ = np.asarray([datetime.fromtimestamp(_) for _ in vτ]) vτ = np.asarray([datetime.fromtimestamp(_) for _ in vτ])
vInititialEPSBEstabSR = np.asarray(vInititialEPSBEstabSR) vInititialEPSBEstabSR = np.asarray(vInititialEPSBEstabSR)
vAddedEPSBEstabSR = np.asarray(vAddedEPSBEstabSR) vAddedEPSBEstabSR = np.asarray(vAddedEPSBEstabSR)
vIPThp_qci = np.asarray(vIPThp_qci)
# Step 4. Plot computed KPIs.
# Step 4. Plot computed KPI. # 4a) The E-RAB Accessibility KPI has two parts: initial E-RAB establishment
# The E-RAB Accessibility KPI has two parts: initial E-RAB establishment
# success rate, and additional E-RAB establishment success rate. kpi.Calc # success rate, and additional E-RAB establishment success rate. kpi.Calc
# provides both of them in the form of their confidence intervals. The # provides both of them in the form of their confidence intervals. The
# lower margin of the confidence interval coincides with 3GPP definition of # lower margin of the confidence interval coincides with 3GPP definition of
...@@ -110,8 +116,15 @@ def main(): ...@@ -110,8 +116,15 @@ def main():
# #
# For each of the parts we plot both its lower margin and the whole # For each of the parts we plot both its lower margin and the whole
# confidence interval area. # confidence interval area.
fig = plt.figure(constrained_layout=True, figsize=(6,8))
figplot_erab_accessibility (fig, vτ, vInititialEPSBEstabSR, vAddedEPSBEstabSR, tperiod) # 4b) The E-UTRAN IP Throughput KPI provides throughput measurements for
# all QCIs and does not have uncertainty. QCIs for which throughput data is
# all zeros are said to be silent and are not plotted.
fig = plt.figure(constrained_layout=True, figsize=(12,8))
facc, fthp = fig.subfigures(1, 2)
figplot_erab_accessibility (facc, vτ, vInititialEPSBEstabSR, vAddedEPSBEstabSR, tperiod)
figplot_eutran_ip_throughput(fthp, vτ, vIPThp_qci, tperiod)
plt.show() plt.show()
...@@ -129,6 +142,27 @@ def figplot_erab_accessibility(fig: plt.Figure, vτ, vInititialEPSBEstabSR, vAdd ...@@ -129,6 +142,27 @@ def figplot_erab_accessibility(fig: plt.Figure, vτ, vInititialEPSBEstabSR, vAdd
plot_success_rate(ax2, vτ, vAddedEPSBEstabSR, "AddedEPSBEstabSR") plot_success_rate(ax2, vτ, vAddedEPSBEstabSR, "AddedEPSBEstabSR")
# figplot_eutran_ip_throughput plots E-UTRAN IP Throughput KPI data on the figure.
def figplot_eutran_ip_throughput(fig: plt.Figure, vτ, vIPThp_qci, tperiod=None):
ax1, ax2 = fig.subplots(2, 1, sharex=True)
fig.suptitle("E-UTRAN IP Throughput / %s" % (tpretty(tperiod) if tperiod is not None else
vτ_period_pretty(vτ)))
ax1.set_title("Downlink")
ax2.set_title("Uplink")
ax1.set_ylabel("Mbit/s")
ax2.set_ylabel("Mbit/s")
v_qci = (vIPThp_qci .view(np.float64) / 1e6) \
.view(vIPThp_qci.dtype)
plot_per_qci(ax1, vτ, v_qci[:,:]['dl'], 'IPThp')
plot_per_qci(ax2, vτ, v_qci[:,:]['ul'], 'IPThp')
_, dmax = ax1.get_ylim()
_, umax = ax2.get_ylim()
ax1.set_ylim(ymin=0, ymax=dmax*1.05)
ax2.set_ylim(ymin=0, ymax=umax*1.05)
# plot_success_rate plots success-rate data from vector v on ax. # plot_success_rate plots success-rate data from vector v on ax.
# v is array with Intervals. # v is array with Intervals.
def plot_success_rate(ax, vτ, v, label): def plot_success_rate(ax, vτ, v, label):
...@@ -145,12 +179,39 @@ def plot_success_rate(ax, vτ, v, label): ...@@ -145,12 +179,39 @@ def plot_success_rate(ax, vτ, v, label):
ax.legend(loc='upper left') ax.legend(loc='upper left')
# plot_per_qci plots data from per-QCI vector v_qci.
#
# v_qci should be array[t, QCI].
# QCIs, for which v[:,qci] is all zeros, are said to be silent and are not plotted.
def plot_per_qci(ax, vτ, v_qci, label):
ax.set_xlim((vτ[0], vτ[-1])) # to have correct x range even if we have no data
assert len(v_qci.shape) == 2
silent = True
propv = list(plt.rcParams['axes.prop_cycle'])
for qci in range(v_qci.shape[1]):
v = v_qci[:, qci]
if (v['hi'] == 0).all(): # skip silent QCIs
continue
silent = False
prop = propv[qci % len(propv)] # to have same colors for same qci in different graphs
ax.plot(vτ, v['lo'], label="%s.%d" % (label, qci), **prop)
ax.fill_between(vτ, v['lo'], v['hi'], alpha=0.3, **prop)
if silent:
ax.plot([],[], ' ', label="all QCI silent")
fmt_dates_pretty(ax.xaxis)
ax.grid(True)
ax.legend(loc='upper left')
# fmt_dates_pretty instructs axis to use concise dates formatting. # fmt_dates_pretty instructs axis to use concise dates formatting.
def fmt_dates_pretty(axis): def fmt_dates_pretty(axis):
xloc = mdates.AutoDateLocator() xloc = mdates.AutoDateLocator()
xfmt = mdates.ConciseDateFormatter(xloc) xfmt = mdates.ConciseDateFormatter(xloc)
axis.set_major_locator(xloc) axis.set_major_locator(xloc)
axis.set_major_formatter(xfmt) axis.set_major_formatter(xfmt)
axis.set_minor_locator(ticker.AutoMinorLocator(5))
# tpretty returns pretty form for time, e.g. 1'2" for 62 seconds. # tpretty returns pretty form for time, e.g. 1'2" for 62 seconds.
......
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