diff --git a/firmware/Spectrum Measurement.ipynb b/firmware/Spectrum Measurement.ipynb index c77709a..66818a9 100644 --- a/firmware/Spectrum Measurement.ipynb +++ b/firmware/Spectrum Measurement.ipynb @@ -2,9 +2,9 @@ "cells": [ { "cell_type": "code", - "execution_count": 277, + "execution_count": 6, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -22,9 +22,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -33,9 +33,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 8, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -46,7 +46,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 9, "metadata": { "collapsed": true }, @@ -64,9 +64,9 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -83,10 +83,8 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, + "execution_count": 11, + "metadata": {}, "outputs": [ { "data": { @@ -94,6 +92,7 @@ "/* 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", @@ -152,6 +151,9 @@ " 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", @@ -221,6 +223,15 @@ " 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", @@ -277,8 +288,9 @@ " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\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", @@ -411,10 +423,10 @@ "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", - " var x0 = msg['x0'];\n", - " var y0 = fig.canvas.height - msg['y0'];\n", - " var x1 = msg['x1'];\n", - " var y1 = fig.canvas.height - msg['y1'];\n", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", @@ -570,8 +582,8 @@ " this.canvas_div.focus();\n", " }\n", "\n", - " var x = canvas_pos.x;\n", - " var y = canvas_pos.y;\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", @@ -692,6 +704,7 @@ "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", @@ -700,7 +713,7 @@ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", - " $(fig.parent_element).html('');\n", + " $(fig.parent_element).html('');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", @@ -711,8 +724,9 @@ "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] = '';\n", + " this.cell_info[1]['text/html'] = '';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", @@ -801,12 +815,9 @@ " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\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", @@ -855,7 +866,7 @@ { "data": { "text/html": [ - "" + "
" ], "text/plain": [ "" @@ -863,6 +874,19 @@ }, "metadata": {}, "output_type": "display_data" + }, + { + "ename": "OperationalError", + "evalue": "no such column: run_id", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOperationalError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mplot_rgb\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m12\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mplot_rgb\u001b[0;34m(id_r, id_g, id_b, loader)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msuptitle\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Runs {}, {}, {} at {:%y-%m-%d %H:%M:%S}'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mid_r\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid_g\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid_b\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdatetime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrun_id\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcolor\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mid_g\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'green'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mid_r\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'red'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mid_b\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'blue'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0msteps\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstdev\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mloader\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrun_id\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0max\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merrorbar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msteps\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0myerr\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstdev\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcolor\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcolor\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;31m#ax.set_ylim([2.2, 5])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mload_run\u001b[0;34m(run_id)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mload_run\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrun_id\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'SELECT step, voltage, voltage_stdev FROM measurements WHERE run_id = ? AND led_on = 1 ORDER BY step ASC'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mrun_id\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfetchall\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mOperationalError\u001b[0m: no such column: run_id" + ] } ], "source": [ @@ -871,9 +895,9 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -892,842 +916,74 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": { - "collapsed": false + "collapsed": true }, - "outputs": [ - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\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", - " 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 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);\n", - " canvas.attr('height', height);\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(51, 54, 55, 61, spline_s=0.05, max_stdev=1.0, live=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 121, "metadata": { "collapsed": true }, @@ -4124,10 +4216,8 @@ }, { "cell_type": "code", - "execution_count": 171, - "metadata": { - "collapsed": false - }, + "execution_count": 122, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -4147,6 +4237,7 @@ "/* 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", @@ -4205,6 +4296,9 @@ " 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", @@ -4274,6 +4368,15 @@ " 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", @@ -4330,8 +4433,9 @@ " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\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", @@ -4464,10 +4568,10 @@ "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", - " var x0 = msg['x0'];\n", - " var y0 = fig.canvas.height - msg['y0'];\n", - " var x1 = msg['x1'];\n", - " var y1 = fig.canvas.height - msg['y1'];\n", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", @@ -4623,8 +4727,8 @@ " this.canvas_div.focus();\n", " }\n", "\n", - " var x = canvas_pos.x;\n", - " var y = canvas_pos.y;\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", @@ -4745,6 +4849,7 @@ "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", @@ -4753,7 +4858,7 @@ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", - " $(fig.parent_element).html('');\n", + " $(fig.parent_element).html('');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", @@ -4764,8 +4869,9 @@ "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] = '';\n", + " this.cell_info[1]['text/html'] = '';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", @@ -4854,12 +4960,9 @@ " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\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", @@ -4908,7 +5011,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -4946,38 +5049,55 @@ }, { "cell_type": "code", - "execution_count": 238, + "execution_count": 166, "metadata": { "collapsed": true }, "outputs": [], "source": [ - "def plot_rgb_bar(data_rgb, ids_rgb, spline_s=1):\n", + "def plot_rgb_bar(data_rgb, ids_rgb, spline_s=1, show_label=True, save_svg=None):\n", " fig, ax = plt.subplots(1, 1)\n", - " fig.suptitle('Runs {}(R), {}(G), {}(B) at {:%y-%m-%d %H:%M:%S}'.format(*ids_rgb, datetime.now()))\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", - " ((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", + " (('#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)\n", + " ax.errorbar(steps, values, yerr=stdev, color=color_bright, zorder=1)\n", " \n", " spline = inter.UnivariateSpline(steps, values, s=spline_s)\n", - " ax.plot(steps, spline(steps), color=color_dark)\n", + " ax.plot(steps, spline(steps), color=color_dark, 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('normalized amplitude')" + " 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": 226, - "metadata": { - "collapsed": false - }, + "execution_count": 124, + "metadata": {}, "outputs": [ { "data": { @@ -4985,6 +5105,7 @@ "/* 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", @@ -5043,6 +5164,9 @@ " 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", @@ -5112,6 +5236,15 @@ " 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", @@ -5168,8 +5301,9 @@ " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\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", @@ -5302,10 +5436,10 @@ "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", - " var x0 = msg['x0'];\n", - " var y0 = fig.canvas.height - msg['y0'];\n", - " var x1 = msg['x1'];\n", - " var y1 = fig.canvas.height - msg['y1'];\n", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", @@ -5461,8 +5595,8 @@ " this.canvas_div.focus();\n", " }\n", "\n", - " var x = canvas_pos.x;\n", - " var y = canvas_pos.y;\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", @@ -5583,6 +5717,7 @@ "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", @@ -5591,7 +5726,7 @@ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", - " $(fig.parent_element).html('');\n", + " $(fig.parent_element).html('');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", @@ -5602,8 +5737,9 @@ "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] = '';\n", + " this.cell_info[1]['text/html'] = '';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", @@ -5692,12 +5828,9 @@ " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\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", @@ -5746,7 +5879,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -5761,7 +5894,7 @@ "(380, 720)" ] }, - "execution_count": 226, + "execution_count": 124, "metadata": {}, "output_type": "execute_result" } @@ -5778,9 +5911,8 @@ }, { "cell_type": "code", - "execution_count": 261, + "execution_count": 168, "metadata": { - "collapsed": false, "scrolled": false }, "outputs": [ @@ -5806,6 +5938,7 @@ "/* 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", @@ -5864,6 +5997,9 @@ " 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", @@ -5933,6 +6069,15 @@ " 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", @@ -5989,8 +6134,9 @@ " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\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", @@ -6123,10 +6269,10 @@ "}\n", "\n", "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", - " var x0 = msg['x0'];\n", - " var y0 = fig.canvas.height - msg['y0'];\n", - " var x1 = msg['x1'];\n", - " var y1 = fig.canvas.height - msg['y1'];\n", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", " x0 = Math.floor(x0) + 0.5;\n", " y0 = Math.floor(y0) + 0.5;\n", " x1 = Math.floor(x1) + 0.5;\n", @@ -6282,8 +6428,8 @@ " this.canvas_div.focus();\n", " }\n", "\n", - " var x = canvas_pos.x;\n", - " var y = canvas_pos.y;\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", "\n", " this.send_message(name, {x: x, y: y, button: event.button,\n", " step: event.step,\n", @@ -6404,6 +6550,7 @@ "};\n", "\n", "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\n", " fig.root.unbind('remove')\n", "\n", " // Update the output cell to use the data from the current canvas.\n", @@ -6412,7 +6559,7 @@ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", " // the notebook keyboard shortcuts fail.\n", " IPython.keyboard_manager.enable()\n", - " $(fig.parent_element).html('');\n", + " $(fig.parent_element).html('');\n", " fig.close_ws(fig, msg);\n", "}\n", "\n", @@ -6423,8 +6570,9 @@ "\n", "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width/mpl.ratio\n", " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] = '';\n", + " this.cell_info[1]['text/html'] = '';\n", "}\n", "\n", "mpl.figure.prototype.updated_canvas_event = function() {\n", @@ -6513,12 +6661,9 @@ " // Check for shift+enter\n", " if (event.shiftKey && event.which == 13) {\n", " this.canvas_div.blur();\n", - " event.shiftKey = false;\n", - " // Send a \"J\" for go to next cell\n", - " event.which = 74;\n", - " event.keyCode = 74;\n", - " manager.command_mode();\n", - " manager.handle_keydown(event);\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", @@ -6567,7 +6712,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -6575,6 +6720,13 @@ }, "metadata": {}, "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "spline_s 0.5\n" + ] } ], "source": [ @@ -6588,6 +6740,7 @@ "λ_led = [623, 518, 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", @@ -6645,21 +6798,24 @@ "data_rgb = [ (λ[λ > 380], y[λ > 380], σ2[λ > 380]) for λ, y, σ2 in data_rgb ]\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", + "#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", - "plot_rgb_bar(data_rgb, ids, spline_s=0.005)" + "# 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", + "\n", + "plot_rgb_bar(data_rgb, ids, spline_s=0.5, show_label=False, save_svg='/tmp/processed_plot_cheap_rgb.svg')" ] }, { "cell_type": "code", - "execution_count": 271, + "execution_count": 58, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ - "# CIE XYZ Color matching functions\n", + "# 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", @@ -6669,7 +6825,7 @@ }, { "cell_type": "code", - "execution_count": 285, + "execution_count": 59, "metadata": { "collapsed": true }, @@ -6688,10 +6844,8 @@ }, { "cell_type": "code", - "execution_count": 289, - "metadata": { - "collapsed": false - }, + "execution_count": 60, + "metadata": {}, "outputs": [ { "data": { @@ -6701,7 +6855,7 @@ " [ 1.75128165e-01, 2.49230694e-01, 9.78488855e-01]])" ] }, - "execution_count": 289, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } @@ -6713,9 +6867,9 @@ }, { "cell_type": "code", - "execution_count": 330, + "execution_count": 61, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -6728,10 +6882,8 @@ }, { "cell_type": "code", - "execution_count": 332, - "metadata": { - "collapsed": false - }, + "execution_count": 62, + "metadata": {}, "outputs": [ { "data": { @@ -6739,7 +6891,7 @@ "array([ 0.72869072, 0.1386238 , 0.20139265])" ] }, - "execution_count": 332, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -6754,8 +6906,20 @@ "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": 0 + "nbformat_minor": 1 } diff --git a/firmware/measure_spectrum.py b/firmware/measure_spectrum.py index 471d1a8..47df7b3 100644 --- a/firmware/measure_spectrum.py +++ b/firmware/measure_spectrum.py @@ -3,7 +3,6 @@ import time import statistics import sqlite3 -from olsndot import Olsndot, Driver from datetime import datetime from pyBusPirateLite import BitBang @@ -12,34 +11,38 @@ if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() - parser.add_argument('run_name', nargs='?', default='auto') - parser.add_argument('buspirate_port', nargs='?', default='/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AD01W1RF-if00-port0') parser.add_argument('-s', '--steps', type=int, nargs='?', default=400, help='Steps to run through') parser.add_argument('-k', '--skip', type=int, nargs='?', default=2, help='Steps skip between measurements for shorter runtime') parser.add_argument('-d', '--database', default='spectra.sqlite3', help='sqlite3 database file to store results in') parser.add_argument('-w', '--wait', type=float, default=2.0, help='time to wait between samples in seconds') parser.add_argument('-o', '--oversample', type=int, default=32, help='oversampling ratio') + parser.add_argument('-g', '--gain', type=float, default=None, help='Transimpedance gain of amplifier in MOhm') parser.add_argument('-c', '--comment', help='run comment') + parser.add_argument('-p', '--port', default='/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AD01W1RF-if00-port0', help='Serial port device of the control buspirate') + parser.add_argument('run_name', nargs='?', default='auto') + parser.add_argument('color', help='Captured color channel') args = parser.parse_args() db = sqlite3.connect(args.database) db.execute(""" CREATE TABLE IF NOT EXISTS runs ( - run_id INTEGER PRIMARY KEY, + capture_id INTEGER PRIMARY KEY, name TEXT, comment TEXT, + color TEXT, -- Captured color channel + gain REAL, -- Preamplifier transimpedance in Ohms timestamp REAL -- unix timestamp in fractional seconds )""") db.execute(""" CREATE TABLE IF NOT EXISTS measurements ( measurement_id INTEGER PRIMARY KEY, - run_id INTEGER, + capture_id INTEGER, led_on INTEGER, step INTEGER, voltage REAL, -- volts voltage_stdev REAL, -- volts timestamp REAL, -- unix timestamp in fractional seconds - FOREIGN KEY (run_id) REFERENCES runs)""") + FOREIGN KEY (capture_id) REFERENCES runs)""") class BPState: def __init__(self, port): @@ -72,7 +75,7 @@ if __name__ == '__main__': self.reinit() return [ self.bp.adc_value for _ in range(oversampling) ] - bp = BPState(args.buspirate_port) + bp = BPState(args.port) run_name = args.run_name if not str.isnumeric(args.run_name[-1]): @@ -82,11 +85,11 @@ if __name__ == '__main__': 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, timestamp) VALUES (?, ?, ?)', - (run_name, args.comment, time.time())) - run_id = cur.lastrowid + cur.execute('INSERT INTO runs(name, comment, color, gain, timestamp) VALUES (?, ?, ?, ?, ?)', + (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(run_id, run_name, datetime.now())) + print('Starting run {} "{}" at {:%y-%m-%d %H:%M:%S:%f}'.format(capture_id, run_name, datetime.now())) print('[measurement id] " " [step number] " " [reading (V)]') bp.stepper_direction('down') @@ -107,9 +110,9 @@ if __name__ == '__main__': cur = db.cursor() cur.execute(''' INSERT INTO measurements ( - run_id, led_on, step, voltage, voltage_stdev, timestamp + capture_id, led_on, step, voltage, voltage_stdev, timestamp ) VALUES (?, ?, ?, ?, ?, ?)''', - (run_id, led_val, step, mean, stdev, time.time())) + (capture_id, led_val, step, mean, stdev, time.time())) print('{:08d} {:03} {}: {:5.4f} stdev {:5.4f}'.format( cur.lastrowid, step, led_val, mean, stdev)) except KeyboardInterrupt: diff --git a/firmware/results.sqlite3 b/firmware/results.sqlite3 deleted file mode 100644 index d0ede6a..0000000 Binary files a/firmware/results.sqlite3 and /dev/null differ diff --git a/firmware/spectra.sqlite3 b/firmware/spectra.sqlite3 index 09e23c2..fe9be41 100644 Binary files a/firmware/spectra.sqlite3 and b/firmware/spectra.sqlite3 differ diff --git a/firmware/stepper_test.py b/firmware/stepper_test.py index 23486fb..95a4e2a 100644 --- a/firmware/stepper_test.py +++ b/firmware/stepper_test.py @@ -3,7 +3,6 @@ import time import statistics import sqlite3 -from olsndot import Olsndot, Driver from datetime import datetime from pyBusPirateLite import BitBang