From 4c8cf48c913f763bdb216d88c505958e9eb17a76 Mon Sep 17 00:00:00 2001 From: jaseg Date: Fri, 18 May 2018 11:02:17 +0200 Subject: Add one more RGB spectrum run --- firmware/Spectrum Measurement.ipynb | 3642 ++--------------------------------- firmware/measure_spectrum.py | 12 +- firmware/spectra.sqlite3 | Bin 12288 -> 98304 bytes 3 files changed, 195 insertions(+), 3459 deletions(-) (limited to 'firmware') diff --git a/firmware/Spectrum Measurement.ipynb b/firmware/Spectrum Measurement.ipynb index 66818a9..516321b 100644 --- a/firmware/Spectrum Measurement.ipynb +++ b/firmware/Spectrum Measurement.ipynb @@ -33,3368 +33,109 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 71, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def load_run(run_id):\n", - " data = db.execute('SELECT step, voltage, voltage_stdev FROM measurements WHERE run_id = ? AND led_on = 1 ORDER BY step ASC', (run_id,)).fetchall()\n", - " return zip(*data)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def load_run_zero_cal(run_id, max_stdev=1e10):\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.run_id = ?1 AND a.led_on = 1 AND b.run_id = ?1 AND b.led_on = 0 '\n", - " 'AND a.voltage_stdev < ?2 AND b.voltage_stdev < ?2'\n", - " 'ORDER BY step ASC', (run_id, max_stdev)).fetchall()\n", - " steps, voltages, voltage_stdevs, zero_voltages, zero_stdevs = map(np.array, zip(*data))\n", - " return steps, voltages-zero_voltages, np.sqrt(np.square(voltage_stdevs) + np.square(zero_stdevs))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def plot_rgb(id_r, id_g, id_b, loader=load_run):\n", - " fig, ax = plt.subplots(1, 1)\n", - " fig.suptitle('Runs {}, {}, {} at {:%y-%m-%d %H:%M:%S}'.format(id_r, id_g, id_b, datetime.now()))\n", - " for run_id, color in [(id_g, 'green'), (id_r, 'red'), (id_b, 'blue')]:\n", - " steps, values, stdev = loader(run_id)\n", - " ax.errorbar(steps, values, yerr=stdev, color=color)\n", - " #ax.set_ylim([2.2, 5])\n", - " #plt.close(fig)\n", - " #return fig" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "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": [ - "#live_plot_rgb_splines(14, 15, 13, live=False, show_title=False)\n", - "live_plot_rgb_splines(45, 46, 44, spline_s=0.08, max_stdev=1.0, live=False, show_title=False, save_svg='/tmp/raw_plot_cheap_rgb.svg')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* Go further than step 250 to capture some zeros beyond the red band to allow the spline fitter to do its job more properly\n", - "* Move the entire screen further down and further increase range to properly capture blue rolloff\n", - "* Decrease amplification to avoid clipping. Maybe change amplification midway for green channel. Currenlty set to 5GOhm using 10M transimp feedback R with 1:10 T feedback and ~1:50 gain voltage amp stage. Maybe go back to plain transimp amp with 10M gain, for a total gain of 500M\n", - "* Decrease VGND bias to allow for more headroom" - ] - }, - { - "cell_type": "code", - "execution_count": 118, - "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" - } - ], + "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": [ - "live_plot_rgb_splines(45, 46, 44, spline_s=0.08, max_stdev=1.0, live=False)" + "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": 120, - "metadata": {}, + "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": { @@ -4176,7 +917,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -4187,7 +928,17 @@ } ], "source": [ - "live_plot_rgb_splines(51, 54, 55, 61, spline_s=0.05, max_stdev=1.0, live=False)" + "live_plot('cheap_rgb', spline_s=0.001, live=False, save_svg='/tmp/raw_plot_cheap_rgb.svg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Go further than step 250 to capture some zeros beyond the red band to allow the spline fitter to do its job more properly\n", + "* Move the entire screen further down and further increase range to properly capture blue rolloff\n", + "* Decrease amplification to avoid clipping. Maybe change amplification midway for green channel. Currenlty set to 5GOhm using 10M transimp feedback R with 1:10 T feedback and ~1:50 gain voltage amp stage. Maybe go back to plain transimp amp with 10M gain, for a total gain of 500M\n", + "* Decrease VGND bias to allow for more headroom" ] }, { @@ -5049,32 +1800,20 @@ }, { "cell_type": "code", - "execution_count": 166, + "execution_count": 97, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def plot_rgb_bar(data_rgb, ids_rgb, spline_s=1, show_label=True, save_svg=None):\n", + "def plot_rgb_calibrated(data_rgb, spline_s=1, save_svg=None):\n", " fig, ax = plt.subplots(1, 1)\n", - " if show_label:\n", - " fig.suptitle('Runs {}(R), {}(G), {}(B) at {:%y-%m-%d %H:%M:%S}'.format(*ids_rgb, datetime.now()))\n", - "\n", - " #colors = [\n", - " # ((1,0,0), (1,0.8,0.8)),\n", - " # ((0,1,0), (0.8,1,0.8)),\n", - " # ((0,0,1), (0.8,0.8,1))\n", - " #]\n", - " colors = [\n", - " (('#fe3ea0', '#ffd2e9')) #ff99cc\n", - " ] * 4\n", - " print('spline_s', spline_s)\n", "\n", - " for (steps, values, stdev), (color_dark, color_bright) in zip(data_rgb, colors):\n", - " ax.errorbar(steps, values, yerr=stdev, color=color_bright, zorder=1)\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=color_dark, zorder=2)\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", @@ -5096,7 +1835,7 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 127, "metadata": {}, "outputs": [ { @@ -5879,7 +2618,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -5887,16 +2626,6 @@ }, "metadata": {}, "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "(380, 720)" - ] - }, - "execution_count": 124, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ @@ -5905,13 +2634,28 @@ "Λ_sfh2701 = np.poly1d(np.polyfit(λ_sfh2701, S_sfh2701, 5))\n", "r = np.arange(380, 720)\n", "fig, ax = plt.subplots(1, 1)\n", - "ax.plot(r, Λ_sfh2701(r))\n", - "ax.set_xlim([380, 720])" + "ax.plot(r, Λ_sfh2701(r), color='#fe3ea0')\n", + "ax.set_xlim([380, 720])\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('$S_{rel,820nm}\\;[1]$')\n", + "fig.savefig('/tmp/photodiode_sensitivity.svg')" ] }, { "cell_type": "code", - "execution_count": 168, + "execution_count": 112, "metadata": { "scrolled": false }, @@ -5920,16 +2664,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "Poly for run 45:\n", - " 2\n", - "2.282e-06 x - 0.001576 x + 0.4019\n", - "Poly for run 46:\n", - " 2\n", - "6.886e-07 x - 0.0005388 x + 0.1561\n", - "Poly for run 44:\n", - " 2\n", - "1.258e-06 x - 0.001514 x + 0.5252\n", - "[297, 228, 117] [339, 270, 210]\n" + "Poly for red channel\n", + " \n", + "-0.0001301 x + 0.4955\n", + "Poly for green channel\n", + " \n", + "-3.846e-05 x + 0.4401\n", + "Poly for blue channel\n", + " \n", + "-0.000189 x + 0.5092\n" ] }, { @@ -6712,7 +3455,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -6720,96 +3463,93 @@ }, "metadata": {}, "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "spline_s 0.5\n" - ] } ], "source": [ - "ids = (45, 46, 44) # Run IDs of runs for R, G and B channel\n", + "captures = find_captures('cheap_rgb')\n", "\n", "# Approximate bands of interest for R, G and B channelsfor offset and stray light correction.\n", - "bands = [(260,410), (150,330), (100,260)] # [step]\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 = [623, 518, 466] # [nm] Assumed wavelengths of R, G and B spectral peaks.\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 = 2 # degree of polynomial for stray light and offset correction. Should be 1 or 2.\n", - "\n", - "max_stdev = 1.0 # [V] Nerved value that has been used for outlier removal in earlier tries\n", + "poly_degree = 1 # degree of polynomial for stray light and offset correction. Should be 1 or 2.\n", "\n", - "remove_thresh = 0.05 # [V] standard deviation delta threshold for outlier removal\n", + "#remove_thresh = 10.0 # [V] standard deviation delta threshold for outlier removal\n", "\n", "# ---\n", - "data_rgb = []\n", - "for run_id, (l, r) in zip(ids, bands):\n", + "data_rgb = {}\n", + "for capture_id, color, gain in captures:\n", " # Load this channel from the database\n", - " steps, values, stdev = load_run_zero_cal(run_id, max_stdev)\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", + " #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 run {}:'.format(run_id))\n", + " print('Poly for', color, 'channel')\n", " print(poly)\n", " values -= poly(steps)\n", " \n", - " data_rgb.append((steps, values, stdev))\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 = [ x[np.argmax(y)] for x, y, σ2 in data_rgb ]\n", - "edgesl = [ x[np.argmax(y > y_edge_min)] for x, y, σ2 in data_rgb ]\n", - "print(edgesl, peaks)\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[2], peaks[0]], [λ_be, λ_led[0]], 1))\n", + "Λ_est = np.poly1d(np.polyfit([edgesl['blue'], peaks['red']], [λ_be, λ_led['red']], 1))\n", "\n", - "data_tmp = [ (x, Λ_est(x), y, σ2) for x, y, σ2 in data_rgb ]\n", - "data_tmp = [ (x, λ, y/Λ_sfh2701(λ), σ2) for x, λ, y, σ2 in data_tmp ]\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 = [ (x[λ > 380], λ[λ > 380], y[λ > 380], σ2[λ > 380]) for x, λ, y, σ2 in data_tmp ]\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 = [ x[np.argmax(y)] for x, λ, y, σ2 in data_tmp ]\n", - "Λ = np.poly1d(np.polyfit(peaks, λ_led, 1))\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 = [ (Λ(x), y, σ2) for x, y, σ2 in data_rgb ]\n", - "data_rgb = [ (λ, y/Λ_sfh2701(λ), σ2) for λ, y, σ2 in data_rgb ]\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 = [ (λ[λ > 380], y[λ > 380], σ2[λ > 380]) for λ, y, σ2 in data_rgb ]\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 = [ (λ, y/transimpedance / 1e-9, σ2/transimpedance / 1e-9) for λ, y, σ2 in data_rgb ]\n", + "data_rgb = { color: (λ, y/transimpedance / 1e-9, σ2/transimpedance / 1e-9) for color, (λ, y, σ2) in data_rgb.items() }\n", "\n", - "plot_rgb_bar(data_rgb, ids, spline_s=0.5, show_label=False, save_svg='/tmp/processed_plot_cheap_rgb.svg')" + "plot_rgb_calibrated(data_rgb.values(), spline_s=0.005, save_svg='/tmp/processed_plot_cheap_rgb.svg')" ] }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 114, "metadata": { "collapsed": true }, @@ -6825,49 +3565,51 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 119, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def integrate_tristimulus_response(data, colorspace='cie_xyz_1931'):\n", + "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[i][0]), data[i][1]),\n", - " data[i][0])\n", + " np.multiply(CMFs[colorspace][j](data[color][0]), data[color][1]), data[color][0])\n", " for j in range(3) ]\n", - " for i in range(len(data)) ])\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": 60, + "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "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]])" + "array([[ 0.06995882, 0.02007191, -0.0260505 ],\n", + " [ 0.05310356, 0.0995779 , 0.03458726],\n", + " [ 0.16122952, 0.16639874, 0.99146324]])" ] }, - "execution_count": 60, + "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tristimulus_data = integrate_tristimulus_response(data_rgb)\n", - "tristimulus_data" + "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": 61, + "execution_count": 121, "metadata": { "collapsed": true }, @@ -6882,16 +3624,16 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([ 0.72869072, 0.1386238 , 0.20139265])" + "array([ 2.96363627, 1.00231926, 0.24462504])" ] }, - "execution_count": 62, + "execution_count": 122, "metadata": {}, "output_type": "execute_result" } diff --git a/firmware/measure_spectrum.py b/firmware/measure_spectrum.py index 47df7b3..70f4e9b 100644 --- a/firmware/measure_spectrum.py +++ b/firmware/measure_spectrum.py @@ -77,19 +77,13 @@ if __name__ == '__main__': bp = BPState(args.port) - run_name = args.run_name - if not str.isnumeric(args.run_name[-1]): - names = [ n[len(run_name):] for n, in db.execute( - 'SELECT name FROM runs WHERE name LIKE ?||"%"', (run_name,)).fetchall() ] - names.append('0') # in case we get no results - run_name += str(1+max(int(n) if str.isnumeric(n) else 0 for n in names)) with db: cur = db.cursor() cur.execute('INSERT INTO runs(name, comment, color, gain, timestamp) VALUES (?, ?, ?, ?, ?)', - (run_name, args.comment, args.color, args.gain*1e6, time.time())) + (args.run_name, args.comment, args.color, args.gain*1e6, time.time())) capture_id = cur.lastrowid - print('Starting run {} "{}" at {:%y-%m-%d %H:%M:%S:%f}'.format(capture_id, run_name, datetime.now())) + print('Starting capture {} "{}" at {:%y-%m-%d %H:%M:%S:%f}'.format(capture_id, args.run_name, datetime.now())) print('[measurement id] " " [step number] " " [reading (V)]') bp.stepper_direction('down') @@ -98,7 +92,7 @@ if __name__ == '__main__': bp.stepper_direction('up') for step in range(0, args.steps+args.skip, args.skip): # Run one skip past end to capture both interval boundaries - for led_val in [0, 1]: + for led_val in [1]: # This can be used for self-calibration. try: bp.led(led_val) time.sleep(args.wait) diff --git a/firmware/spectra.sqlite3 b/firmware/spectra.sqlite3 index fe9be41..00fa710 100644 Binary files a/firmware/spectra.sqlite3 and b/firmware/spectra.sqlite3 differ -- cgit