Update thesis

This commit is contained in:
jaseg 2020-04-01 18:27:14 +02:00
parent a803d10b03
commit 6ab3ac3dff
18 changed files with 13076 additions and 208 deletions

View file

@ -177,7 +177,7 @@ static void sr_jtdev_tdi(struct jtdev *p, int out) {
static void sr_jtdev_rst(struct jtdev *p, int out) {
UNUSED(p);
sr_gpio_write(SR_GPIO_RST, !out);
sr_gpio_write(SR_GPIO_RST, out);
}
static void sr_jtdev_tst(struct jtdev *p, int out) {

View file

@ -76,7 +76,7 @@
},
{
"cell_type": "code",
"execution_count": 75,
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
@ -99,7 +99,7 @@
},
{
"cell_type": "code",
"execution_count": 57,
"execution_count": 6,
"metadata": {},
"outputs": [
{
@ -108,7 +108,7 @@
"(129, 470)"
]
},
"execution_count": 57,
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
@ -119,7 +119,7 @@
},
{
"cell_type": "code",
"execution_count": 58,
"execution_count": 7,
"metadata": {},
"outputs": [
{
@ -128,7 +128,7 @@
"3.90625"
]
},
"execution_count": 58,
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
@ -139,21 +139,13 @@
},
{
"cell_type": "code",
"execution_count": 61,
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-61-530955947ba4>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(len(test_data), figsize=(8, 20), sharex=True)\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "30b7e529e3f94c1b8241c6b6760b7e69",
"model_id": "c7a38939cb3a42cfbfe99fe7d603e11a",
"version_major": 2,
"version_minor": 0
},
@ -182,21 +174,13 @@
},
{
"cell_type": "code",
"execution_count": 76,
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-76-31c82486a777>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(len(test_data), figsize=(8, 20), sharex=True)\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "9e0976ade81c4990a10fd1182f0f20d5",
"model_id": "e6b769f15870407ba59cff627632d447",
"version_major": 2,
"version_minor": 0
},
@ -225,7 +209,7 @@
},
{
"cell_type": "code",
"execution_count": 62,
"execution_count": 10,
"metadata": {},
"outputs": [
{
@ -255,7 +239,7 @@
" 492.1875 , 496.09375, 500. ])"
]
},
"execution_count": 62,
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@ -266,21 +250,13 @@
},
{
"cell_type": "code",
"execution_count": 63,
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-63-888d30b0f7d6>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, axs = plt.subplots(len(test_data), figsize=(8, 20), sharex=True)\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cef58f5753084c54a648418e134775d8",
"model_id": "db4021b95410428cb07f76edd932907c",
"version_major": 2,
"version_minor": 0
},
@ -388,7 +364,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.1"
"version": "3.8.2"
}
},
"nbformat": 4,

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,7 @@
"metadata": {},
"outputs": [],
"source": [
"db = sqlite3.connect('data/waveform-raspi.sqlite3')"
"db = sqlite3.connect('data/waveform-raspi-2-2.sqlite3')"
]
},
{
@ -48,7 +48,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Run 000: 2020-01-31 19:05:24 - 2020-02-01 01:13:45 ( 6:08:21.589, 22126080sp)\n"
"Run 000: 2020-03-25 16:07:36 - 2020-03-26 00:15:13 ( 8:07:37.266, 29261120sp)\n"
]
}
],
@ -100,12 +100,12 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "0b088957d9a24a74ab1b81d68099aa99",
"model_id": "582c4360e293466e9baed5bc66a47883",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(FloatProgress(value=0.0, max=691440.0), HTML(value='')))"
"HBox(children=(FloatProgress(value=0.0, max=914410.0), HTML(value='')))"
]
},
"metadata": {},
@ -133,7 +133,7 @@
" 'SELECT seq, data FROM measurements WHERE run_id = ? ORDER BY rx_ts LIMIT ? OFFSET ?',\n",
" (last_run, limit, n_records-limit))), total=n_records):\n",
" \n",
" if last_seq is None or seq == (last_seq + 1)%0xffff:\n",
" if last_seq is None or seq == (last_seq + 1)%0x10000:\n",
" last_seq = seq\n",
" idx = write_index if skip_dropped_sections else i\n",
" data[idx*record_size:(idx+1)*record_size] = np.frombuffer(chunk, dtype='<H')\n",
@ -156,7 +156,7 @@
{
"data": {
"text/plain": [
"227.68691180713367"
"227.0922848236977"
]
},
"execution_count": 7,
@ -177,7 +177,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "8a6f7e9ac8f04d1b84035c29623cfa99",
"model_id": "ecf3e3e261c54d87b169c1eb391a67f9",
"version_major": 2,
"version_minor": 0
},
@ -266,7 +266,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "a3824e732a0647d4a12e8c5a567f5dc0",
"model_id": "cc101709475d440ea77e68bcb56ce3b7",
"version_major": 2,
"version_minor": 0
},
@ -299,12 +299,12 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "342f89b5d55f435ab132deb5d051c926",
"model_id": "b0202d59643548cf83b6fa6fd7580d2d",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(FloatProgress(value=0.0, max=221260.0), HTML(value='')))"
"HBox(children=(FloatProgress(value=0.0, max=292611.0), HTML(value='')))"
]
},
"metadata": {},
@ -364,7 +364,7 @@
" #print(coeff)\n",
" A, mu, sigma, *_ = coeff\n",
" f_mean[le_t] = mu\n",
" except Exception:\n",
" except Exception as e:\n",
" f_mean[le_t] = np.nan"
]
},
@ -376,7 +376,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "33431729d479469cb89bcf86e22508ad",
"model_id": "59d50a2876634433bdfb751a7a66d9ca",
"version_major": 2,
"version_minor": 0
},
@ -420,6 +420,8 @@
"for i in np.where(np.isnan(f_mean))[0]:\n",
" ax.axvspan(f_t[i], f_t[i+1], color='lightblue')\n",
"\n",
"formatter = matplotlib.ticker.FuncFormatter(lambda s, x: str(datetime.timedelta(seconds=s)))\n",
"ax.xaxis.set_major_formatter(formatter)\n",
"ax.set_xlabel('recording time t [s]')\n",
"None"
]
@ -432,7 +434,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e8a4ecab028f4fcf8d9821dd66a42027",
"model_id": "95cfea97c3b946ed9cdf351b16c2c45e",
"version_major": 2,
"version_minor": 0
},
@ -529,13 +531,80 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 53,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-53-c54c3e4ac2be>:20: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(figsize=(5, 2))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "bcf4b384d95949c38a4754cdb47ae512",
"model_id": "ad5454f664734681adb8640f480ce69a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Text(20, 1, '50 Hz')"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Number of samplepoints\n",
"N = len(data)\n",
"# sample spacing\n",
"T = 1.0 / sampling_rate\n",
"x = np.linspace(0.0, N*T, N)\n",
"yf = scipy.fftpack.fft(data * sig.blackman(N))\n",
"xf = np.linspace(0.0, 1.0/(2.0*T), N//2)\n",
"\n",
"yf = 2.0/N * np.abs(yf[:N//2])\n",
"\n",
"average_from = lambda val, start, average_width: np.hstack([val[:start], [ np.mean(val[i:i+average_width]) for i in range(start, len(val), average_width) ]])\n",
"\n",
"average_width = 6\n",
"average_start = 20\n",
"yf = average_from(yf, average_start, average_width)\n",
"xf = average_from(xf, average_start, average_width)\n",
"yf = average_from(yf, 200, average_width)\n",
"xf = average_from(xf, 200, average_width)"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-68-21b49a5af249>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(figsize=(6, 3))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "4a3edb0925fe47eb8751150aa7da8c22",
"version_major": 2,
"version_minor": 0
},
@ -550,60 +619,48 @@
"name": "stderr",
"output_type": "stream",
"text": [
"/home/user/safety-reset/lab-windows/env/lib/python3.8/site-packages/numpy/core/_asarray.py:85: ComplexWarning: Casting complex values to real discards the imaginary part\n",
" return array(a, dtype, copy=False, order=order)\n"
"The PostScript backend does not support transparency; partially transparent artists will be rendered opaque.\n"
]
},
{
"data": {
"text/plain": [
"5.0"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data = f_copy\n",
"ys = scipy.fftpack.fft(data)\n",
"ys = scipy.fftpack.fftshift(ys)\n",
"#ys = 2.0/len(data) * np.abs(ys[:len(data)//2])\n",
"#s = 3\n",
"\n",
"#ys = np.convolve(ys, np.ones((s,))/s, mode='valid')\n",
"\n",
"#xs = np.linspace(0, 5, len(data)//2)\n",
"xs = np.linspace(-5, 5, len(data))\n",
"\n",
"#ys *= 2*np.pi*xs[s//2:-s//2+1]\n",
"#ys *= xs\n",
"\n",
"#xs = np.linspace(len(data)/2, 1, len(data)/2)\n",
"\n",
"fig, ax = plt.subplots(figsize=(9,5))\n",
"#ax.loglog(xs[s//2:-s//2+1], ys)\n",
"#ax.loglog(xs[s//2:-s//2+1], ys)\n",
"#ax.loglog(xs, ys)\n",
"#ys[len(xs)//2] = 0\n",
"#ax.set_yscale('log')\n",
"ax.plot(xs, ys)\n",
"fig, ax = plt.subplots(figsize=(6, 3))\n",
"fig.tight_layout()\n",
"ax.loglog(xf, yf)\n",
"#ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _pos: f'{1/x:.1f}'))\n",
"ax.set_xlabel('f [Hz]')\n",
"ax.set_ylabel('Amplitude V [V]')\n",
"ax.grid()\n",
"#plt.show()\n",
"xs[-1]"
"ax.set_xlim([0.1, 500])\n",
"fig.subplots_adjust(bottom=0.2)\n",
"\n",
"for le_f in (50, 150, 250, 350, 450):\n",
" ax.axvline(le_f, color=(1, 0.5, 0.5), zorder=-2)\n",
"ax.annotate('50 Hz', xy=(20, 1), xycoords='data', bbox=dict(fc='white', alpha=0.8, ec='none'))\n",
"font = {'family' : 'normal',\n",
" 'weight' : 'normal',\n",
" 'size' : 10}\n",
"matplotlib.rc('font', **font)\n",
"fig.savefig('fig_out/mains_voltage_spectrum.eps')"
]
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-43-2e31f0cb9460>:21: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots()\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cbc03380a4234b4d8160d25e867ff5a9",
"model_id": "37e159955f114f36824dd42da060b9ea",
"version_major": 2,
"version_minor": 0
},
@ -617,41 +674,49 @@
{
"data": {
"text/plain": [
"(1.6666666666666667e-05, 0.5)"
"[<matplotlib.lines.Line2D at 0x7fafc108cdc0>]"
]
},
"execution_count": 17,
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Number of samplepoints\n",
"N = len(data)\n",
"newcopy = np.copy(f_mean[1:-2])\n",
"N = len(newcopy)\n",
"# sample spacing\n",
"T = 1.0 / 10.0\n",
"T = 1.0 / 10\n",
"x = np.linspace(0.0, N*T, N)\n",
"yf = scipy.fftpack.fft(data)\n",
"xf = np.linspace(0.0, 1.0/(2.0*T), N//2)\n",
"yf = scipy.fftpack.fft(newcopy * sig.blackman(N))\n",
"xf = np.linspace(0.0, 10/2, N//2)\n",
"\n",
"yf = 2.0/N * np.abs(yf[:N//2])\n",
"\n",
"average_from = lambda val, start, average_width: np.hstack([val[:start], [ np.mean(val[i:i+average_width]) for i in range(start, len(val), average_width) ]])\n",
"\n",
"average_width = 6\n",
"average_start = 20\n",
"yf = average_from(yf, average_start, average_width)\n",
"xf = average_from(xf, average_start, average_width)\n",
"yf = average_from(yf, 200, average_width)\n",
"xf = average_from(xf, 200, average_width)\n",
"average_width1, average_start1 = 3, 40\n",
"average_width2, average_start2 = 4, 100\n",
"yf = average_from(yf, average_start1, average_width1)\n",
"xf = average_from(xf, average_start1, average_width1)\n",
"yf = average_from(yf, average_start2, average_width2)\n",
"xf = average_from(xf, average_start2, average_width2)\n",
"\n",
"fig, ax = plt.subplots()\n",
"ax.loglog(xf, yf)\n",
"ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _pos: f'{1/x:.1f}'))\n",
"ax.set_xlabel('T in s')\n",
"ax.set_ylabel('Amplitude Δf')\n",
"ax.set_xlabel('T [s]')\n",
"ax.set_ylabel('Amplitude Δf [Hz]')\n",
"\n",
"for i, t in enumerate([60, 300, 450, 1200, 1800]):\n",
" ax.axvline(1/t, color='red', alpha=0.5)\n",
" ax.annotate(f'{t} s', xy=(1/t, 3e-5), xytext=(-15, 0), xycoords='data', textcoords='offset pixels', rotation=90)\n",
"#ax.text(1/60, 10,'60 s', ha='left')\n",
"ax.grid()\n",
"ax.set_xlim([1/60000, 0.5])"
"#ax.set_xlim([1/60000, 0.5])\n",
"ax.set_ylim([5e-7, 2e-2])\n",
"ax.plot(xf[1:], 2e-6/xf[1:])"
]
},
{
@ -662,7 +727,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "8eb3621b74c04c4fb7dd3e919f0d1fed",
"model_id": "671ae919bf124e72b54144310ea1602d",
"version_major": 2,
"version_minor": 0
},
@ -672,59 +737,20 @@
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"(5e-07, 0.02)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Number of samplepoints\n",
"N = len(data)\n",
"# sample spacing\n",
"T = 1.0 / 10.0\n",
"x = np.linspace(0.0, N*T, N)\n",
"yf = scipy.fftpack.fft(data)\n",
"xf = np.linspace(0.0, 1.0/(2.0*T), N//2)\n",
"\n",
"yf = 2.0/N * np.abs(yf[:N//2])\n",
"\n",
"average_from = lambda val, start, average_width: np.hstack([val[:start], [ np.mean(val[i:i+average_width]) for i in range(start, len(val), average_width) ]])\n",
"\n",
"average_width = 6\n",
"average_start = 20\n",
"yf = average_from(yf, average_start, average_width)\n",
"xf = average_from(xf, average_start, average_width)\n",
"yf = average_from(yf, 70, 4)\n",
"xf = average_from(xf, 70, 4)\n",
"\n",
"fig, ax = plt.subplots()\n",
"ax.loglog(xf, yf)\n",
"ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _pos: f'{1/x:.1f}'))\n",
"ax.set_xlabel('T in s')\n",
"ax.set_ylabel('Amplitude Δf')\n",
"\n",
"for i, t in enumerate([45, 60, 600, 1200, 1800, 3600]):\n",
" ax.axvline(1/t, color='red', alpha=0.5)\n",
" ax.annotate(f'{t} s', xy=(1/t, 3e-5), xytext=(-15, 0), xycoords='data', textcoords='offset pixels', rotation=90)\n",
"#ax.text(1/60, 10,'60 s', ha='left')\n",
"ax.grid()\n",
"ax.set_xlim([1/60000, 0.5])\n",
"ax.set_ylim([5e-7, 2e-2])"
"ax.plot(np.linspace(0, (len(f_mean)-3)/10, len(f_mean)-3) , f_mean[1:-2])\n",
"ax.grid()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "winlabenv",
"display_name": "labenv",
"language": "python",
"name": "winlabenv"
"name": "labenv"
},
"language_info": {
"codemirror_mode": {
@ -736,7 +762,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
"version": "3.8.2"
}
},
"nbformat": 4,

