Commit 51785980 authored by Kirill Smelkov's avatar Kirill Smelkov

demo/kpidemo.*: Refactor commonly used bits into helper routines

- move code to load amari.kpi.LogMeasure -> kpi.MeasurementLog into
  load_measurements(). We will need to use that when showcasing E-UTRAN
  IP Throughput KPI to load another enb.xlog dataset.
- factor code to iterate over MeasurementLog and invoke kpi.Calc on each
  period into calc_each_period(). Same reason.
- factor plotting code into helper routines located only in kpidemo.py.
  The notebook version now uses those routines by way of importing. The
  plotting code is not helping to understand the KPI computation
  pipeline usage, so it makes sense not to show it out of the box in the
  demo notebook.
parent 1dc74b0c
...@@ -78,15 +78,19 @@ ...@@ -78,15 +78,19 @@
"source": [ "source": [
"from xlte import kpi\n", "from xlte import kpi\n",
"\n", "\n",
"mlog = kpi.MeasurementLog()\n", "def load_measurements(alogm: akpi.LogMeasure) -> kpi.MeasurementLog:\n",
"try:\n", " mlog = kpi.MeasurementLog()\n",
" while 1:\n", " try:\n",
" m = alogm.read()\n", " while 1:\n",
" if m is None:\n", " m = alogm.read()\n",
" break\n", " if m is None:\n",
" mlog.append(m)\n", " break\n",
"finally:\n", " mlog.append(m)\n",
" alogm.close()" " finally:\n",
" alogm.close()\n",
" return mlog\n",
"\n",
"mlog = load_measurements(alogm)"
] ]
}, },
{ {
...@@ -102,24 +106,38 @@ ...@@ -102,24 +106,38 @@
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 3,
"id": "00696868-2191-4176-b786-16e01a755230", "id": "00696868-2191-4176-b786-16e01a755230",
"metadata": {}, "metadata": {
"tags": []
},
"outputs": [], "outputs": [],
"source": [ "source": [
"import numpy as np\n",
"from datetime import datetime\n",
"\n",
"# calc_each_period partitions mlog data into periods and yields kpi.Calc for each period.\n",
"def calc_each_period(mlog: kpi.MeasurementLog, tperiod: float): # -> yield kpi.Calc\n",
" τ = mlog.data()[0]['X.Tstart']\n",
" for m in mlog.data()[1:]:\n",
" τ_ = m['X.Tstart']\n",
" if (τ_ - τ) >= tperiod:\n",
" calc = kpi.Calc(mlog, τ, τ+tperiod)\n",
" τ = calc.τ_hi\n",
" yield calc\n",
"\n",
"tperiod = 1*60 # 1 minute\n", "tperiod = 1*60 # 1 minute\n",
"vτ = []\n", "vτ = []\n",
"vInititialEPSBEstabSR = []\n", "vInititialEPSBEstabSR = []\n",
"vAddedEPSBEstabSR = []\n", "vAddedEPSBEstabSR = []\n",
"\n", "\n",
"τ = mlog.data()[0]['X.Tstart']\n", "for calc in calc_each_period(mlog, tperiod):\n",
"for m in mlog.data()[1:]:\n", " vτ.append(calc.τ_lo)\n",
" τ_ = m['X.Tstart']\n", " _ = calc.erab_accessibility() # E-RAB Accessibility\n",
" if (τ_ - τ) >= tperiod:\n", " vInititialEPSBEstabSR.append(_[0])\n",
" calc = kpi.Calc(mlog, τ, τ+tperiod)\n", " vAddedEPSBEstabSR .append(_[1])\n",
" vτ.append(calc.τ_lo)\n", "\n",
" τ = calc.τ_hi\n", "vτ = np.asarray([datetime.fromtimestamp(_) for _ in vτ])\n",
" _ = calc.erab_accessibility()\n", "vInititialEPSBEstabSR = np.asarray(vInititialEPSBEstabSR)\n",
" vInititialEPSBEstabSR.append(_[0])\n", "vAddedEPSBEstabSR = np.asarray(vAddedEPSBEstabSR)"
" vAddedEPSBEstabSR .append(_[1])"
] ]
}, },
{ {
...@@ -167,42 +185,10 @@ ...@@ -167,42 +185,10 @@
} }
], ],
"source": [ "source": [
"import numpy as np\n", "from xlte.demo import kpidemo\n",
"import matplotlib.pyplot as plt\n", "import matplotlib.pyplot as plt\n",
"import matplotlib.dates as mdates\n",
"from datetime import datetime\n",
"\n", "\n",
"fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, layout='constrained')\n", "kpidemo.figplot_erab_accessibility(plt.gcf(), vτ, vInititialEPSBEstabSR, vAddedEPSBEstabSR, tperiod)"
"pmin, psec = divmod(tperiod, 60) \n",
"fig.suptitle(\"E-RAB Accessibility / %s%s\" % (\"%d'\" % pmin if pmin else '', \n",
" '%d\"' % psec if psec else ''))\n",
"ax1.set_title(\"Initial E-RAB establishment success rate\")\n",
"ax2.set_title(\"Added E-RAB establishment success rate\")\n",
"\n",
"vτ = [datetime.fromtimestamp(_) for _ in vτ] \n",
"def plot1(ax, v, label): # plot1 plots KPI data from vector v on ax.\n",
" v = np.asarray(v)\n",
" ax.plot(vτ, v['lo'], drawstyle='steps-post', label=label)\n",
" ax.fill_between(vτ, v['lo'], v['hi'],\n",
" step='post', alpha=0.1, label='%s\\nuncertainty' % label)\n",
"\n",
"plot1(ax1, vInititialEPSBEstabSR, \"InititialEPSBEstabSR\")\n",
"plot1(ax2, vAddedEPSBEstabSR, \"AddedEPSBEstabSR\")\n",
"\n",
"for ax in (ax1, ax2):\n",
" ax.set_ylabel(\"%\")\n",
" ax.set_ylim([0-10, 100+10])\n",
" ax.set_yticks([0,20,40,60,80,100])\n",
"\n",
" xloc = mdates.AutoDateLocator()\n",
" xfmt = mdates.ConciseDateFormatter(xloc)\n",
" ax.xaxis.set_major_locator(xloc)\n",
" ax.xaxis.set_major_formatter(xfmt)\n",
"\n",
" ax.grid(True)\n",
" ax.legend(loc='upper left')\n",
"\n",
"plt.show()"
] ]
}, },
{ {
......
...@@ -11,7 +11,7 @@ from golang import func, defer ...@@ -11,7 +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 datetime import datetime from datetime import datetime, timedelta
import sys import sys
from urllib.request import urlopen from urllib.request import urlopen
...@@ -45,33 +45,49 @@ def main(): ...@@ -45,33 +45,49 @@ def main():
# The data, as contained in the measurement log, is kept there in the form # The data, as contained in the measurement log, is kept there in the form
# of kpi.Measurement, which is driver-independent representation for # of kpi.Measurement, which is driver-independent representation for
# KPI-related measurement data. # KPI-related measurement data.
mlog = kpi.MeasurementLog()
while 1: def load_measurements(alogm: akpi.LogMeasure) -> kpi.MeasurementLog:
m = alogm.read() mlog = kpi.MeasurementLog()
if m is None: while 1:
break m = alogm.read()
mlog.append(m) if m is None:
break
mlog.append(m)
return mlog
mlog = load_measurements(alogm)
# Step 3. Compute E-RAB Accessibility KPI over MeasurementLog with # Step 3. Compute E-RAB Accessibility KPI over MeasurementLog with
# specified granularity period. We partition entries in the measurement log # specified granularity period. We partition entries in the measurement log
# by specified time period, and further use kpi.Calc to compute the KPI # by specified time period, and further use kpi.Calc to compute the KPI
# over each period. # over 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
τ = mlog.data()[0]['X.Tstart']
for m in mlog.data()[1:]:
τ_ = m['X.Tstart']
if (τ_ - τ) >= tperiod:
calc = kpi.Calc(mlog, τ, τ+tperiod)
τ = calc.τ_hi
yield calc
tperiod = float(sys.argv[1]) tperiod = float(sys.argv[1])
vτ = [] vτ = []
vInititialEPSBEstabSR = [] vInititialEPSBEstabSR = []
vAddedEPSBEstabSR = [] vAddedEPSBEstabSR = []
τ = mlog.data()[0]['X.Tstart'] for calc in calc_each_period(mlog, tperiod):
for m in mlog.data()[1:]: vτ.append(calc.τ_lo)
τ_ = m['X.Tstart']
if (τ_ - τ) >= tperiod: _ = calc.erab_accessibility() # E-RAB Accessibility
calc = kpi.Calc(mlog, τ, τ+tperiod) vInititialEPSBEstabSR.append(_[0])
vτ.append(calc.τ_lo) vAddedEPSBEstabSR .append(_[1])
τ = calc.τ_hi
_ = calc.erab_accessibility() vτ = np.asarray([datetime.fromtimestamp(_) for _ in vτ])
vInititialEPSBEstabSR.append(_[0]) vInititialEPSBEstabSR = np.asarray(vInititialEPSBEstabSR)
vAddedEPSBEstabSR .append(_[1]) vAddedEPSBEstabSR = np.asarray(vAddedEPSBEstabSR)
# Step 4. Plot computed KPI. # Step 4. Plot computed KPI.
...@@ -94,37 +110,69 @@ def main(): ...@@ -94,37 +110,69 @@ 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, (ax1, ax2) = plt.subplots(2, 1, sharex=True, layout='constrained') fig = plt.figure(constrained_layout=True, figsize=(6,8))
pmin, psec = divmod(tperiod, 60) figplot_erab_accessibility (fig, vτ, vInititialEPSBEstabSR, vAddedEPSBEstabSR, tperiod)
fig.suptitle("E-RAB Accessibility / %s%s" % ("%d'" % pmin if pmin else '', plt.show()
'%d"' % psec if psec else ''))
ax1.set_title("Initial E-RAB establishment success rate")
ax2.set_title("Added E-RAB establishment success rate")
vτ = [datetime.fromtimestamp(_) for _ in vτ]
def plot1(ax, v, label): # plot1 plots KPI data from vector v on ax.
v = np.asarray(v)
ax.plot(vτ, v['lo'], drawstyle='steps-post', label=label)
ax.fill_between(vτ, v['lo'], v['hi'],
step='post', alpha=0.1, label='%s\nuncertainty' % label)
plot1(ax1, vInititialEPSBEstabSR, "InititialEPSBEstabSR")
plot1(ax2, vAddedEPSBEstabSR, "AddedEPSBEstabSR")
for ax in (ax1, ax2):
ax.set_ylabel("%")
ax.set_ylim([0-10, 100+10])
ax.set_yticks([0,20,40,60,80,100])
xloc = mdates.AutoDateLocator() # ---- plotting routines ----
xfmt = mdates.ConciseDateFormatter(xloc)
ax.xaxis.set_major_locator(xloc)
ax.xaxis.set_major_formatter(xfmt)
ax.grid(True) # figplot_erab_accessibility plots E-RAB Accessibility KPI data on the figure.
ax.legend(loc='upper left') def figplot_erab_accessibility(fig: plt.Figure, vτ, vInititialEPSBEstabSR, vAddedEPSBEstabSR, tperiod=None):
ax1, ax2 = fig.subplots(2, 1, sharex=True)
fig.suptitle("E-RAB Accessibility / %s" % (tpretty(tperiod) if tperiod is not None else
vτ_period_pretty(vτ)))
ax1.set_title("Initial E-RAB establishment success rate")
ax2.set_title("Added E-RAB establishment success rate")
plt.show() plot_success_rate(ax1, vτ, vInititialEPSBEstabSR, "InititialEPSBEstabSR")
plot_success_rate(ax2, vτ, vAddedEPSBEstabSR, "AddedEPSBEstabSR")
# plot_success_rate plots success-rate data from vector v on ax.
# v is array with Intervals.
def plot_success_rate(ax, vτ, v, label):
ax.plot(vτ, v['lo'], drawstyle='steps-post', label=label)
ax.fill_between(vτ, v['lo'], v['hi'],
step='post', alpha=0.1, label='%s\nuncertainty' % label)
ax.set_ylabel("%")
ax.set_ylim([0-10, 100+10])
ax.set_yticks([0,20,40,60,80,100])
fmt_dates_pretty(ax.xaxis)
ax.grid(True)
ax.legend(loc='upper left')
# fmt_dates_pretty instructs axis to use concise dates formatting.
def fmt_dates_pretty(axis):
xloc = mdates.AutoDateLocator()
xfmt = mdates.ConciseDateFormatter(xloc)
axis.set_major_locator(xloc)
axis.set_major_formatter(xfmt)
# tpretty returns pretty form for time, e.g. 1'2" for 62 seconds.
def tpretty(t):
tmin, tsec = divmod(t, 60)
return "%s%s" % ("%d'" % tmin if tmin else '',
'%d"' % tsec if tsec else '')
# vτ_period_pretty returns pretty form for time period in vector vτ.
# for example [2,5,8,11] gives 3'.
def vτ_period_pretty(vτ):
if len(vτ) < 2:
return "?"
s = timedelta(seconds=1)
δvτ = (vτ[1:] - vτ[:-1]) / s # in seconds
min = δvτ.min()
avg = δvτ.mean()
max = δvτ.max()
std = δvτ.std()
if min == max:
return tpretty(min)
return "%s ±%s [%s, %s]" % (tpretty(avg), tpretty(std), tpretty(min), tpretty(max))
if __name__ == '__main__': if __name__ == '__main__':
......
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