From cba83e780a9350eb45eb1c2f09fc87f5d389e1ac Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 20 May 2018 15:54:03 +0200 Subject: Move documentation and simulation stuff to its own subdir --- firmware/Spectrum Measurement.ipynb | 3667 ----------------------------------- 1 file changed, 3667 deletions(-) delete mode 100644 firmware/Spectrum Measurement.ipynb (limited to 'firmware/Spectrum Measurement.ipynb') diff --git a/firmware/Spectrum Measurement.ipynb b/firmware/Spectrum Measurement.ipynb deleted file mode 100644 index 516321b..0000000 --- a/firmware/Spectrum Measurement.ipynb +++ /dev/null @@ -1,3667 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import sqlite3\n", - "import time\n", - "from IPython import display\n", - "from datetime import datetime\n", - "import scipy.interpolate as inter\n", - "from scipy import integrate\n", - "\n", - "import numpy as np\n", - "from matplotlib import pyplot as plt\n", - "%matplotlib notebook" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "db = sqlite3.connect('spectra.sqlite3')" - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def load_run(capture_id, gain, zero_cal=False):\n", - " if zero_cal:\n", - " data = db.execute('SELECT a.step, a.voltage, a.voltage_stdev, b.voltage, b.voltage_stdev '\n", - " 'FROM measurements a JOIN measurements b USING (step) '\n", - " 'WHERE a.capture_id = ?1 AND a.led_on = 1 AND b.capture_id = ?1 AND b.led_on = 0 '\n", - " 'ORDER BY step ASC', (capture_id,)).fetchall()\n", - " steps, voltages, voltage_stdevs, zero_voltages, zero_stdevs = map(np.array, zip(*data))\n", - " else:\n", - " data = db.execute('SELECT step, voltage, voltage_stdev '\n", - " 'FROM measurements '\n", - " 'WHERE capture_id = ? AND led_on = 1 '\n", - " 'ORDER BY step ASC', (capture_id,)).fetchall()\n", - " steps, voltages, voltage_stdevs = map(np.array, zip(*data))\n", - " zero_voltages = zero_stdevs = np.zeros(len(steps))\n", - " \n", - " return (steps,\n", - " (voltages-zero_voltages)/gain*1e9, # nanoamps\n", - " np.sqrt(np.square(voltage_stdevs) + np.square(zero_stdevs))/gain*1e9) #nanoamps" - ] - }, - { - "cell_type": "code", - "execution_count": 94, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def find_captures(name):\n", - " # Get the newest capture for each color\n", - " captures = db.execute(\n", - " 'SELECT capture_id, color, gain FROM runs WHERE (name, color, timestamp) IN '\n", - " '(SELECT name, color, MAX(timestamp) FROM runs '\n", - " 'WHERE name=? GROUP BY color ORDER BY timestamp)', (name,)).fetchall()\n", - " \n", - " if not captures:\n", - " raise ValueError('Run not found')\n", - " return captures" - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def live_plot(name,\n", - " spline_s=1, interval=1,\n", - " live=True, save_svg=None):\n", - " captures = find_captures(name)\n", - " \n", - " fig, ax = plt.subplots(1, 1)\n", - " \n", - " colors = {\n", - "\n", - " }\n", - " \n", - " while True:\n", - " ax.clear()\n", - " ax.spines['top'].set_visible(False)\n", - " ax.spines['right'].set_visible(False)\n", - " ax.spines['bottom'].set_color('#08bdf9')\n", - " ax.spines['left'].set_color('#08bdf9')\n", - " ax.tick_params(axis='x', colors='#01769D')\n", - " ax.tick_params(axis='y', colors='#01769D')\n", - " ax.xaxis.label.set_color('#01769D')\n", - " ax.yaxis.label.set_color('#01769D')\n", - " ax.set_xlabel('$x\\;[step]$')\n", - " ax.set_ylabel('$I_{pd}\\;[nA]$')\n", - " ax.grid(color='#08bdf9', linestyle=':')\n", - " \n", - " for capture_id, color, gain in captures:\n", - " color_dark, color_bright = colors.get(color, ('#fe3ea0', '#ffd2e9'))\n", - " steps, values, stdev = load_run(capture_id, gain)\n", - " \n", - " ax.errorbar(steps, values, yerr=stdev, color=color_bright, zorder=1)\n", - " try:\n", - " spline = inter.UnivariateSpline(steps, values, s=spline_s)\n", - " ax.plot(steps, spline(steps), color=color_dark, zorder=2)\n", - " except:\n", - " pass\n", - " fig.canvas.draw()\n", - " if save_svg:\n", - " fig.savefig(save_svg)\n", - " if save_svg or not live:\n", - " break\n", - " time.sleep(1)" - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support.' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('
');\n", - " this._root_extra_style(this.root)\n", - " this.root.attr('style', 'display: inline-block');\n", - "\n", - " $(parent_element).append(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", - " fig.send_message(\"send_image_mode\", {});\n", - " if (mpl.ratio != 1) {\n", - " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", - " }\n", - " fig.send_message(\"refresh\", {});\n", - " }\n", - "\n", - " this.imageObj.onload = function() {\n", - " if (fig.image_mode == 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function() {\n", - " this.ws.close();\n", - " }\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "}\n", - "\n", - "mpl.figure.prototype._init_header = function() {\n", - " var titlebar = $(\n", - " '
');\n", - " var titletext = $(\n", - " '
');\n", - " titlebar.append(titletext)\n", - " this.root.append(titlebar);\n", - " this.header = titletext[0];\n", - "}\n", - "\n", - "\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._init_canvas = function() {\n", - " var fig = this;\n", - "\n", - " var canvas_div = $('
');\n", - "\n", - " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", - "\n", - " function canvas_keyboard_event(event) {\n", - " return fig.key_event(event, event['data']);\n", - " }\n", - "\n", - " canvas_div.keydown('key_press', canvas_keyboard_event);\n", - " canvas_div.keyup('key_release', canvas_keyboard_event);\n", - " this.canvas_div = canvas_div\n", - " this._canvas_extra_style(canvas_div)\n", - " this.root.append(canvas_div);\n", - "\n", - " var canvas = $('');\n", - " canvas.addClass('mpl-canvas');\n", - " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", - "\n", - " this.canvas = canvas[0];\n", - " this.context = canvas[0].getContext(\"2d\");\n", - "\n", - " var backingStore = this.context.backingStorePixelRatio ||\n", - "\tthis.context.webkitBackingStorePixelRatio ||\n", - "\tthis.context.mozBackingStorePixelRatio ||\n", - "\tthis.context.msBackingStorePixelRatio ||\n", - "\tthis.context.oBackingStorePixelRatio ||\n", - "\tthis.context.backingStorePixelRatio || 1;\n", - "\n", - " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband = $('');\n", - " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", - "\n", - " var pass_mouse_events = true;\n", - "\n", - " canvas_div.resizable({\n", - " start: function(event, ui) {\n", - " pass_mouse_events = false;\n", - " },\n", - " resize: function(event, ui) {\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " stop: function(event, ui) {\n", - " pass_mouse_events = true;\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " });\n", - "\n", - " function mouse_event_fn(event) {\n", - " if (pass_mouse_events)\n", - " return fig.mouse_event(event, event['data']);\n", - " }\n", - "\n", - " rubberband.mousedown('button_press', mouse_event_fn);\n", - " rubberband.mouseup('button_release', mouse_event_fn);\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband.mousemove('motion_notify', mouse_event_fn);\n", - "\n", - " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", - " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", - "\n", - " canvas_div.on(\"wheel\", function (event) {\n", - " event = event.originalEvent;\n", - " event['data'] = 'scroll'\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " mouse_event_fn(event);\n", - " });\n", - "\n", - " canvas_div.append(canvas);\n", - " canvas_div.append(rubberband);\n", - "\n", - " this.rubberband = rubberband;\n", - " this.rubberband_canvas = rubberband[0];\n", - " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", - " this.rubberband_context.strokeStyle = \"#000000\";\n", - "\n", - " this._resize_canvas = function(width, height) {\n", - " // Keep the size of the canvas, canvas container, and rubber band\n", - " // canvas in synch.\n", - " canvas_div.css('width', width)\n", - " canvas_div.css('height', height)\n", - "\n", - " canvas.attr('width', width * mpl.ratio);\n", - " canvas.attr('height', height * mpl.ratio);\n", - " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", - "\n", - " rubberband.attr('width', width);\n", - " rubberband.attr('height', height);\n", - " }\n", - "\n", - " // Set the figure to an initial 600x600px, this will subsequently be updated\n", - " // upon first draw.\n", - " this._resize_canvas(600, 600);\n", - "\n", - " // Disable right mouse context menu.\n", - " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", - " return false;\n", - " });\n", - "\n", - " function set_focus () {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "}\n", - "\n", - "mpl.figure.prototype._init_toolbar = function() {\n", - " var fig = this;\n", - "\n", - " var nav_element = $('
')\n", - " nav_element.attr('style', 'width: 100%');\n", - " this.root.append(nav_element);\n", - "\n", - " // Define a callback function for later on.\n", - " function toolbar_event(event) {\n", - " return fig.toolbar_button_onclick(event['data']);\n", - " }\n", - " function toolbar_mouse_event(event) {\n", - " return fig.toolbar_button_onmouseover(event['data']);\n", - " }\n", - "\n", - " for(var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " // put a spacer in here.\n", - " continue;\n", - " }\n", - " var button = $('');\n", - " button.click(method_name, toolbar_event);\n", - " button.mouseover(tooltip, toolbar_mouse_event);\n", - " nav_element.append(button);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = $('');\n", - " nav_element.append(status_bar);\n", - " this.message = status_bar[0];\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = $('
');\n", - " var button = $('');\n", - " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", - " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", - " buttongrp.append(button);\n", - " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", - " titlebar.prepend(buttongrp);\n", - "}\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(el){\n", - " var fig = this\n", - " el.on(\"remove\", function(){\n", - "\tfig.close_ws(fig, {});\n", - " });\n", - "}\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(el){\n", - " // this is important to make the div 'focusable\n", - " el.attr('tabindex', 0)\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " }\n", - " else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._key_event_extra = function(event, name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager)\n", - " manager = IPython.keyboard_manager;\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which == 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "ids = (45, 46, 44)\n", - "bands = [(260,410), (150,330), (100,260)]\n", - "poly_degree = 2\n", - "max_stdev = 1.0\n", - "remove_thresh = 0.05\n", - "\n", - "data_rgb = []\n", - "for run_id, (l, r) in zip(ids, bands):\n", - " steps, values, stdev = load_run_zero_cal(run_id, max_stdev)\n", - " \n", - " idxs = (np.abs(stdev[1:-1] - stdev[0:-2]) < remove_thresh) |\\\n", - " (np.abs(stdev[1:-1] - stdev[2:]) < remove_thresh)\n", - " idxs = np.hstack([np.array([True]), idxs, np.array([True])])\n", - " steps, values, stdev = steps[idxs], values[idxs], stdev[idxs]\n", - " \n", - " idxs = (steps < l) | (steps > r)\n", - " poly = np.poly1d(np.polyfit(steps[idxs], values[idxs], poly_degree))\n", - " print('Poly for run {}: {}'.format(run_id, str(poly).strip()))\n", - " \n", - " values -= poly(steps)\n", - " data_rgb.append((steps, values, stdev))\n", - "\n", - "plot_rgb_foo(data_rgb, ids, spline_s=0.05)" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def plot_rgb_calibrated(data_rgb, spline_s=1, save_svg=None):\n", - " fig, ax = plt.subplots(1, 1)\n", - "\n", - " for steps, values, stdev in data_rgb:\n", - " ax.errorbar(steps, values, yerr=stdev, color='#ffd2e9', zorder=1)\n", - " \n", - " spline = inter.UnivariateSpline(steps, values, s=spline_s)\n", - " ax.plot(steps, spline(steps), color='#fe3ea0', zorder=2)\n", - " \n", - " ax.spines['top'].set_visible(False)\n", - " ax.spines['right'].set_visible(False)\n", - " ax.spines['bottom'].set_color('#08bdf9')\n", - " ax.spines['left'].set_color('#08bdf9')\n", - " ax.tick_params(axis='x', colors='#01769D')\n", - " ax.tick_params(axis='y', colors='#01769D')\n", - " ax.xaxis.label.set_color('#01769D')\n", - " ax.yaxis.label.set_color('#01769D')\n", - " ax.grid(color='#08bdf9', linestyle=':')\n", - " \n", - " ax.set_xlim([380, 720])\n", - " ax.set_xlabel('$\\lambda\\;[nm]$')\n", - " ax.set_ylabel('$I_{pd}\\;[nA]$')\n", - " \n", - " if save_svg:\n", - " fig.savefig(save_svg)" - ] - }, - { - "cell_type": "code", - "execution_count": 127, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support.' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('
');\n", - " this._root_extra_style(this.root)\n", - " this.root.attr('style', 'display: inline-block');\n", - "\n", - " $(parent_element).append(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", - " fig.send_message(\"send_image_mode\", {});\n", - " if (mpl.ratio != 1) {\n", - " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", - " }\n", - " fig.send_message(\"refresh\", {});\n", - " }\n", - "\n", - " this.imageObj.onload = function() {\n", - " if (fig.image_mode == 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function() {\n", - " this.ws.close();\n", - " }\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "}\n", - "\n", - "mpl.figure.prototype._init_header = function() {\n", - " var titlebar = $(\n", - " '
');\n", - " var titletext = $(\n", - " '
');\n", - " titlebar.append(titletext)\n", - " this.root.append(titlebar);\n", - " this.header = titletext[0];\n", - "}\n", - "\n", - "\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._init_canvas = function() {\n", - " var fig = this;\n", - "\n", - " var canvas_div = $('
');\n", - "\n", - " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", - "\n", - " function canvas_keyboard_event(event) {\n", - " return fig.key_event(event, event['data']);\n", - " }\n", - "\n", - " canvas_div.keydown('key_press', canvas_keyboard_event);\n", - " canvas_div.keyup('key_release', canvas_keyboard_event);\n", - " this.canvas_div = canvas_div\n", - " this._canvas_extra_style(canvas_div)\n", - " this.root.append(canvas_div);\n", - "\n", - " var canvas = $('');\n", - " canvas.addClass('mpl-canvas');\n", - " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", - "\n", - " this.canvas = canvas[0];\n", - " this.context = canvas[0].getContext(\"2d\");\n", - "\n", - " var backingStore = this.context.backingStorePixelRatio ||\n", - "\tthis.context.webkitBackingStorePixelRatio ||\n", - "\tthis.context.mozBackingStorePixelRatio ||\n", - "\tthis.context.msBackingStorePixelRatio ||\n", - "\tthis.context.oBackingStorePixelRatio ||\n", - "\tthis.context.backingStorePixelRatio || 1;\n", - "\n", - " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband = $('');\n", - " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", - "\n", - " var pass_mouse_events = true;\n", - "\n", - " canvas_div.resizable({\n", - " start: function(event, ui) {\n", - " pass_mouse_events = false;\n", - " },\n", - " resize: function(event, ui) {\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " stop: function(event, ui) {\n", - " pass_mouse_events = true;\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " });\n", - "\n", - " function mouse_event_fn(event) {\n", - " if (pass_mouse_events)\n", - " return fig.mouse_event(event, event['data']);\n", - " }\n", - "\n", - " rubberband.mousedown('button_press', mouse_event_fn);\n", - " rubberband.mouseup('button_release', mouse_event_fn);\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband.mousemove('motion_notify', mouse_event_fn);\n", - "\n", - " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", - " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", - "\n", - " canvas_div.on(\"wheel\", function (event) {\n", - " event = event.originalEvent;\n", - " event['data'] = 'scroll'\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " mouse_event_fn(event);\n", - " });\n", - "\n", - " canvas_div.append(canvas);\n", - " canvas_div.append(rubberband);\n", - "\n", - " this.rubberband = rubberband;\n", - " this.rubberband_canvas = rubberband[0];\n", - " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", - " this.rubberband_context.strokeStyle = \"#000000\";\n", - "\n", - " this._resize_canvas = function(width, height) {\n", - " // Keep the size of the canvas, canvas container, and rubber band\n", - " // canvas in synch.\n", - " canvas_div.css('width', width)\n", - " canvas_div.css('height', height)\n", - "\n", - " canvas.attr('width', width * mpl.ratio);\n", - " canvas.attr('height', height * mpl.ratio);\n", - " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", - "\n", - " rubberband.attr('width', width);\n", - " rubberband.attr('height', height);\n", - " }\n", - "\n", - " // Set the figure to an initial 600x600px, this will subsequently be updated\n", - " // upon first draw.\n", - " this._resize_canvas(600, 600);\n", - "\n", - " // Disable right mouse context menu.\n", - " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", - " return false;\n", - " });\n", - "\n", - " function set_focus () {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "}\n", - "\n", - "mpl.figure.prototype._init_toolbar = function() {\n", - " var fig = this;\n", - "\n", - " var nav_element = $('
')\n", - " nav_element.attr('style', 'width: 100%');\n", - " this.root.append(nav_element);\n", - "\n", - " // Define a callback function for later on.\n", - " function toolbar_event(event) {\n", - " return fig.toolbar_button_onclick(event['data']);\n", - " }\n", - " function toolbar_mouse_event(event) {\n", - " return fig.toolbar_button_onmouseover(event['data']);\n", - " }\n", - "\n", - " for(var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " // put a spacer in here.\n", - " continue;\n", - " }\n", - " var button = $('');\n", - " button.click(method_name, toolbar_event);\n", - " button.mouseover(tooltip, toolbar_mouse_event);\n", - " nav_element.append(button);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = $('');\n", - " nav_element.append(status_bar);\n", - " this.message = status_bar[0];\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = $('
');\n", - " var button = $('');\n", - " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", - " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", - " buttongrp.append(button);\n", - " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", - " titlebar.prepend(buttongrp);\n", - "}\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(el){\n", - " var fig = this\n", - " el.on(\"remove\", function(){\n", - "\tfig.close_ws(fig, {});\n", - " });\n", - "}\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(el){\n", - " // this is important to make the div 'focusable\n", - " el.attr('tabindex', 0)\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " }\n", - " else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._key_event_extra = function(event, name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager)\n", - " manager = IPython.keyboard_manager;\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which == 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "}\n", - "\n", - "mpl.figure.prototype.handle_save = function(fig, msg) {\n", - " fig.ondownload(fig, null);\n", - "}\n", - "\n", - "\n", - "mpl.find_output_cell = function(html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] == html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel != null) {\n", - " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", - "}\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "captures = find_captures('cheap_rgb')\n", - "\n", - "# Approximate bands of interest for R, G and B channelsfor offset and stray light correction.\n", - "bands = {\n", - " 'red': (260,410), # [step]\n", - " 'green': (150,330),\n", - " 'blue': (100,260)\n", - "}\n", - "\n", - "# The wavelengths are from a random RGB LED datasheet and are just preliminary starting values.\n", - "# https://www.sparkfun.com/datasheets/Components/YSL-R596CR3G4B5C-C10.pdf\n", - "λ_led = {'red': 623, 'green': 518, 'blue': 466} # [nm] Assumed wavelengths of R, G and B spectral peaks.\n", - "λ_be = 400 # [nm] Approximate short-λ edge of blue band\n", - "y_edge_min = 0.5\n", - "transimpedance = 630e6 # Ohms.\n", - "\n", - "poly_degree = 1 # degree of polynomial for stray light and offset correction. Should be 1 or 2.\n", - "\n", - "#remove_thresh = 10.0 # [V] standard deviation delta threshold for outlier removal\n", - "\n", - "# ---\n", - "data_rgb = {}\n", - "for capture_id, color, gain in captures:\n", - " # Load this channel from the database\n", - " steps, values, stdev = load_run(capture_id, gain)\n", - " \n", - " # Remove outlier values whose standard deviation is much larger than that of their right and left neighbors\n", - " #idxs = (np.abs(stdev[1:-1] - stdev[0:-2]) < remove_thresh) |\\\n", - " # (np.abs(stdev[1:-1] - stdev[2:]) < remove_thresh)\n", - " #idxs = np.hstack([np.array([True]), idxs, np.array([True])])\n", - " #steps, values, stdev = steps[idxs], values[idxs], stdev[idxs]\n", - " \n", - " # Remove offset and stray light by fitting a second-order polynomial over the parts of the curve\n", - " # that are clearly *not* part of the primary peak.\n", - " l, r = bands[color]\n", - " idxs = (steps < l) | (steps > r)\n", - " poly = np.poly1d(np.polyfit(steps[idxs], values[idxs], poly_degree))\n", - " print('Poly for', color, 'channel')\n", - " print(poly)\n", - " values -= poly(steps)\n", - " \n", - " data_rgb[color] = (steps, values, stdev)\n", - "\n", - "\n", - "# Produce a first estimate for wavelength scaling. Use the short-wavelength edge of the blue band and the red peak\n", - "# for this, as both can be assumed to remain stable even after photodiode response compensation. Then apply photodiode\n", - "# response compensation and do another, second round of wavelength scaling estimation but this time using all three\n", - "# peaks and a proper least-squares fit.\n", - "peaks = { color: x[np.argmax(y)] for color, (x, y, σ2) in data_rgb.items() }\n", - "edgesl = { color: x[np.argmax(y > y_edge_min)] for color, (x, y, σ2) in data_rgb.items() }\n", - "\n", - "Λ_est = np.poly1d(np.polyfit([edgesl['blue'], peaks['red']], [λ_be, λ_led['red']], 1))\n", - "\n", - "data_tmp = { color: (x, Λ_est(x), y, σ2) for color, (x, y, σ2) in data_rgb.items() }\n", - "data_tmp = { color: (x, λ, y/Λ_sfh2701(λ), σ2) for color, (x, λ, y, σ2) in data_tmp.items() }\n", - "# Limit wavelength range\n", - "data_tmp = { color: (x[λ > 380], λ[λ > 380], y[λ > 380], σ2[λ > 380]) for color, (x, λ, y, σ2) in data_tmp.items() }\n", - "\n", - "# Calibrate wavelength axis using assumed peaks for r, g and b. Use least-squares polyfit for getting coefficients.\n", - "peaks = { color: x[np.argmax(y)] for color, (x, λ, y, σ2) in data_tmp.items() }\n", - "Λ = np.poly1d(np.polyfit(\n", - " [peaks['red'], peaks['green'], peaks['blue']],\n", - " [λ_led['red'], λ_led['green'], λ_led['blue']], 1))\n", - "\n", - "data_rgb = { color: (Λ(x), y, σ2) for color, (x, y, σ2) in data_rgb.items() }\n", - "data_rgb = { color: (λ, y/Λ_sfh2701(λ), σ2) for color, (λ, y, σ2) in data_rgb.items() }\n", - "\n", - "# Limit wavelength range to slightly-larger-than visible range. We're getting improbably large values in the\n", - "# utraviolet region that are probably caused by stray light.\n", - "data_rgb = { color: (λ[λ > 380], y[λ > 380], σ2[λ > 380]) for color, (λ, y, σ2) in data_rgb.items() }\n", - "\n", - "# Normalize amplitude data to brightest channel for ease of reading\n", - "#max_val = max(np.max(y) for λ, y, σ2 in data_rgb)\n", - "#data_rgb = [ (λ, y/max_val, σ2/max_val) for λ, y, σ2 in data_rgb ]\n", - "\n", - "# Convert amplitude data to current in nanoampère\n", - "data_rgb = { color: (λ, y/transimpedance / 1e-9, σ2/transimpedance / 1e-9) for color, (λ, y, σ2) in data_rgb.items() }\n", - "\n", - "plot_rgb_calibrated(data_rgb.values(), spline_s=0.005, save_svg='/tmp/processed_plot_cheap_rgb.svg')" - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# CIE XYZ Color matching functions from http://cvrl.ioo.ucl.ac.uk/\n", - "# rows are: λ[nm], x, y, z\n", - "CMFs = { fn[:-4]: np.genfromtxt(fn, delimiter=',')\n", - " for fn in ['cie_xyz_1931.csv', 'cie_xyz_judd_1951.csv', 'cie_xyz_judd_vos_1978.csv'] }\n", - "CMFs = { name: np.hstack([inter.interp1d(d[:,0], d[:,i]) for i in range(1,4)])\n", - " for name, d in CMFs.items() }" - ] - }, - { - "cell_type": "code", - "execution_count": 119, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def integrate_tristimulus_response(data, channels=('red', 'green', 'blue'), colorspace='cie_xyz_1931'):\n", - " a = np.array([[\n", - " integrate.simps(\n", - " np.multiply(CMFs[colorspace][j](data[color][0]), data[color][1]), data[color][0])\n", - " for j in range(3) ]\n", - " for color in channels ])\n", - " # normalize by largest component\n", - " return a / np.max(np.sum(a, axis=0))" - ] - }, - { - "cell_type": "code", - "execution_count": 120, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 0.06995882, 0.02007191, -0.0260505 ],\n", - " [ 0.05310356, 0.0995779 , 0.03458726],\n", - " [ 0.16122952, 0.16639874, 0.99146324]])" - ] - }, - "execution_count": 120, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tristimulus_data = integrate_tristimulus_response(data_rgb)\n", - "tristimulus_data\n", - "#array([[ 3.46142003e-01, 1.73335974e-01, -7.18827590e-05],\n", - "# [ 9.01721797e-02, 1.69512416e-01, 2.15830281e-02],\n", - "# [ 1.75128165e-01, 2.49230694e-01, 9.78488855e-01]])" - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def led_setpoint_from_xyz(x, y, z):\n", - " # returns [r, g, b] array.\n", - " # Note that many xyz tristimulus values cannot be produced because one component is outside [0, 1]\n", - " #return np.linalg.solve(tristimulus_data.T, np.array([x, y, z]))\n", - " return np.dot(np.linalg.inv(tristimulus_data.T), np.array([x, y, z]))" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 2.96363627, 1.00231926, 0.24462504])" - ] - }, - "execution_count": 122, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "led_setpoint_from_xyz(0.3, 0.2, 0.2)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.5" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} -- cgit