View file

@ -9,9 +9,9 @@ MAKEFLAGS += --no-builtin-rules
all: safety_reset.pdf
%.pdf: %.tex %.bib
pdflatex $<
pdflatex -shell-escape $<
biber $*
pdflatex $<
pdflatex -shell-escape $<
.PHONY: clean
clean:

View file

@ -17,8 +17,10 @@
\makeatletter
\newcommand*{\@titelTitel}{Titel der Arbeit}
\newcommand{\titel}[1]{\renewcommand*{\@titelTitel}{#1}} % Titel der Arbeit
\newcommand*{\@titelTitelEN}{Titel der Arbeit (EN)}
\newcommand*{\@titelTitelDE}{Titel der Arbeit (DE)}
\newcommand{\titelen}[1]{\renewcommand*{\@titelTitelEN}{#1}} % Titel der Arbeit
\newcommand{\titelde}[1]{\renewcommand*{\@titelTitelDE}{#1}} % Titel der Arbeit
\newcommand*{\@titelArbeit}{Arbeitstyp}
\newcommand{\typ}[1]{\renewcommand*{\@titelArbeit}{#1}} % Typ der Arbeit
\newcommand*{\@titelGrad}{akademischer Grad}
@ -75,8 +77,10 @@
\begin{center}
\begin{doublespace}
\vspace{\baselineskip}
{\LARGE \textbf{\@titelTitel}}\\
%\vspace{1\baselineskip}
{\LARGE \textbf{\@titelTitelEN}}\\
\vspace{1cm}
{\large \textbf{\@titelTitelDE}}\\
\vspace{1cm}
{\Large
\@titelArbeit\\
zur Erlangung des akademischen Grades\\

View file

@ -1,3 +1,4 @@
% Encoding: UTF-8
@online{bnetza1,
author = {Bundesnetzagentur},
publisher = {Bundesnetzagentur},
@ -563,16 +564,16 @@
title = {Power System Oscillations},
year = {2000}
}
@proceedings{grebe01,
author = {E. Grebe and J. Kabouris and S. L{\'o}pez Barba and W. Sattinger and W. Winter},
doi = { 10.1109/PES.2010.5589932 {\textperiodcentered}},
journaltitle = {IEEE PES General Meeting},
month = aug,
publisher = {IEEE},
title = {Low Frequency Oscillations in the Interconnected System of Continental Europe},
year = {2010}
}
@Proceedings{grebe01,
title = {Low Frequency Oscillations in the Interconnected System of Continental Europe},
doi = {10.1109/PES.2010.5589932 {\textperiodcentered}},
publisher = {IEEE},
author = {E. Grebe and J. Kabouris and S. L{\'o}pez Barba and W. Sattinger and W. Winter},
journaltitle = {IEEE PES General Meeting},
month = aug,
year = {2010},
}
@article{mcdaniel01,
author = {McDaniel Patrick and McLaughlin Stephen},
@ -582,18 +583,17 @@
title = {Security and Privacy Challenges in the Smart Grid},
year = {2009}
}
@article{schafer01,
author = {Benjamin Sch{\"a}fer and Moritz Matthiae and Marc Timme and Dirk Witthaut},
doi = { doi:10.1088/1367-2630/17/1/015002
},
journaltitle = {New Journal of Physics},
month = jan,
publisher = {IOP/DPG},
title = {Decentral Smart Grid Control},
volume = {17},
year = {2015}
}
@Article{schafer01,
author = {Benjamin Sch{\"a}fer and Moritz Matthiae and Marc Timme and Dirk Witthaut},
journaltitle = {New Journal of Physics},
title = {Decentral Smart Grid Control},
doi = {doi:10.1088/1367-2630/17/1/015002},
volume = {17},
month = jan,
publisher = {IOP/DPG},
year = {2015},
}
@article{kosut01,
author = {Oliver Kosut and Liyan Jia and Robert J. Thomas and Lang Tong},
@ -675,4 +675,149 @@
volume = {66},
year = {2014}
}
@Article{dzung01,
author = {Dacfey Dzung and Inigo Berganza and Alberto Sendin},
date = {2011},
journaltitle = {2011 IEEE International Symposium on Power Line Communications and Its Applications},
title = {Evolution of powerline communications for smart distribution: From Ripple Control to OFDM},
doi = {10.1109/ISPLC.2011.5764444},
url = {https://www.researchgate.net/profile/Inigo_Berganza/publication/224236306_Evolution_of_powerline_communications_for_smart_distribution_From_ripple_control_to_OFDM/links/5c658800299bf1d14cc74cbd/Evolution-of-powerline-communications-for-smart-distribution-From-ripple-control-to-OFDM.pdf},
}
@WWW{hovi01,
author = {Jochen Fritz and Alexander Hovi},
date = {2020},
title = {Transkommando-System},
url = {http://www.rundsteuerung.de/entwicklung/transkommando.html},
journaltitle = {Rundsteuertechnik: Übertragung von Steuersignalen über das Energieversorgungsnetz},
}
@Book{kundur01,
author = {Kundur, Prabha and Balu, Neal J and Lauby, Mark G},
date = {1994},
title = {Power system stability and control},
publisher = {McGraw-hill New York},
volume = {7},
year = {1994},
}
@Book{goiser01,
author = {Alois M. J. Goiser},
date = {1998},
title = {Handbuch der Spread-Spectrum Technik},
isbn = {3-211-83080-4},
publisher = {Springer},
}
@TechReport{lamport02,
author = {Lamport, Leslie},
date = {19},
institution = {Technical Report CSL-98, SRI International},
title = {Constructing digital signatures from a one-way function},
year = {1979},
}
@InProceedings{buchmann01,
author = {Buchmann, Johannes and Dahmen, Erik and Ereth, Sarah and H{\"u}lsing, Andreas and R{\"u}ckert, Markus},
booktitle = {International Conference on Cryptology in Africa},
title = {On the security of the Winternitz one-time signature scheme},
organization = {Springer},
pages = {363--378},
year = {2011},
}
@InProceedings{merkle01,
author = {Merkle, Ralph C},
booktitle = {Conference on the Theory and Application of Cryptology},
title = {A certified digital signature},
organization = {Springer},
pages = {218--238},
year = {1989},
}
@InProceedings{dods01,
author = {Dods, Chris and Smart, Nigel P and Stam, Martijn},
booktitle = {IMA International Conference on Cryptography and Coding},
title = {Hash based digital signature schemes},
organization = {Springer},
pages = {96--115},
year = {2005},
}
@TechReport{gasior01,
author = {Gasior, M and Gonzalez, JL},
institution = {CERN-AB-Note-2004-021},
title = {Improving FFT frequency measurement resolution by parabolic and gaussian interpolation},
year = {2004},
}
@InProceedings{giudice01,
author = {Del Giudice, Antonio and Graditi, Giorgio and Pietrosanto, Antonio and Paciello, Vincenzo},
booktitle = {2015 IEEE International Workshop on Measurements \& Networking (M\&N)},
title = {Power quality in smart distribution grids},
organization = {IEEE},
pages = {1--6},
year = {2015},
}
@Article{virtanen01,
author = {{Virtanen}, Pauli and {Gommers}, Ralf and {Oliphant}, Travis E. and {Haberland}, Matt and {Reddy}, Tyler and {Cournapeau}, David and {Burovski}, Evgeni and {Peterson}, Pearu and {Weckesser}, Warren and {Bright}, Jonathan and {van der Walt}, St{\'e}fan J. and {Brett}, Matthew and {Wilson}, Joshua and {Jarrod Millman}, K. and {Mayorov}, Nikolay and {Nelson}, Andrew R.~J. and {Jones}, Eric and {Kern}, Robert and {Larson}, Eric and {Carey}, CJ and {Polat}, {\.I}lhan and {Feng}, Yu and {Moore}, Eric W. and {Vand erPlas}, Jake and {Laxalde}, Denis and {Perktold}, Josef and {Cimrman}, Robert and {Henriksen}, Ian and {Quintero}, E.~A. and {Harris}, Charles R and {Archibald}, Anne M. and {Ribeiro}, Ant{\^o}nio H. and {Pedregosa}, Fabian and {van Mulbregt}, Paul and {Contributors}, SciPy 1. 0},
title = {{SciPy 1.0: Fundamental Algorithms for Scientific Computing in Python}},
doi = {https://doi.org/10.1038/s41592-019-0686-2},
pages = {261--272},
volume = {17},
adsurl = {https://rdcu.be/b08Wh},
journal = {Nature Methods},
year = {2020},
}
@Article{derviskadic01,
author = {Dervi{\v{s}}kadi{\'c}, Asja and Romano, Paolo and Paolone, Mario},
title = {Iterative-interpolated DFT for synchrophasor estimation: A single algorithm for P-and M-class compliant PMUs},
number = {3},
pages = {547--558},
volume = {67},
journal = {IEEE Transactions on Instrumentation and Measurement},
publisher = {IEEE},
year = {2017},
}
@Article{narduzzi01,
author = {Narduzzi, Claudio and Bertocco, Matteo and Frigo, Guglielmo and Giorgi, Giada},
title = {Fast-TFM—Multifrequency phasor measurement for distribution networks},
number = {8},
pages = {1825--1835},
volume = {67},
journal = {IEEE Transactions on Instrumentation and Measurement},
publisher = {IEEE},
year = {2018},
}
@Article{cheshire01,
author = {Stuart Cheshire and Mary Baker},
title = {Consistent overhead Byte stuffing},
doi = {10.1109/90.769765},
number = {2},
pages = {159--172},
volume = {7},
bibsource = {dblp computer science bibliography, https://dblp.org},
biburl = {https://dblp.org/rec/journals/ton/CheshireB99.bib},
journal = {{IEEE/ACM} Trans. Netw.},
year = {1999},
}
@InProceedings{kluyver01,
author = {Thomas Kluyver and Benjamin Ragan{-}Kelley and Fernando P{\'{e}}rez and Brian E. Granger and Matthias Bussonnier and Jonathan Frederic and Kyle Kelley and Jessica B. Hamrick and Jason Grout and Sylvain Corlay and Paul Ivanov and Dami{\'{a}}n Avila and Safia Abdalla and Carol Willing and et al.},
booktitle = {Positioning and Power in Academic Publishing: Players, Agents and Agendas, 20th International Conference on Electronic Publishing, G{\"{o}}ttingen, Germany, June 7-9, 2016},
title = {Jupyter Notebooks - a publishing format for reproducible computational workflows},
doi = {10.3233/978-1-61499-649-1-87},
editor = {Fernando Loizides and Birgit Schmidt},
pages = {87--90},
publisher = {{IOS} Press},
bibsource = {dblp computer science bibliography, https://dblp.org},
biburl = {https://dblp.org/rec/conf/elpub/KluyverRPGBFKHG16.bib},
year = {2016},
}
@Comment{jabref-meta: databaseType:biblatex;}

Binary file not shown.

1
ma/safety_reset.pdf Symbolic link
View file

@ -0,0 +1 @@
/mnt/c/Users/jaseg/shared/safety_reset.pdf

View file

@ -20,8 +20,12 @@
\usepackage{multirow}
\usepackage{multicol}
\usepackage{tikz}
\usepackage{mathtools}
\DeclarePairedDelimiter{\ceil}{\lceil}{\rceil}
\DeclarePairedDelimiter{\paren}{(}{)}
\usetikzlibrary{arrows}
\usetikzlibrary{chains}
\usetikzlibrary{backgrounds}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}
@ -42,7 +46,7 @@
\usepackage[underline=false]{pgf-umlsd}
\usetikzlibrary{calc}
%\usepackage[pdftex]{graphicx,color}
%\usepackage{epstopdf}
\usepackage{epstopdf}
% Needed for murks.tex
\usepackage{setspace}
\usepackage[draft=false,babel,tracking=true,kerning=true,spacing=true]{microtype} % optischer Randausgleich etc.
@ -56,15 +60,15 @@
% Beispielhafte Nutzung der Vorlage für die Titelseite (bitte anpassen):
\input{murks}
\titel{FIXME} % Titel der Arbeit
\typ{Masterarbeit} % Typ der Arbeit: Diplomarbeit, Masterarbeit, Bachelorarbeit
\grad{Master of Science (M. Sc.)} % erreichter Akademischer Grad
% z.B.: Master of Science (M. Sc.), Master of Education (M. Ed.), Bachelor of Science (B. Sc.), Bachelor of Arts (B. A.), Diplominformatikerin
\titelen{A Post-Attack Recovery Architecture for Smart Electricity Meters}
\titelde{Eine Architektur zur Kontrollwiederherstellung nach Angriffen auf Smart Metering in Stromnetzen}
\typ{Masterarbeit}
\grad{Master of Science (M. Sc.)}
\autor{Jan Sebastian Götte}
\gebdatum{Aus datenschutzrechtlichen Gründen nicht abgedruckt} % Geburtsdatum des Autors
\gebort{Aus datenschutzrechtlichen Gründen nicht abgedruckt} % Geburtsort des Autors
\gutachter{Prof. Dr. Björn Scheuermann}{FIXME} % Erst- und Zweitgutachter der Arbeit
\mitverteidigung % entfernen, falls keine Verteidigung erfolgt
\gebdatum{Aus Datenschutzgründen nicht abgedruckt} % Geburtsdatum des Autors
\gebort{Aus Datenschutzgründen nicht abgedruckt} % Geburtsort des Autors
\gutachter{Prof. Dr. Björn Scheuermann}{Prof. Dr.-Ing. Eckhard Grass}
\mitverteidigung % entfernen, falls keine Verteidigung erfolgt %FIXME
\makeTitel
\selbstaendigkeitserklaerung{31.03.2020}
\newpage
@ -99,13 +103,13 @@ Smart meters usually are built around a standard microcontroller. \label{sm-cpu}
\section{Regulatory frameworks around the world}
\subsection{International standards}
\subsection{Regulations in Europe}
\subsection{The regulatory situation in Germany}
\subsection{The regulatory situation in France}
\subsection{The regulatory situation in the UK}
\subsection{The regulatory situation in Italy}
\subsection{The regulatory situation in northern America}
\subsection{The regulatory situation in Japan}
\subsection{The regulatory situation in selected countries}
\subsubsection{Germany}
\subsubsection{France}
\subsubsection{the UK}
\subsubsection{Italy}
\subsubsection{Northern America}
\subsubsection{Japan}
\subsection{Common themes}
\section{Security in smart grids}
@ -213,7 +217,7 @@ Communication channel attacks are attacks on the communication links between sma
attacks on IP-connected parts of the core network or attacks on shared busses between smart meters and IP gateways in
substations. Generally, these attacks can be mitigated by securing the aforementioned communication links using modern
cryptography. IP links can be protected using TLS, and more low-level busses can be protected using more lightweight
Noise-based protocols. % FIXME cite
Noise\cite{perrin01}-based protocols.
Cryptographic security transforms an attackers ability to manipulate communication contents into a mere denial of
service attack. Thus, in addition to cryptographic security safety under DoS conditions must be ensured to ensure
continued system performance under attacks. This safety property is identical with the safety required to withstand
@ -452,7 +456,7 @@ Microcontrollers have gained enormously in both performance/efficiency as well a
gains have largely been driven by insatiable customer demand for faster, more powerful chips and for a long time
security has not been considered important outside of some specific niches such as smartcards. Traditionally a
microcontroller would spend its entire lifetime without ever being exposed to any networks. Though this trend has been
reversing with the increasing adoption of internet-of-things things % FIXME is this pun ok?
reversing with the increasing adoption of internet-of-things things
and more advanced security features have started appearing in general-purpose microcontrollers, most still lack even
basic functionality found in processors for computers or smartphones.
@ -470,41 +474,528 @@ simple to reduce attack surface there.
\subsection{Safety vs. Security: Opting for restoration instead of prevention}
\subsection{Technical outline of a safety reset}
\subsection{Technical outline of a safety reset system}
\section{Communication channels on the grid}
\subsection{Powerline communication systems and their use}
There is a number of well-established technologies for communication on or along power lines. We can distinguish three
basic system categories: Systems using separate wires (such as DSL over landline telephone wiring), wireless radio
systems (such as LTE) and \emph{powerline communication} (PLC) systems that re-use the existing mains wiring and
superimpose data transmissions on the 50 Hz mains sine\cite{gungor01,kabalci01}.
For our scenario, we will ignore short-range communication systems. There exists a large number of \emph{wideband}
powerline communication systems that are popular with consumers for bridging ethernet between parts of an apartment or
house. These systems transmit at up to several hundred megabits over distances up to several tens of
meters\cite{kabalci01}. Technologically, these wideband PLC systems are very different from \emph{narrowband} systems
used by utilities for load management among other applications and they are not relevant to our analysis.
\subsection{Powerline communication (PLC) systems and their use}
In long-distance communications for applications such as load management, PLC systems are attractive since they allow
re-using the existing wiring infrastructure and have been used as early as in the 1930s\cite{hovi01}. Narrowband PLC
systems are a potentially low-cost solution to the problem of transmitting data at small bandwidth over distances of
several hundred meters up to tens of kilometers.
Narrowband PLC systems transmit on the order of kilobits per second or slower. A common use of this sort of system are
\emph{ripple control} systems. These systems superimpose a low-frequency signal at some few hundred Hertz carrier
frequency on top of the 50Hz mains sine. This low-frequency signal is used to encode switching commands for
non-essential residential or industrial loads. Ripple control systems provide utilities with the ability to actively
control demand while promising small savings in electricity cost to consumers\cite{dzung01}.
In any PLC system there is a strict tradeoff between bandwidth, power and distance. Higher bandwidth requires higher
power and reduces maximum transmission distance. Where ripple control systems usually use few transmitters to cover
the entire grid of a regional distribution utility, higher-bandwidth bidirectional systems used for automatic meter
reading (AMR) in places such as italy or france require repeaters within a few hundred meters of a transmitter.
\subsection{Landline and wireless IP-based systems}
Especially in automated meter reading (AMR) infrastructure the cost-benefit tradeoff of powerline systems does not
always work out for utilities. A common alternative in these systems is to use the public internet for communication.
Using the public internet has the advantage of low initial investment on the part of the utility company as well as
quick commissioning. Disadvantages compared to a PLC system are potentially higher operational costs due to recurring
fees to network providers as well as lower reliability. Being integrated into power grid infrastructure, a PLC system's
failure modes are highly correlated with the overall grid. Put briefly, if the PLC interface is down, there is a good
chance that power is out, too. In contrast to this general internet services exhibit a multitude of failures that are
entirely decorrelated from power grid stability.
For purposes such as meter reading for billing purposes, this stability is sufficient. However for systems that need to
hold up in crisis situations such as the recovery system we are contemplating in this thesis, the public internet may
not provide sufficient reliability.
\subsection{Proprietary wireless systems}
\subsection{Landline IP}
\subsection{IP-based wireless systems}
% FIXME
\subsection{Frequency modulation as a communication channel}
For our system, we chose grid frequency modulation (henceforth GFC) as a low-bandwidth uni-directional communications channel.
Compared to traditional PLC GFC requires no additional hardware, works reliably throughout the grid and is harder to
manipulate by a malicious actor.
% FIXME \cite{urtasun01}
For our system, we chose grid frequency modulation (henceforth GFM) as a low-bandwidth uni-directional broadcast
communications channel. Compared to traditional PLC GFM requires only a small amount of additional hardware, works
reliably throughout the grid and is harder to manipulate by a malicious actor.
Grid frequency in europe's synchronous areas is nominally 50 Hertz, but there are small load-dependent variations from
this nominal value. Any device connected to the power grid (or even just within physical proximity of power wiring) can
reliably and accurately measure grid frequency at low hardware overhead. By intentionally modifying grid frequency, we
can create a very low-bandwidth broadcast communication channel. Grid frequency modulation has only ever been proposed
as a communications channel at very small scales in microgrids before\cite{urtasun01} but to our knowledge has not yet
been considered for large-scale application.
Advantages of using grid frequency for communication are low receiver hardware complexity as well as the fact that a
single transmitter can cover an entire synchronous area. Though the transmitter has to be very large and powerful, setup
of a single large transmitter faces lower bureaucratic hurdles than integration of hundreds of smaller ones into
hundreds of local systems each with autonomous goverance.
\subsubsection{The frequency dependance of grid frequency}
% FIXME find a solid citation on this
\subsubsection{Control systems coupled to grid frequency}
\subsubsection{Avoiding dangerous modes}
Modern power systems are complex electromechanical systems. Each component is controlled by several carefully tuned
feedback loops to ensure voltage, load and frequency regulation. Multiple components are coupled through transmission
lines that themselves exhibit complex dynamic behavior. The overall system is generally stable, but may exhbit some
instabilities to particular small-signal stimuli. These instabilities, called \emph{modes} occur when due to mis-tuning
of parameters or physical constraints the overall system exhibits oscillation at particular frequencies.
\textcite{kundur01} splits these into four categories:
\begin{description}
\item[Local modes] where a single power station oscillates in some parameter
\item[Interarea modes] where subsections of the overall grid oscillate w.r.t.\ each other due to weak coupling
between them
\item[Control modes] caused by imperfectly tuned control systems
\item[Torsional modes] that originate from electromechanical oscillations in the generator itself
\end{description}
The oscillation frequencies associated with each of these modes are usually between a few tens of Millihertz and a few
Hertz, see for example \textcite{grebe01} and \textcite{entsoe01}. It is hard to predict the particular modes of a
power system at the scale of the central-european interconnected system. Theoretical analysis and simulation may give
rough indications but cannot yield conclusive results. Due to the obvious danger as well as high economical impact due
to inefficiencies experimental measurements are infeasible. Finally, modes are highly dependent on the power grid's
structure and will change with changes in the power grid over time. For all of these reasons, a grid frequency
modulation system must be designed very conservatively without relying on the absence (or presence) of modes at
particular frequencies. A concrete design guideline that we can derive from this situation is that the frequency
spectrum of any grid frequency modulation system should not exhibit any notable peaks and should avoid a concentration
of spectral energy in certain frequency ranges. On the one hand this rules out some modulation schemes. On the other
hand it provides us with a useful pointer towards those techniques that might work well: Spread-spectrum techniques. By
employing spread-spectrum modulation we can produce an almost ideal frequency-domain behavior while at the same time
achieving some modulation gain, increasing system sensitivity.
By using spread-spectrum techniques we can spread the energy of our modulation over a maximum in
bandwidth\cite{goiser01}. The coding gain spread-spectrum techniques yield potentially allows for a weaker excitation,
thereby allowing further reduction of the probability of disturbance to the overall system. Spread-spectrum techniques
also inherently allow a tradeoff between receiver sensitivity and data rate which is a highly useful parameter to have
for the overall system design.
\subsubsection{Overall system parameters}
\subsubsection{An outline of practical implementation}
\section{From grid frequency to a reliable communications channel}
\subsection{Channel properties}
\subsection{Modulation and its parameters}
\subsection{Error-correcting codes}
\subsection{Cryptographic security}
Informally the system we are looking for can be modelled as consisting of three parties: The trusted
\textsc{Transmitter}, one of a large number of untrusted \textsc{Receivers}, and an \textsc{Attacker} according to the
following rules:
\begin{enumerate}
\item \textsc{Transmitter} and \textsc{Attacker} can both transmit any bit sequence
\item \textsc{Receiver} receives any transmission by either \textsc{Transmitter} or \textsc{Attacker} but cannot
distinguish between the two on the signal level
\item \textsc{Attacker} knows anything a \textsc{Receiver} might know
\item \textsc{Transmitter} is stronger than \textsc{Attacker} and will ``win'' in simultaneous transmission
\item Both \textsc{Transmitter} and \textsc{Receiver} can be seeded with some information on each other such as
public key fingerprints.
\end{enumerate}
We are not interested in congestion scenarios where an attacker attempts to disrupt an ongoing transmission by the
transmitter. In practice there are several avenues to prevent such attempts including the following. Compromised loads
that are being abused by the attacker can be manually disconnected by the utility. Error-correcting codes can be used to
provide resiliency against small-scale disturbances. Finally, the transmitter can be designed to have high enough power
to be able to override any likely attacker.
Our goal is to find a cryptographic primitive that has the following properties:
\begin{enumerate}
\item \textsc{Transmitter} can produce a transmission bit sequence $\mathbf{s}$ (or equivalently a set of such
sequences) that \textsc{Receiver} can uniquely identify as being generated by \textsc{Transmitter}:
$\mathcal{R}\left(\mathbf{s}\right) = 1$. Upon reception of this sequence, \textsc{Receiver} performs the safety
reset.
\item \textsc{Attacker} cannot forge $\mathbf{s}$, that is find $\mathbf{s}'$ such that
$\mathbf{s} \neq \mathbf{s}' \land \mathcal{R}\left(\mathbf{s}'\right) = 1$
\item Our system conforms to an at-most-once semantic. That is, upon transmission of a valid bit sequence coded for
a particular \textsc{Receiver} or set of receivers each one either performs exactly one safety reset or none at
all. We cannot achieve an exactly-once semantic since we are using an unidirectional lossy communication
primitive. More coloquially, \textsc{Receiver} might be offline due to a localized power outage and might thus
not hear \textsc{Transmitter} even if our broadcast primitive is reliable. The practical impact of this
limitation can be mitigated by transmitter simply repeating itself until the desired effect has been achieved.
\end{enumerate}
An important limitation from the rules of our setup above is that \textsc{Attacker} can always record the bit sequence
\textsc{Transmitter} transmits and replay that same sequence later. Before considering any cryptographic approaches we
can make the preliminary observation that we can trivially prevent \textsc{Attacker} from violating the
at-most-once criterion by simply requiring \textsc{Receiver} to memorize all bit sequences that have been transmitted
thus far and only reacting to new bit sequences. This means an attacker might be able to cause offline receivers to
reset at a later point, but considering our goal is to reset them in the first place this would not pose a danger to the
system.
% FIXME elaborate why this is not a threat, and possible mitigations
As it seems we need a cryptographic primitive that looks somewhat like a signature. Different from a signature however,
we have somewhat relaxed constraints here: While cryptographic signatures need to work over arbitrary inputs, all we
want to ``sign'' here is the instruction to perform a safety reset. Since this is the only message we might ever want to
transmit, our message space has only one entry and thus the informational content of our message is 0 bit! All the
information we want to transmit is already encoded \emph{in the fact that we are transmitting}, and we do not require
any further payload to be transmitted. This means we can omit the entirety of the message and just transmit whatever
``signature'' we produce. This is useful since we have to conserve transmission bits so our transmissions do not take
exceeedingly long time over our extremely slow communication channel.
We could use any of several traditional asymmetric cryptographic primitives to produce these signatures. The
comparatively high computational effort required for signature verification would not be an issue. Transmissions take
several minutes anyway and we can afford to spend some tens of seconds even in signature verification. Transmission
length and by proxy system latency would be determined by the length of the signature. For RSA signature length is the
modulus length (i.e. larger than 1000 bit for even basic contemporary security). For elliptic curve-based systems
signature size is approximately twice the curve length (i.e. ~300 bit for contemporary security). However, we can do
better than this: We can exploit the strange nature of our setting that our effective message entropy is 0 bit to derive
a more efficient scheme.
\subsubsection{Lamport signatures}
In 1979, \textcite{lamport02} introduced a signature scheme that is based only on a one-way function such as a
cryptographic hash function. The basic observation is that by choosing a random secret input to a one-way function and
publishing the output, one can later prove knowledge of the input by simply publishing it. In the following paragraphs
we will describe a construction of a one-time signature scheme based on this observation. The scheme we describe is the
one usually called a ``Lamport Signature'' in modern literature and is slightly different from the variant described in
the 1979 paper, but for our purposes we can consider both to be equivalent.
\paragraph{Setup.} In a Lamport signature, for an n-bit hash function $H$ the signer generates a private key $s =
\left(s_{b, i} | b\in\left\{0, 1\right\}, 0\le i<n\right)$ of $2n$ random strings of length $n$. The signer publishes a
public key $p = \left(p_{b, i} = H\left(s_{b, i}\right), b\in\left\{0, 1\right\}, 0\le i<n\right)$ that is simply the
list of hashes of each of the random strings that make up the private key.
\paragraph{Signing.} To sign a message $m$, the signer publishes the signature $\sigma = \left(\sigma_i = k_{H(m)_i,
i}\right)$ where $H(m)_i$ is the $i$-th bit of $H$ applied to $m$. That is, for the $i$-th bit of the message's hash
$H(m)$ the signer publishes either of $p_{0, i}$ or $p_{1, i}$ depending on the hash bit's value, keeping the other
entry of $P$ secret.
\paragraph{Verification.} The verifier can compute $H(m)$ themselves and check the corresponding entries $\sigma_i =
k_{H(m)_i}$ of $S$ correctly evaluate to $p_{b, i} = H\left(s_{b, i}\right)$ from $P$ under $H$.
The above scheme is a one-time signature scheme only. After one signature has been published for a given key, the
corresponding key must not be re-used for other signatures. This is intutively clear as we are effectively publishing
part of the private key as the signature, and if we were to publish a signature for another message an attacker could
derive additional signatures by ``mixing'' the two published signatures.
\subsubsection{Winternitz Signatures}
An improvement to basic Lamport signatures as described above are Winternitz signatures as detailed in
\textcite{merkle01} and \textcite{dods01}. Winternitz signatures reduce public key length as well as signature length
for hash length $n$ from $2n$ to $\mathcal O \left(n/t\right)$ for some choice of parameter $t$ (usually a small number
such as 4).
\paragraph{Setup.} The signer generates a private key $s = \left(s_i\right)$ consisting of $\ceil{\frac{n}{t}}$ random
bit strings. The signer publishes a public key $p = \left(H^{2^t}\left(s_i\right)\right)$ where each element
$H^{2^t}\left(s_i\right)$ is the $2^t$-fold recursive application of $H$ to $s_i$.
\paragraph{Signing.} The signer splits $m$ padded to a multiple of $t$ bits into $\ceil{\frac{n}{t}}$ chunks $m_i$ of
$t$ bit each. The signer publishes the signature $\sigma = \left( \sigma_i = H^{m_i}\left(s_i\right) \right)$.
\paragraph{Verification.} The verifier can calculate for each $\sigma_i = H^{m_i}\left(s_i\right)$ that $H^{2^t -
m_i}\left(\sigma_i\right) = H^{2^t - m_i}\left(H^{m_i}\left(s_i\right)\right) = H^{2^t - m_i + m_i} \left(s_i\right) =
p_i$.
To prevent an attacker from forging additional signatures from one signature by calculating $\sigma_i' =
H\left(\sigma_i\right)$ matching $m_i' = m_i + 1$, this scheme is usually paired with a simple checksum as described in
\textcite{merkle01}.
\subsubsection{Using hash-based signatures for trigger authentication}
The most basic possible trigger authentication scheme would be to simply generate a random bit string secret key $s$ and
publish $p = H(s)$ for some hash function $H$. To activate the trigger, $\sigma = s$ would be published and listeners
could verify that $H(\sigma) = p = H(s)$. This simplistic scheme has one main disadvantage: It is a fundamentally
one-time construction. To prevent an attacker from re-triggering a listener a second time by replaying a valid trigger
$\sigma$ all listeners have to blacklist any ``used'' $\sigma$. Alas, this means we can only ever trigger a listener
\emph{once}. The good part is that any listener that missed this trigger can still be triggered later, but the bad part
is that once $s$ is burned we are out of options. The trivial solution to this would be to simply inform each listener
with a whole list of public keys in advance. This however takes $n$ times the amount of space for $n$-fold
retriggerability. Luckily we can easily derive a scheme that yields $n$-fold retriggerability while using no more same
space than the original scheme by taking some inspiration from Winternitz signatures above.
In this scheme the secret key $s$ is still a random bit string. The public key is $p = H^n(s)$ for n-times
retriggerability. The $i$-th time the trigger is activated, $\sigma_i = H^n-i(s)$ is published, and every listener can
verify that $\sigma_{i-1} = H\left(\sigma_i\right)$ with $\sigma_0 = p$. In case a listener missed one or more previous
triggers it can simply continue computing $H\left(H\left(\sigma_i\right)\right)$ and
$H\left(H\left(H\left(\sigma_i\right)\right)\right)$ until either reaching the $n$-th recursion level (indicating an
invalid signature) or finding $H^n\left(\sigma_i\right) = \sigma_j$ with $sigma_j$ being the last signature this
listener recorded, or $p$ in case there is none.
This scheme provides replay protection through listeners memorizing the last signature they activated to. Public key
length is equal to the length of the hash function $H$ used. Even for our embedded systems use case $n$ can
realistically be up to $\mathcal O\left(10^3\right)$, which is easily enough for our application.
% FIXME here and in previous ~2 pages get transmitter/receiver and sender/listener terminology straight. Also perhaps do
% some sort of scenario definition introducing those terms somewhere.
\chapter{Practical implementation}
\section{Cryptographic validation}
\section{Data collection for channel validation}
To design a solid system we needed to parametrize mains frequency variations under normal conditions. To set modulation
amplitude as well as parameters of our modulation scheme we need a frequency spectrum of mains frequency variations
(that is $\mathcal F\left(f(V(t))\right)$: Taking mains frequency $f(x)$ as a variable, the frequency spectrum of that
variable, as opposed to the frequency spectrum of mains voltage $V(t)$ itself).
\subsection{Grid Frequency Estimation}
\label{frequency_estimation}
In commercial power systems Phasor Measurement Units (PMUs) are used to precisely measure parameters of a mains voltage
waveform. One of the parameters PMUs measure is mains frequency. PMUs are used as part of SCADA systems controlling
transmission networks to characterize the operational state of the network.
From a superficial viewpoint measuring mains frequency might seem like a simple problem. Take the mains voltage
waveform, measure time between two rising-edge (or falling-edge) zero-crossings and take the inverse $f = t^{-1}$. In
practice, phasor measurement units are significantly more complex than this. This discrepancy is due to the unhealthy
% FIXME is this pun ok?
combination of both high precision and quick response that is demanded from these units. High precision is necessary
since variations of mains frequency under normal operating conditions are quite small--in the range of $5-10 \text{mHz}$
over short intervals of time. Relative to the nominal $50 \text{Hz}$ this is a derivation of less than $100 \text{ppm}$.
Relative to the corresponding $20 \text{ms}$ period that means a time derivation of about $2 \mu\text{s}$ from cycle to
cycle. From this it is already obvious why a simplistic measurement cannot yield the required precision for manageable
averaging times--we would need either a ADC sampling rate in the order of megabits or for a reconstruction through
interpolated readings an impractically high ADC resolution.
Detail on the inner workings of commercial phasor measurement units is scarce but given their essential role to SCADA
systems there is a large amount of academic research on such algorithms\cite{narduzzi01,derviskadic01}. A popular
approach to these systems is to perform a Short-Time Fourier Transform (STFT) on ADC data sampled at high sampling rate
(e.g. $10 \text{kHz}$) and then perform some analysis on the frequency-domain data to precisely locate the strong peak
around $50 \text{Hz}$. A key observation here is that FFT bin size is going to be much larger than required frequency
resolution. This fundamental limitiation follows from the nyquist criterion %FIXME maybe cite? and if we had to process
an \emph{arbitrary} signal this would highly limit our practical measurement accuracy
\footnote{
Some software packages providing FFT or STFT primitives such as scipy\cite{virtanen01} allow the user to
super-sample FFT output by specifying an FFT width larger than input data length, padding the input data with zeros
on both sides. Note that in line with Nyquist this \emph{does not} actually provide finer output resolution but
instead just amounts to an interpolation between output bins. Depending on the downstream analysis algorithm it may
still be sensible to use this property of the DFT for interpolation, but in general it will be computationally
expensive compared to other interpolation methods and in any case it will not yield any better frequency resolution
aside from a hypothetical numerical advantage\cite{gasior01}.
}.
For this reason all approaches to mains frequency estimation are based on a model of the mains voltage waveform.
Nominally, this waveform would be a perfect sine at $f = 50 \text{Hz}$. In practice it is a sine at $f \approx 50
\text{Hz}$ superimposed with some aperiodic noise (e.g. irregular spikes from inductive loads being energized) as well
as harmonic distortion that is caused by grid-topologically nearby devices with power factor
\footnote{
Power factor is a power engineering term that is used to describe how close the current waveform of a load is to
that of a purely resistive load. Given sinusoidal input voltage $V(t) = V_\text{pk} \sin \paren{\omega_\text{nom}
t}$ with $\omega_\text{nom} = 2 \pi f_\text{nom} = 2 \pi \cdot 50 \text{Hz}$ being the nominal angular frequency,
the current waveform of a resistor with resistance $R \left[\Omega\right]$ according to Ohm's law would be $I(t) =
\frac{V(t)}{R} = \frac{1}{R} V_\text{pk} \sin\paren{\omega_\text{nom} t}$. In this case voltage and current are
perfectly in phase, i.e. the current at time $t$ is linear in voltage at constant factor $\frac{1}{R}$.
In contrast to this idealized scenario reality provides us with two common issues: One, the load may be reactive.
This means its current waveform is an ideal sinusoid, but there is a phase difference between mains voltage and load
current like so: $I(t) = \frac{V(t)}{R} = \frac{1}{\left|Z\right|} V_\text{pk} \sin\paren{\omega_\text{nom} t +
\varphi}$ $Z$ would be the load's complex impedance combining inductive, capacitive and resistive components and
$\varphi$ the phase difference between the resulting current waveform and the mains voltage waveform. A common case
of such loads are motors and the inductive ballasts in old fluorescent lighting fixtures.
The second potential issue are loads with non-sinusoidal current waveform. There are many classes of these but the
most common one are switching-mode power supplies. Most SMPS for modern electronic devices have an input stage
consisting of a bridge rectifier followed by a capacitor that provide high-voltage DC power to the following
switch-mode convert circuit. This rectifier-capacitor input stage under normal load draws a high current only at the
very peak of the input voltage sinusoid and draws almost zero current for most of the period.
These two cases are measured by \emph{displacement power factor} and \emph{distortion power factor} that when
combined yield the overall true power factor. The power factor is a key quantity in the design and operation of the
power grid since a high power factor (close to $1.0$ or an in-phase sinusoidal current waveform) yields lowest
transmission and generation losses.
}
$\cos \theta \neq 1.0$. Under a continous fourier transform over a long period the frequency spectrum of a signal
distorted like this will be a low noise floor depending mainly on aperiodic noise on which a comb of harmonics as well
as some sub-harmonics of $f \approx f_\text{nom} = 50Hz$ rides. The main peak at $f \approx f_\text{nom}$ will be very
strong with the harmonics being approximately an order of magnitude weaker in energy and the noise floor being at least
another order of magnitude weaker. See figure \ref{mains_voltage_spectrum} for a measured spectrum. This domain
knowledge about the expected frequency spectrum of the signal can be employed in a number of interpolation techniques to
re-construct the precise frequency of the spectrum's main component despite comparatively coarse STFT resolution and
despite numerous distortions.
\begin{figure}
\centering
\includegraphics{../lab-windows/fig_out/mains_voltage_spectrum}
\caption{Fourier transform of an 8 hour capture of mains voltage. Data was captured using our frequency measurement
sensor described in section \ref{sec-fsensor} and FFT'ed after applying a blackman window. Vertical lines indicate
$50 \text{Hz}$ and odd harmonics.}
\label{mains_voltage_spectrum}
\end{figure}
Published grid frequency estimation algorithms such as \textcite{narduzzi01} or \textcite{derviskadic01} are rather
sophisticated and use a combination of techniques to reduce numerical errors in FFT calculation and peak fitting. Given
that we do not need reference standard-grade accuracy for our application we chose to start with a very basic algorithm
instead. We chose to use a general approach developed by experimental physicists at CERN that is described by
\textcite{gasior01}. This approach assumes a general sinusoidal signal superimposed with harmonics and broadband noise.
Applicable to a wide spectrum of practical signal analysis tasks it is a reasonable first-degree approximation of the
much more sophisticated estimation algorithms developed specifically for power systems. Some algorithms have components
such as kalman filters\cite{narduzzi01} that require a phyiscal model. As a general algorithm from \textcite{gasior01}
does not require this kind of application-specific tuning, eliminating one source of error.
\subsection{Frequency sensor hardware design}
\label{sec-fsensor}
Our safety reset controller % FIXME is this the right term?
will have to measure mains frequency to later demodulate a reset signal transmitted through it. Since we have decided to
do our own frequency measurement system here we can use this frequency measurement setup as a prototype for the
frequency measurement subcomponent of the demodulation system we will later develop. Since we do not plan to do a
large-scale field deployment of our measurement setup we can keep the hardware implementation simple by moving most of
the signal processing to a regular computer and concentrating our hardware efforts on raw signal capture.
\begin{figure}
\begin{center}
\begin{tikzpicture}[start chain = going below, node distance = 12mm and 50mm, every join/.style = {norm}]
\tikzset{
base/.style = {draw, on chain, on grid, align=center, minimum height = 4ex, font=\footnotesize},
text/.style = {base},
component/.style = {base, rectangle, text width=40mm},
coord/.style = {coordinate, on chain, on grid, node distance=6mm and 25mm}
}
\node[text centered] (input) {Single-Phase Mains Input};
\node[component] (safety) [below = of input] {Input Protection};
\node[coord] (safety-anchor) [below = of safety] {};
\node[component] (analog) [below = of safety-anchor] {Analog Signal Processing};
\node[component] (powersupply) [left = of analog] {Power supply};
\node[component] (adc) [below = of analog] {ADC};
\node[component] (micro) [below = of adc] {Microcontroller};
\node[component] (isol) [below = of micro] {Galvanic Digital Isolation};
\node[coord] (isol-left) [left = 6cm of isol.west] {};
\node[coord] (isol-right) [right = 1cm of isol.east] {};
\node[component] (usb) [below = of isol] {USB interface};
\draw[->] (input.south) -- (safety.north);
\draw[-] (safety.south) -- (safety-anchor);
\draw[->] (safety-anchor) -| (powersupply.north);
\draw[->] (safety-anchor) -| (analog.north);
\draw[->] (powersupply.south) |- (adc.west);
\draw[->] (powersupply.south) |- (micro.west);
\draw[->] (analog.south) -- (adc.north);
\draw[->] (adc.south) -- (micro.north);
\draw[->] (micro.south) -- (isol.north);
\draw[->] (isol.south) -- (usb.north);
\draw[dashed] (isol.west) -- (isol-left.east);
\draw[dashed] (isol.east) -- (isol-right.west);
\end{tikzpicture}
\end{center}
\caption{Frequency sensor hardware diagram}
\label{fmeas-sens-diag}
\end{figure}
An overall block diagram of our system is shown in fig. \ref{fmeas-sens-diag}. The mircrocontroller we chose is an
\texttt{STM32F030F4P6} ARM Cortex-M0 microcontroller made by ST Microelectronics. The ADC in fig. \ref{fmeas-sens-diag}
in our design is the integrated 12-bit ADC of this microcontroller, which is sufficient for our purposes. The USB
interface is a simple USB to serial converter IC (\texttt{CH340G}) and the galvanic digital isolation is accomplished
with a pair of high-speed optocouplers on its \texttt{RX} and \texttt{TX} lines. The analog signal processing is a
simple voltage divider using high-power resistors to get the required creepage along with some high-frequency filter
capacitors and an op-amp buffer. The power supply is an off-the-shelf mains-input power module. The system is
implemented on a single two-layer PCB that is housed in an off-the-shelf industrial plastic case fitted with a printed
label and a few status lights on its front.
\subsection{Clock accuracy considerations}
Our measurement hardware will sample line voltage at some sampling rate $f_S$, e.g.\ $1 \text{kHz}$. All downstream
processsing is limited in accuracy by the accuracy of $f_S$\footnote{
We are not considering the effects of clock jitter. We are highly oversampling the signal and the FFT done in our
downstream processing will eliminate small jitter effects leaving only frequency stability to worry about. }. We
generate our sampling clock in hardware by clocking the ADC from one of the microcontroller's timer blocks clocked from
the microcontroller's system clock. This means our ADC's sampling window will be synchronized cycle-accurate to the
microcontroller's system clock.
Our downstream measurement of mains frequency by nature is relative to our sampling frequency $f_S$. In the setup
described above this means we have to make sure our system clock is fairly stable. A frequency derivation of $1
\text{ppm}$ in our system clock causes a proportional grid frequency measurement error of $\Delta f = f_\text{nom} \cdot
10^{-6} = 50 \mu\text{Hz}$. In a worst-case where our system is clocked from a particularly bad crystal that exhibits
$100 \text{ppm}$ of instabilities over our measurement period we end up with an error of $5 \text{mHz}$. This is well
within our target measurement range, so we need a more stable clock source. Ideally we want to avoid writing our own
clock conditioning code where we try to change an oscillators operating frequency to match some reference. Clock
conditioning algorithms are highly complex and in our case post-processing of measurement data and simply adding and
offset is simpler and less error-prone.
Our solution to these problems is to use a crystal oven\footnote{
A crystal oven is a crystal oscillator thermally coupled closely to a heater and temperature sensor and enclosed in
a thermally isolated case. The heater is controlled to hold the crystal oscillator at a near-constant temperature
some few ten degrees above ambient. Any ambient temperature variations will be absorbed by the temperature control.
This yields a crystal frequency that is almost completely unaffected by ambient temperature variations below the
oven temperature and whose main remaining instability is aging.
}as our main system clock source. Crystal ovens are expensive compared to ordinary crystal oscillators. Since any
crystal oven will be much more accurate than a standard room-temperature crystal we chose to reduce cost by using one
recycled from old telecommunications equipment.
To verify clock accuracy we routed an externally accessible SMA connector to a microcontroller pin that is routed to one
of the microcontroller's timer inputs. By connecting a GPS 1pps signal to this pin and measuring its period we can
calculate our system's Allan variance\footnote{
Allan variance is a measure of frequency stability between two clocks.
}, thereby measuring both clock stability and clock accuracy.
We ran a 4 hour test of our frequency sensor that generated the histogram shown in figure \ref{ocxo_freq_stability}.
These results show that while we get a systematic error of about $10 \text{ppm}$ due to manufacturing tolerances the
random error at less than $10 \text{ppb}$ is smaller than that of a room-temperature crystal oscillator by 3-4 orders of
magnitude. Since we are interested in grid frequency variations over time but not in the absolute value of grid
frequency the systematic error is of no consequence to us. The random error at $3.66 \text{ppb}$ corresponds to a
frequency measurement error of about $0.2 \mu\text{Hz}$, well below what we can achieve at reasonable sampling rates and
ADC resolution.
\begin{figure}
\centering
\includegraphics{../lab-windows/fig_out/ocxo_freq_stability}
\caption{OCXO Frequency derivation from nominal $19.440 \text{MHz}$ measured against GPS 1pps}
\label{ocxo_freq_stability}
\end{figure}
\subsection{Firmware implementation}
The firmware uses one of the microcontroller's timers clocked from an external crystal oscillator to produce an $1
\text{ms}$ tick that the internal ADC is triggered from for a sample rate of $1 \text{ksps}$. Higher sample rates would
be possible but reliable data transmission over the opto-isolated serial interface might prove challenging and $1
\text{ksps}$ corresponds to $20$ samples per cycle at $f_\text{nominal}$. This is $10\times$ nyquist and should be
plenty for accurate measurements.
The ADC measurements are read using DMA and written into a circular buffer. Using some DMA controller features this
circular buffer is split in back and front halves with one being written to and the other being read at the same time.
Buffer contents are moved from the ADC DMA buffer into a packet-based reliable UART interface as they come in. The UART
packet interface keeps two ringbuffers: One byte-based ringbuffer for transmission data and one ringbuffer pointer
structure that keeps track of ADC data packet boundaries in the byte-based ringbuffer. Every time a chunk of data is
available from the ADC the data is framed into the byte-based ringbuffer and the packet boundaries are logged in the
packet pointer ringbuffer. If the UART transmitter is idle at this time a DMA-backed transmission of the oldest packet
in the packet ringbuffer is triggered at this point. Data is framed using Consistent Overhead Byte Stuffing
(COBS)\footnote{
COBS is a framing technique that allows encoding $n$ bytes of arbitray data into exactly $n+1$ bytes with no embedded
$0$-bytes that can then be delimited using $0$-bytes. COBS is simple to implement and allows both one-pass decoding and
encoding. The encoder either needs to be able to read up to $256 \text{bytes}$ ahead or needs a buffer of $256
\text{bytes}$. COBS is very robust in that it allows self-synchronization. At any point a receiver can reliably
synchronize itself against a COBS data stream by waiting for the next $0$-byte. The constant overhead allows precise
bandwidth and buffer planning and provides constant, good efficiency close to the theoretical maximum.
}\cite{cheshire01} along with a CRC-32 checksum for error checking. When the host receives a new packet with a
valid checksum it returns an acknowledgement packet to the sensor. When the sensor receives the acknowledgement, the
acknowledged packet is dropped from the transmission packet ringbuffer. When the host detects an incorrect checksum it
simply stays quiet and waits for the sensor to resume with retransmission when the next ADC buffer has been received.
% FIXME make actual error rate measurements
The serial interface logic presents most of the complexity of the sensor firmware. This complexity is necessary since
we need reliable, error-checked transmission to the host. Though rare, bit errors on a serial interface do happen and
data corruption is unacceptable. The packet-layer queueing on the sensor is necessary since the host is not a realtime
system and unpredictable latency spikes of several hundred milliseconds are possible.
The host in our recording setup is a Raspberry Pi 3 model B running a Python script. The Python script handles serial
communication and logs data and errors into an SQLite database file. SQLite has been chosen for its simple yet flexible
interface and its good tolerance of system resets due to unexpected power loss.
\subsection{Frequency sensor measurement results}
Captured raw waveform data is processed in the Jupyter Lab environment\cite{kluyver01} and grid frequency estimates are
extracted as described in sec. \ref{frequency_estimation} using the \textcite{gasior01} technique.
% FIXME comparison against reference measurements?
\section{Channel simulation and parameter validation}
\section{Implementation of a demonstrator unit}
\section{Experimental results}