{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 26. Active filters\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " \n", " Loading BokehJS ...\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " const force = true;\n", "\n", " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", " root._bokeh_onload_callbacks = [];\n", " root._bokeh_is_loading = undefined;\n", " }\n", "\n", "const JS_MIME_TYPE = 'application/javascript';\n", " const HTML_MIME_TYPE = 'text/html';\n", " const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n", " const CLASS_NAME = 'output_bokeh rendered_html';\n", "\n", " /**\n", " * Render data to the DOM node\n", " */\n", " function render(props, node) {\n", " const script = document.createElement(\"script\");\n", " node.appendChild(script);\n", " }\n", "\n", " /**\n", " * Handle when an output is cleared or removed\n", " */\n", " function handleClearOutput(event, handle) {\n", " const cell = handle.cell;\n", "\n", " const id = cell.output_area._bokeh_element_id;\n", " const server_id = cell.output_area._bokeh_server_id;\n", " // Clean up Bokeh references\n", " if (id != null && id in Bokeh.index) {\n", " Bokeh.index[id].model.document.clear();\n", " delete Bokeh.index[id];\n", " }\n", "\n", " if (server_id !== undefined) {\n", " // Clean up Bokeh references\n", " const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n", " cell.notebook.kernel.execute(cmd_clean, {\n", " iopub: {\n", " output: function(msg) {\n", " const id = msg.content.text.trim();\n", " if (id in Bokeh.index) {\n", " Bokeh.index[id].model.document.clear();\n", " delete Bokeh.index[id];\n", " }\n", " }\n", " }\n", " });\n", " // Destroy server and session\n", " const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n", " cell.notebook.kernel.execute(cmd_destroy);\n", " }\n", " }\n", "\n", " /**\n", " * Handle when a new output is added\n", " */\n", " function handleAddOutput(event, handle) {\n", " const output_area = handle.output_area;\n", " const output = handle.output;\n", "\n", " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n", " if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n", " return\n", " }\n", "\n", " const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", "\n", " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n", " toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n", " // store reference to embed id on output_area\n", " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", " }\n", " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", " const bk_div = document.createElement(\"div\");\n", " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", " const script_attrs = bk_div.children[0].attributes;\n", " for (let i = 0; i < script_attrs.length; i++) {\n", " toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n", " toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n", " }\n", " // store reference to server id on output_area\n", " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", " }\n", " }\n", "\n", " function register_renderer(events, OutputArea) {\n", "\n", " function append_mime(data, metadata, element) {\n", " // create a DOM node to render to\n", " const toinsert = this.create_output_subarea(\n", " metadata,\n", " CLASS_NAME,\n", " EXEC_MIME_TYPE\n", " );\n", " this.keyboard_manager.register_events(toinsert);\n", " // Render to node\n", " const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", " render(props, toinsert[toinsert.length - 1]);\n", " element.append(toinsert);\n", " return toinsert\n", " }\n", "\n", " /* Handle when an output is cleared or removed */\n", " events.on('clear_output.CodeCell', handleClearOutput);\n", " events.on('delete.Cell', handleClearOutput);\n", "\n", " /* Handle when a new output is added */\n", " events.on('output_added.OutputArea', handleAddOutput);\n", "\n", " /**\n", " * Register the mime type and append_mime function with output_area\n", " */\n", " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", " /* Is output safe? */\n", " safe: true,\n", " /* Index of renderer in `output_area.display_order` */\n", " index: 0\n", " });\n", " }\n", "\n", " // register the mime type if in Jupyter Notebook environment and previously unregistered\n", " if (root.Jupyter !== undefined) {\n", " const events = require('base/js/events');\n", " const OutputArea = require('notebook/js/outputarea').OutputArea;\n", "\n", " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", " register_renderer(events, OutputArea);\n", " }\n", " }\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " const NB_LOAD_WARNING = {'data': {'text/html':\n", " \"
\\n\"+\n", " \"

\\n\"+\n", " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", " \"

\\n\"+\n", " \"\\n\"+\n", " \"\\n\"+\n", " \"from bokeh.resources import INLINE\\n\"+\n", " \"output_notebook(resources=INLINE)\\n\"+\n", " \"\\n\"+\n", " \"
\"}};\n", "\n", " function display_loaded() {\n", " const el = document.getElementById(\"1002\");\n", " if (el != null) {\n", " el.textContent = \"BokehJS is loading...\";\n", " }\n", " if (root.Bokeh !== undefined) {\n", " if (el != null) {\n", " el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n", " }\n", " } else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(display_loaded, 100)\n", " }\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", " if (root._bokeh_is_loading > 0) {\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " }\n", " if (js_urls == null || js_urls.length === 0) {\n", " run_callbacks();\n", " return null;\n", " }\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " root._bokeh_is_loading = css_urls.length + js_urls.length;\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", "\n", " function on_error(url) {\n", " console.error(\"failed to load \" + url);\n", " }\n", "\n", " for (let i = 0; i < css_urls.length; i++) {\n", " const url = css_urls[i];\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error.bind(null, url);\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " }\n", "\n", " for (let i = 0; i < js_urls.length; i++) {\n", " const url = js_urls[i];\n", " const element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error.bind(null, url);\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.3.min.js\"];\n", " const css_urls = [];\n", "\n", " const inline_js = [ function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", "function(Bokeh) {\n", " }\n", " ];\n", "\n", " function run_inline_js() {\n", " if (root.Bokeh !== undefined || force === true) {\n", " for (let i = 0; i < inline_js.length; i++) {\n", " inline_js[i].call(root, root.Bokeh);\n", " }\n", "if (force === true) {\n", " display_loaded();\n", " }} else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!root._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " root._bokeh_failed_load = true;\n", " } else if (force !== true) {\n", " const cell = $(document.getElementById(\"1002\")).parents('.cell').data().cell;\n", " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", " }\n", " }\n", "\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", " run_inline_js();\n", " } else {\n", " load_libs(css_urls, js_urls, function() {\n", " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", " run_inline_js();\n", " });\n", " }\n", "}(window));" ], "application/vnd.bokehjs_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n const el = document.getElementById(\"1002\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.3.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\nif (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"1002\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "import bokeh.plotting\n", "import bokeh.io\n", "bokeh.io.output_notebook()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "In [a previous lesson](../20/introduction_to_filters.ipynb), we built RC filters. Those filters were **passive** because they are not powered. Here, we will consider **active** filters, which feature powered op-amps." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Motivation for active filters\n", "\n", "As we have already seen, the structure of a simple RC filter is the same as a voltage divider, as shown below.\n", "\n", "
\n", " \n", "![Generic voltage divider 2](generic_voltage_divider.svg) \n", " \n", "
\n", "\n", "For a low-pass filter, Z₁ is a resistor (say, with resistance $R$) and Z₂ is a capacitor (say, with capacitance $C$). In a high-pass filter, the \n", "Z₁ is a capacitor and Z₂ is a resistor. \n", "\n", "Consider for a moment a low-pass RC filter. We previously worked out that\n", "\n", "\\begin{align}\n", "\\left|V_\\mathrm{out}\\right| = \\frac{1}{\\sqrt{1 + \\omega^2R^2C^2}}\\,\\left|V_\\mathrm{in}\\right|.\n", "\\end{align}\n", "\n", "To get a feel for this relationship, let's make a plot of the response. The response is typically plotted in decibels (dB), given by\n", "\n", "\\begin{align}\n", "\\text{dB} = 10 \\log_{10}\\frac{\\left|V_\\mathrm{out}\\right|}{\\left|V_\\mathrm{in}\\right|}.\n", "\\end{align}\n", "\n", "We plot the response in decibels below." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function embed_document(root) {\n", " const docs_json = {\"6ff87293-1a1c-4dbf-9ffb-1b4cb34ce188\":{\"defs\":[],\"roots\":{\"references\":[{\"attributes\":{\"below\":[{\"id\":\"1012\"}],\"center\":[{\"id\":\"1015\"},{\"id\":\"1019\"}],\"frame_height\":175,\"frame_width\":250,\"left\":[{\"id\":\"1016\"}],\"renderers\":[{\"id\":\"1038\"},{\"id\":\"1044\"}],\"title\":{\"id\":\"1046\"},\"toolbar\":{\"id\":\"1027\"},\"x_range\":{\"id\":\"1004\"},\"x_scale\":{\"id\":\"1008\"},\"y_range\":{\"id\":\"1006\"},\"y_scale\":{\"id\":\"1010\"}},\"id\":\"1003\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{\"start\":-30},\"id\":\"1006\",\"type\":\"Range1d\"},{\"attributes\":{},\"id\":\"1008\",\"type\":\"LogScale\"},{\"attributes\":{\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1041\",\"type\":\"Line\"},{\"attributes\":{\"axis\":{\"id\":\"1012\"},\"coordinates\":null,\"group\":null,\"ticker\":null},\"id\":\"1015\",\"type\":\"Grid\"},{\"attributes\":{\"end\":1000.0,\"start\":0.001},\"id\":\"1004\",\"type\":\"Range1d\"},{\"attributes\":{\"axis_label\":\"response (dB)\",\"coordinates\":null,\"formatter\":{\"id\":\"1049\"},\"group\":null,\"major_label_policy\":{\"id\":\"1050\"},\"ticker\":{\"id\":\"1017\"}},\"id\":\"1016\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"1056\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"coordinates\":null,\"group\":null},\"id\":\"1046\",\"type\":\"Title\"},{\"attributes\":{\"num_minor_ticks\":10},\"id\":\"1013\",\"type\":\"LogTicker\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"lightgray\",\"line_width\":4,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1037\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1055\",\"type\":\"Selection\"},{\"attributes\":{},\"id\":\"1057\",\"type\":\"Selection\"},{\"attributes\":{\"data\":{\"x\":[0.001,1,1],\"y\":[0,0,-30]},\"selected\":{\"id\":\"1055\"},\"selection_policy\":{\"id\":\"1054\"}},\"id\":\"1034\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"axis\":{\"id\":\"1016\"},\"coordinates\":null,\"dimension\":1,\"group\":null,\"ticker\":null},\"id\":\"1019\",\"type\":\"Grid\"},{\"attributes\":{\"line_color\":\"lightgray\",\"line_width\":4,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1035\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1017\",\"type\":\"BasicTicker\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1042\",\"type\":\"Line\"},{\"attributes\":{\"source\":{\"id\":\"1040\"}},\"id\":\"1045\",\"type\":\"CDSView\"},{\"attributes\":{\"ticker\":null},\"id\":\"1052\",\"type\":\"LogTickFormatter\"},{\"attributes\":{},\"id\":\"1050\",\"type\":\"AllLabels\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1043\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1020\",\"type\":\"PanTool\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1040\"},\"glyph\":{\"id\":\"1041\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1043\"},\"nonselection_glyph\":{\"id\":\"1042\"},\"view\":{\"id\":\"1045\"}},\"id\":\"1044\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"1021\",\"type\":\"WheelZoomTool\"},{\"attributes\":{},\"id\":\"1025\",\"type\":\"HelpTool\"},{\"attributes\":{},\"id\":\"1049\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"overlay\":{\"id\":\"1026\"}},\"id\":\"1022\",\"type\":\"BoxZoomTool\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1034\"},\"glyph\":{\"id\":\"1035\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1037\"},\"nonselection_glyph\":{\"id\":\"1036\"},\"view\":{\"id\":\"1039\"}},\"id\":\"1038\",\"type\":\"GlyphRenderer\"},{\"attributes\":{\"bottom_units\":\"screen\",\"coordinates\":null,\"fill_alpha\":0.5,\"fill_color\":\"lightgrey\",\"group\":null,\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":1.0,\"line_color\":\"black\",\"line_dash\":[4,4],\"line_width\":2,\"right_units\":\"screen\",\"syncable\":false,\"top_units\":\"screen\"},\"id\":\"1026\",\"type\":\"BoxAnnotation\"},{\"attributes\":{},\"id\":\"1054\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"source\":{\"id\":\"1034\"}},\"id\":\"1039\",\"type\":\"CDSView\"},{\"attributes\":{},\"id\":\"1024\",\"type\":\"ResetTool\"},{\"attributes\":{\"tools\":[{\"id\":\"1020\"},{\"id\":\"1021\"},{\"id\":\"1022\"},{\"id\":\"1023\"},{\"id\":\"1024\"},{\"id\":\"1025\"}]},\"id\":\"1027\",\"type\":\"Toolbar\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"lightgray\",\"line_width\":4,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1036\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1053\",\"type\":\"AllLabels\"},{\"attributes\":{\"data\":{\"x\":{\"__ndarray__\":\"/Knx0k1iUD+HZ0uK1o9RPxbaHL4M01I/7fUgZH8tVD/0AZog2qBVP2fLLlbnLlc/vcC6W5LZWD/2Xsva6aJaP8yRt1kijVw/Hnlz9JiaXj94W74j62ZgPyefPMjIlGE/WXIyBFrYYj9xgbg9LjNkP+DMgpHxpmU/xYhS4241Zz/xk2UUkuBoPzi2nmJqqmo/YhlU8yyVbD8QUeeMN6NuP5wDQsGJa3A/miTQaryZcT+l5o3IqN1yPwtUEbHeOHQ/BxOiuQqtdT8oG0BH+Dt3P2K1ssWT53g/cbtbB+2xej8lXb3QOZ18PwCi1pLYq34/vFfaqylwgD/SaWpysZ6BP4fhmgv54oI/zdWevpA+hD9viHOZJbOFP0AbfIKDQoc/FkYwcJfuiD9tx5rJcbmKP6iplvJIpYw/6nXwBny0jj+NJ+XjynSQPw79b9+no5E/5ivFzUrokj9Fj9RmRESUP/cDczFCuZU/FEeLlRBJlz8Sj2wUnfWYP9Nd9Kn4wJo/j3mDWVqtnD8VCOTpIb2ePzRdwGlteaA/2IhFsp+ooT/3rHgPnu2iP5gpJqr5SaQ/Xn8cgmC/pT8PgvKAn0+nP3YB9rKk/Kg/Sy0BqYHIqj9vdScGbrWsPyXFYDzKxa4/R/3JPRF+sD8d1E/rmK2xP2BqIdHy8rI/bW4HibBPtD9PF+yLgMW1PwjVNkUwVrc/fzZbTK4DuT9/D1rHDNC6Pwd0JvmDvbw/JUsW/3TOvj/YJmBgtoLAPyTC84qTssE/L4grE0n4wj8SSOwDaVXEP2cLXk+iy8U/UG7d4sJcxz+Q7yrhuQrJPxkJmAWa18o/NXokM5zFzD+XabQyItfOP3sT4dFch9A/qlKWkY+30T/jSAPWoP3SP3jBSBsjW9Q/Rb7uzMXR1T+4oWtaV2PXP0kW9HHHEdk/5klUZCnf2j8Ku8W0ts3cP4Ah69fR394/TBerkgSM4D/ToZz/jLzhP38NFRr6AuM/QQaRz95g5D+PtRoF69flP6HoZqztaec/irxF/9YY6T/XLCjkuubqP9eXrn7T1ew/eaVq74Po7j/9oByjrZDwP0boa9WLwfE/ilXN31QI8z/FYjkhnGb0P/yZXvgR3vU/A+JU2YVw9z9qHK+J6B/5Pww4rYVO7vo/OKCDkfLd/D+7WeN5OPH+P9M5lANYlQBAHXtpE4zGAUAYv5gnsQ0DQB5EthBbbARAYTc3pzrkBUB2UrvhH3cHQG+YvxH8JglA5Bx9SeT1CkAhkuntE+YMQCrUBXjv+Q5AtoVwtAOaEEANzPq5jcsRQNgG5PEOExNALzh8nhtyFEC3fCESZeoVQEEkIMa7fRdAd7sGmBEuGUAHuDEwfP0aQO9ZhZQ37hxAatyC6qgCH0A4QxC2sJ4gQFZphcmQ0CFAFwgcP24YI0Cy7f/K3XckQDB8mjmR8CVAZGcJh1mEJ0DROBQdKTUpQGkRZToWBStAcRL8hV32LEDwawvSZAsvQJVL0ghfozBA1P1uQpXVMUDGvK0Pzx0zQDs0tpahfTRAI2sfHr/2NUCdUf0k+Yo3QEPsd6FCPDlAe1yxaLIMO0D0BPPChf48QPCtUC8jFD9AxZIVrQ6oQEADUR0lm9pBQJY9BmQxI0NARvwTAmeDREA9oi3A7vxFQHo+gqCakUdAF9rBJV5DSUAB+LC7UBRLQFipD0ywBk1Anf8DA+QcT0B6Jzmjv6xQQA1H9nGi31FA5MGSPJUoU0A+V44NLolUQHWdQiAgA1ZAYK8e+j2YV0ApL4Kqe0pZQERu/jPxG1tAEab3Id0OXUAX8NZNpyVfQC8znOtxsWBAy+BfKavkYUDVn8CZ+i1jQIZ3mrn2jmRAF/zbPlMJZkCVS1ky455nQO9ASTCbUWlAE3U00pMja0A/0FBFDBdtQH9AexBtLm9AK/qdhiW2cEDTO8BLtelxQFhM/XthM3NAhbCtBsGUdEDSgHcciA92QE3guEmKpXdAhY2nt7xYeUDO7e2WOCt7QLcrwbY9H31AB+SiSzU3f0CJ25102rqAQH2SfdnA7oFAO1u248k4g0Crdj31jJqEQMERk7m+FYZAsmDEQDOsh0C7uy1B4F+JQIXlxYLfMotADOvudnEnjUAAAAAAAECPQA==\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]},\"y\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]}},\"selected\":{\"id\":\"1057\"},\"selection_policy\":{\"id\":\"1056\"}},\"id\":\"1040\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"axis_label\":\"\\u03c9RC\",\"coordinates\":null,\"formatter\":{\"id\":\"1052\"},\"group\":null,\"major_label_policy\":{\"id\":\"1053\"},\"ticker\":{\"id\":\"1013\"}},\"id\":\"1012\",\"type\":\"LogAxis\"},{\"attributes\":{},\"id\":\"1023\",\"type\":\"SaveTool\"},{\"attributes\":{},\"id\":\"1010\",\"type\":\"LinearScale\"}],\"root_ids\":[\"1003\"]},\"title\":\"Bokeh Application\",\"version\":\"2.4.3\"}};\n", " const render_items = [{\"docid\":\"6ff87293-1a1c-4dbf-9ffb-1b4cb34ce188\",\"root_ids\":[\"1003\"],\"roots\":{\"1003\":\"f40e4751-49dd-49f2-8301-4a963d6048d4\"}}];\n", " root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n", " }\n", " if (root.Bokeh !== undefined) {\n", " embed_document(root);\n", " } else {\n", " let attempts = 0;\n", " const timer = setInterval(function(root) {\n", " if (root.Bokeh !== undefined) {\n", " clearInterval(timer);\n", " embed_document(root);\n", " } else {\n", " attempts++;\n", " if (attempts > 100) {\n", " clearInterval(timer);\n", " console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\");\n", " }\n", " }\n", " }, 10, root)\n", " }\n", "})(window);" ], "application/vnd.bokehjs_exec.v0+json": "" }, "metadata": { "application/vnd.bokehjs_exec.v0+json": { "id": "1003" } }, "output_type": "display_data" } ], "source": [ "omega = np.logspace(-3, 3, 200)\n", "lowpass_dB = -5 * np.log10(1 + omega**2)\n", "\n", "p = bokeh.plotting.figure(\n", " frame_width=250,\n", " frame_height=175,\n", " x_axis_type='log',\n", " x_axis_label='ωRC',\n", " y_axis_label='response (dB)',\n", " x_range=[1e-3, 1e3],\n", " y_range=[-30, 1],\n", ")\n", "\n", "p.line([1e-3, 1, 1], [0, 0, -30], color='lightgray', line_width=4)\n", "p.line(omega, lowpass_dB, line_width=2)\n", "\n", "bokeh.io.show(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I have also included in this plot the response of an ideal low-pass filter in gray. Any frequencies above $1/RC$ are blocked and those below $1/RC$ can be passed through without significant attenuation. Conversely, the simple RC filter has a dull (as opposed to sharp) **knee**, the name given to the bend in the curve. To the right of the knee, the response features a **roll off** of ten dB per factor of ten in frequency.\n", "\n", "We would like the response to be as close to ideal as possible. That means we want a steeper roll off. We also want the knee at $\\omega = 1/RC$ to be sharper. This can be accomplished with more complex filter designs, particularly through the use of **inductors** (giving so-called **RLC filters**).\n", "\n", "There are, however, many disadvantages to using inductors. Importantly, they are bulky and expensive and also have series resistance, leading to non-ideal behavior. Fortunately, we can use op-amps to synthesize circuits that have the properties of (near) ideal RLC circuits. Because the op-amps are powered, these are called active filters." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sallen-Key filters\n", "\n", "We will consider one of the simplest active filters, the **Sallen-Key filter**. It is a simple special case of **voltage-controlled voltage-source** (VCVS) filters. The topology of the Sallen-Key filter is shown below.\n", "\n", "
\n", " \n", "![Sallen-key topology](sallen-key.svg)\n", " \n", "
\n", "\n", "For a high-pass filter, Z₁ and Z₂ are capacitors and Z₃ and Z₄ are resistors. For a low-pass filter, Z₁ and Z₂ are resistors and Z₃ and Z₄ are capacitors. The topology looks like cascaded RC filters, except with feedback.\n", "\n", "Taking as an example a low-pass filter, we an take $R_1 = R_2 = R$ and $C_3 = C_4 = C$, and derive that the response is\n", "\n", "\\begin{align}\n", "\\frac{\\left|V_\\mathrm{out}\\right|}{\\left|V_\\mathrm{in}\\right|} = \\frac{1}{1 + \\omega^2R^2C^2}.\n", "\\end{align}\n", "\n", "An important consequence of this result is that the cut-off frequency is, like in the case of the passive RC filters, about $1/RC$. We can add this response to the plot." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function embed_document(root) {\n", " const docs_json = {\"5c8a802a-1a41-4235-8809-2d87128d44f7\":{\"defs\":[],\"roots\":{\"references\":[{\"attributes\":{\"below\":[{\"id\":\"1012\"}],\"center\":[{\"id\":\"1015\"},{\"id\":\"1019\"}],\"frame_height\":175,\"frame_width\":250,\"left\":[{\"id\":\"1016\"}],\"renderers\":[{\"id\":\"1038\"},{\"id\":\"1044\"},{\"id\":\"1128\"}],\"title\":{\"id\":\"1046\"},\"toolbar\":{\"id\":\"1027\"},\"x_range\":{\"id\":\"1004\"},\"x_scale\":{\"id\":\"1008\"},\"y_range\":{\"id\":\"1006\"},\"y_scale\":{\"id\":\"1010\"}},\"id\":\"1003\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{\"start\":-30},\"id\":\"1006\",\"type\":\"Range1d\"},{\"attributes\":{},\"id\":\"1008\",\"type\":\"LogScale\"},{\"attributes\":{\"data\":{\"x\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]},\"y\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]}},\"selected\":{\"id\":\"1143\"},\"selection_policy\":{\"id\":\"1142\"}},\"id\":\"1124\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1041\",\"type\":\"Line\"},{\"attributes\":{\"axis\":{\"id\":\"1012\"},\"coordinates\":null,\"group\":null,\"ticker\":null},\"id\":\"1015\",\"type\":\"Grid\"},{\"attributes\":{\"end\":1000.0,\"start\":0.001},\"id\":\"1004\",\"type\":\"Range1d\"},{\"attributes\":{\"axis_label\":\"response (dB)\",\"coordinates\":null,\"formatter\":{\"id\":\"1049\"},\"group\":null,\"major_label_policy\":{\"id\":\"1050\"},\"ticker\":{\"id\":\"1017\"}},\"id\":\"1016\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"1056\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"coordinates\":null,\"group\":null},\"id\":\"1046\",\"type\":\"Title\"},{\"attributes\":{\"num_minor_ticks\":10},\"id\":\"1013\",\"type\":\"LogTicker\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"lightgray\",\"line_width\":4,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1037\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1055\",\"type\":\"Selection\"},{\"attributes\":{},\"id\":\"1057\",\"type\":\"Selection\"},{\"attributes\":{\"data\":{\"x\":[0.001,1,1],\"y\":[0,0,-30]},\"selected\":{\"id\":\"1055\"},\"selection_policy\":{\"id\":\"1054\"}},\"id\":\"1034\",\"type\":\"ColumnDataSource\"},{\"attributes\":{},\"id\":\"1143\",\"type\":\"Selection\"},{\"attributes\":{\"axis\":{\"id\":\"1016\"},\"coordinates\":null,\"dimension\":1,\"group\":null,\"ticker\":null},\"id\":\"1019\",\"type\":\"Grid\"},{\"attributes\":{\"line_color\":\"lightgray\",\"line_width\":4,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1035\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1017\",\"type\":\"BasicTicker\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1042\",\"type\":\"Line\"},{\"attributes\":{\"source\":{\"id\":\"1040\"}},\"id\":\"1045\",\"type\":\"CDSView\"},{\"attributes\":{\"ticker\":null},\"id\":\"1052\",\"type\":\"LogTickFormatter\"},{\"attributes\":{},\"id\":\"1050\",\"type\":\"AllLabels\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1043\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1142\",\"type\":\"UnionRenderers\"},{\"attributes\":{},\"id\":\"1020\",\"type\":\"PanTool\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1040\"},\"glyph\":{\"id\":\"1041\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1043\"},\"nonselection_glyph\":{\"id\":\"1042\"},\"view\":{\"id\":\"1045\"}},\"id\":\"1044\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"1021\",\"type\":\"WheelZoomTool\"},{\"attributes\":{},\"id\":\"1025\",\"type\":\"HelpTool\"},{\"attributes\":{},\"id\":\"1049\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"overlay\":{\"id\":\"1026\"}},\"id\":\"1022\",\"type\":\"BoxZoomTool\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1034\"},\"glyph\":{\"id\":\"1035\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1037\"},\"nonselection_glyph\":{\"id\":\"1036\"},\"view\":{\"id\":\"1039\"}},\"id\":\"1038\",\"type\":\"GlyphRenderer\"},{\"attributes\":{\"bottom_units\":\"screen\",\"coordinates\":null,\"fill_alpha\":0.5,\"fill_color\":\"lightgrey\",\"group\":null,\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":1.0,\"line_color\":\"black\",\"line_dash\":[4,4],\"line_width\":2,\"right_units\":\"screen\",\"syncable\":false,\"top_units\":\"screen\"},\"id\":\"1026\",\"type\":\"BoxAnnotation\"},{\"attributes\":{},\"id\":\"1054\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"source\":{\"id\":\"1034\"}},\"id\":\"1039\",\"type\":\"CDSView\"},{\"attributes\":{\"line_color\":\"orange\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1125\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1024\",\"type\":\"ResetTool\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"orange\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1127\",\"type\":\"Line\"},{\"attributes\":{\"source\":{\"id\":\"1124\"}},\"id\":\"1129\",\"type\":\"CDSView\"},{\"attributes\":{\"tools\":[{\"id\":\"1020\"},{\"id\":\"1021\"},{\"id\":\"1022\"},{\"id\":\"1023\"},{\"id\":\"1024\"},{\"id\":\"1025\"}]},\"id\":\"1027\",\"type\":\"Toolbar\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1124\"},\"glyph\":{\"id\":\"1125\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1127\"},\"nonselection_glyph\":{\"id\":\"1126\"},\"view\":{\"id\":\"1129\"}},\"id\":\"1128\",\"type\":\"GlyphRenderer\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"lightgray\",\"line_width\":4,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1036\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1053\",\"type\":\"AllLabels\"},{\"attributes\":{\"data\":{\"x\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]},\"y\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]}},\"selected\":{\"id\":\"1057\"},\"selection_policy\":{\"id\":\"1056\"}},\"id\":\"1040\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"orange\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1126\",\"type\":\"Line\"},{\"attributes\":{\"axis_label\":\"\\u03c9RC\",\"coordinates\":null,\"formatter\":{\"id\":\"1052\"},\"group\":null,\"major_label_policy\":{\"id\":\"1053\"},\"ticker\":{\"id\":\"1013\"}},\"id\":\"1012\",\"type\":\"LogAxis\"},{\"attributes\":{},\"id\":\"1023\",\"type\":\"SaveTool\"},{\"attributes\":{},\"id\":\"1010\",\"type\":\"LinearScale\"}],\"root_ids\":[\"1003\"]},\"title\":\"Bokeh Application\",\"version\":\"2.4.3\"}};\n", " const render_items = [{\"docid\":\"5c8a802a-1a41-4235-8809-2d87128d44f7\",\"root_ids\":[\"1003\"],\"roots\":{\"1003\":\"b4be1302-7024-42fc-bd3b-a82e0d9ff218\"}}];\n", " root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n", " }\n", " if (root.Bokeh !== undefined) {\n", " embed_document(root);\n", " } else {\n", " let attempts = 0;\n", " const timer = setInterval(function(root) {\n", " if (root.Bokeh !== undefined) {\n", " clearInterval(timer);\n", " embed_document(root);\n", " } else {\n", " attempts++;\n", " if (attempts > 100) {\n", " clearInterval(timer);\n", " console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\");\n", " }\n", " }\n", " }, 10, root)\n", " }\n", "})(window);" ], "application/vnd.bokehjs_exec.v0+json": "" }, "metadata": { "application/vnd.bokehjs_exec.v0+json": { "id": "1003" } }, "output_type": "display_data" } ], "source": [ "sk_lowpass_dB = -10 * np.log10(1 + omega**2)\n", "p.line(omega, sk_lowpass_dB, line_width=2, color='orange')\n", "\n", "bokeh.io.show(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, the Sallen-Key filter has a steeper roll-off. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Thinking exercise 8: Sallen-Key response\n", "\n", "Derive the above expression for the response of a Sallen-Key low-pass filter.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## VCVS filters\n", "\n", "Though the Sallen-Key filter has better roll-off, the knee, however, is still dull. This can be fixed by using the op-amp to amplify the output signal, as is done in VCVS filters, the topology of which is shown below.\n", "\n", "
\n", " \n", "![VCVS topology](VCVS.png)\n", " \n", "
\n", "\n", "Within the VCVS topology many filters can be designed with sharp knees, strong roll-off, and flat pass bands. However, filter design requires careful thought, and things can go wrong, including introduction of [ripple](https://en.wikipedia.org/wiki/Ripple_(electrical)#Frequency-domain_ripple) and [resonance](https://en.wikipedia.org/wiki/Resonance). I would recommend reading chapter 6 of Horowitz and Hill to learn more.\n", "\n", "For the purposes of the projects in this class, you should be able to get good signals using a Sallen-Key filter, perhaps with some amplification after the filtering. (In looking at the above diagram, it is clear that the Sallen-Key filter is a VCVS filter with $R_1 = 0$ and infinite $R_2$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Follow-along exercise 17: Sallen-Key filters\n", "\n", "In this exercise, you will build two Sallen-Key filters, a high-pass one and a low-pass one. To see how they work, you will send a sinusoidal signal that is tainted with high-frequency noise that also has slow drift. The high-pass filter will eliminate the drift and the low-pass filter will eliminate the high-frequency noise.\n", "\n", "Build the circuit below. The resistances are marked, and the capacitors should have capacitance $C_1 = C_2 = 2.2$ µF and $C_3 = C_4 = 0.22$ µF. Note that the part of the circuit featuring resistors R₁ and R₂ and capacitors C₁ and C₂ constitutes a high-pass filter, and the part of the circuit featuring R₃, R₄, C₃, and C₄ constitutes a low-pass filter.\n", "\n", "
\n", " \n", "![Sallen-Key high and low pass filters](sallen_key_exercise_schem.svg)\n", "\n", "
\n", "\n", "Based on the resistor and capacitor values, we can plot the respective response curves for the respective filters. If you like, you can derive that the response curve for the high-pass filter is\n", "\n", "\\begin{align}\n", "\\frac{\\left|V_\\mathrm{out}\\right|}{\\left|V_\\mathrm{in}\\right|} = \\frac{1}{1 + \\omega^{-2}R^{-2}C^{-2}}.\n", "\\end{align}\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function embed_document(root) {\n", " const docs_json = {\"ba1b42d7-f5f4-49d9-9896-aa9d797b6c99\":{\"defs\":[],\"roots\":{\"references\":[{\"attributes\":{\"below\":[{\"id\":\"1229\"}],\"center\":[{\"id\":\"1232\"},{\"id\":\"1236\"},{\"id\":\"1268\"}],\"frame_height\":175,\"frame_width\":300,\"left\":[{\"id\":\"1233\"}],\"renderers\":[{\"id\":\"1255\"},{\"id\":\"1274\"}],\"title\":{\"id\":\"1257\"},\"toolbar\":{\"id\":\"1244\"},\"x_range\":{\"id\":\"1221\"},\"x_scale\":{\"id\":\"1225\"},\"y_range\":{\"id\":\"1223\"},\"y_scale\":{\"id\":\"1227\"}},\"id\":\"1220\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1252\",\"type\":\"Line\"},{\"attributes\":{\"axis\":{\"id\":\"1233\"},\"coordinates\":null,\"dimension\":1,\"group\":null,\"ticker\":null},\"id\":\"1236\",\"type\":\"Grid\"},{\"attributes\":{},\"id\":\"1287\",\"type\":\"Selection\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"orange\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1273\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1241\",\"type\":\"ResetTool\"},{\"attributes\":{},\"id\":\"1234\",\"type\":\"BasicTicker\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1270\"},\"glyph\":{\"id\":\"1271\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1273\"},\"nonselection_glyph\":{\"id\":\"1272\"},\"view\":{\"id\":\"1275\"}},\"id\":\"1274\",\"type\":\"GlyphRenderer\"},{\"attributes\":{\"overlay\":{\"id\":\"1243\"}},\"id\":\"1239\",\"type\":\"BoxZoomTool\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1253\",\"type\":\"Line\"},{\"attributes\":{\"data\":{\"x\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]},\"y\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]}},\"selected\":{\"id\":\"1287\"},\"selection_policy\":{\"id\":\"1286\"}},\"id\":\"1270\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"source\":{\"id\":\"1270\"}},\"id\":\"1275\",\"type\":\"CDSView\"},{\"attributes\":{},\"id\":\"1237\",\"type\":\"PanTool\"},{\"attributes\":{},\"id\":\"1227\",\"type\":\"LinearScale\"},{\"attributes\":{\"label\":{\"value\":\"low-pass\"},\"renderers\":[{\"id\":\"1255\"}]},\"id\":\"1269\",\"type\":\"LegendItem\"},{\"attributes\":{},\"id\":\"1286\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"start\":-30},\"id\":\"1223\",\"type\":\"Range1d\"},{\"attributes\":{\"data\":{\"x\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]},\"y\":{\"__ndarray__\":\"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\",\"dtype\":\"float64\",\"order\":\"little\",\"shape\":[200]}},\"selected\":{\"id\":\"1266\"},\"selection_policy\":{\"id\":\"1265\"}},\"id\":\"1251\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"line_color\":\"orange\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1271\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"1240\",\"type\":\"SaveTool\"},{\"attributes\":{\"bottom_units\":\"screen\",\"coordinates\":null,\"fill_alpha\":0.5,\"fill_color\":\"lightgrey\",\"group\":null,\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":1.0,\"line_color\":\"black\",\"line_dash\":[4,4],\"line_width\":2,\"right_units\":\"screen\",\"syncable\":false,\"top_units\":\"screen\"},\"id\":\"1243\",\"type\":\"BoxAnnotation\"},{\"attributes\":{},\"id\":\"1260\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"label\":{\"value\":\"high-pass\"},\"renderers\":[{\"id\":\"1274\"}]},\"id\":\"1289\",\"type\":\"LegendItem\"},{\"attributes\":{},\"id\":\"1261\",\"type\":\"AllLabels\"},{\"attributes\":{\"line_alpha\":0.2,\"line_color\":\"#1f77b4\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1254\",\"type\":\"Line\"},{\"attributes\":{\"ticker\":null},\"id\":\"1263\",\"type\":\"LogTickFormatter\"},{\"attributes\":{\"coordinates\":null,\"group\":null},\"id\":\"1257\",\"type\":\"Title\"},{\"attributes\":{},\"id\":\"1264\",\"type\":\"AllLabels\"},{\"attributes\":{\"coordinates\":null,\"group\":null,\"items\":[{\"id\":\"1269\"},{\"id\":\"1289\"}],\"location\":\"bottom_center\"},\"id\":\"1268\",\"type\":\"Legend\"},{\"attributes\":{},\"id\":\"1265\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"end\":10000.0,\"start\":0.001},\"id\":\"1221\",\"type\":\"Range1d\"},{\"attributes\":{\"coordinates\":null,\"data_source\":{\"id\":\"1251\"},\"glyph\":{\"id\":\"1252\"},\"group\":null,\"hover_glyph\":null,\"muted_glyph\":{\"id\":\"1254\"},\"nonselection_glyph\":{\"id\":\"1253\"},\"view\":{\"id\":\"1256\"}},\"id\":\"1255\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"1266\",\"type\":\"Selection\"},{\"attributes\":{\"axis_label\":\"f (Hz)\",\"coordinates\":null,\"formatter\":{\"id\":\"1263\"},\"group\":null,\"major_label_policy\":{\"id\":\"1264\"},\"ticker\":{\"id\":\"1230\"}},\"id\":\"1229\",\"type\":\"LogAxis\"},{\"attributes\":{\"num_minor_ticks\":10},\"id\":\"1230\",\"type\":\"LogTicker\"},{\"attributes\":{},\"id\":\"1225\",\"type\":\"LogScale\"},{\"attributes\":{\"tools\":[{\"id\":\"1237\"},{\"id\":\"1238\"},{\"id\":\"1239\"},{\"id\":\"1240\"},{\"id\":\"1241\"},{\"id\":\"1242\"}]},\"id\":\"1244\",\"type\":\"Toolbar\"},{\"attributes\":{\"source\":{\"id\":\"1251\"}},\"id\":\"1256\",\"type\":\"CDSView\"},{\"attributes\":{\"line_alpha\":0.1,\"line_color\":\"orange\",\"line_width\":2,\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"1272\",\"type\":\"Line\"},{\"attributes\":{\"axis_label\":\"response (dB)\",\"coordinates\":null,\"formatter\":{\"id\":\"1260\"},\"group\":null,\"major_label_policy\":{\"id\":\"1261\"},\"ticker\":{\"id\":\"1234\"}},\"id\":\"1233\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"1242\",\"type\":\"HelpTool\"},{\"attributes\":{\"axis\":{\"id\":\"1229\"},\"coordinates\":null,\"group\":null,\"ticker\":null},\"id\":\"1232\",\"type\":\"Grid\"},{\"attributes\":{},\"id\":\"1238\",\"type\":\"WheelZoomTool\"}],\"root_ids\":[\"1220\"]},\"title\":\"Bokeh Application\",\"version\":\"2.4.3\"}};\n", " const render_items = [{\"docid\":\"ba1b42d7-f5f4-49d9-9896-aa9d797b6c99\",\"root_ids\":[\"1220\"],\"roots\":{\"1220\":\"1c6e4ab4-0b26-4391-ae84-e7a0afddff76\"}}];\n", " root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n", " }\n", " if (root.Bokeh !== undefined) {\n", " embed_document(root);\n", " } else {\n", " let attempts = 0;\n", " const timer = setInterval(function(root) {\n", " if (root.Bokeh !== undefined) {\n", " clearInterval(timer);\n", " embed_document(root);\n", " } else {\n", " attempts++;\n", " if (attempts > 100) {\n", " clearInterval(timer);\n", " console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\");\n", " }\n", " }\n", " }, 10, root)\n", " }\n", "})(window);" ], "application/vnd.bokehjs_exec.v0+json": "" }, "metadata": { "application/vnd.bokehjs_exec.v0+json": { "id": "1220" } }, "output_type": "display_data" } ], "source": [ "# Resistances and capacitances\n", "R = 68e3\n", "C_lp = 0.22e-6\n", "C_hp = 2.2e-6\n", "\n", "omega = np.logspace(-3, 4, 200)\n", "lowpass_dB = -10 * np.log10(1 + (2 * np.pi * R * C_lp * omega)**2)\n", "highpass_dB = -10 * np.log10(1 + 1/(2 * np.pi * R * C_hp * omega)**2)\n", "\n", "p = bokeh.plotting.figure(\n", " frame_width=300,\n", " frame_height=175,\n", " x_axis_type='log',\n", " x_axis_label='f (Hz)',\n", " y_axis_label='response (dB)',\n", " x_range=[1e-3, 1e4],\n", " y_range=[-30, 1],\n", ")\n", "\n", "p.line(omega, lowpass_dB, line_width=2, legend_label=\"low-pass\")\n", "p.line(omega, highpass_dB, line_width=2, color=\"orange\", legend_label=\"high-pass\")\n", "\n", "p.legend.location = \"bottom_center\"\n", "\n", "bokeh.io.show(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The high-pass filter lets frequencies above about 1 Hz through and the low-pass filter lets frequencies below about 10 Hz through. So, the low-pass filter should filter out high-frequency noise, and the high-pass filter should filter out slow variations in the signal.\n", "\n", "To verify this, upload the sketch below to Arduino. The sketch is set up for use with serial-dashboard (time stamps are written out).\n", "\n", "```arduino\n", "#include \n", "\n", "#define MCP4725_ADDR 0x62\n", "\n", "const int analogOutPin = A0;\n", "const int highPassPin = A1;\n", "const int lowPassPin = A3;\n", "\n", "const float highFreq = 10.0;\n", "const float lowFreq = 0.1;\n", "const unsigned long sampleDelay = 10;\n", "const unsigned long dacDelay = 1;\n", "unsigned long lastSampleTime = 0;\n", "unsigned long lastDACTime = 0;\n", "\n", "Adafruit_MCP4725 dac;\n", "\n", "unsigned long printVoltages() {\n", " unsigned long timeMilliseconds = millis();\n", " \n", " // Read voltages\n", " int dacReading = analogRead(analogOutPin);\n", " int highPassReading = analogRead(highPassPin);\n", " int lowPassReading = analogRead(lowPassPin);\n", "\n", " // Write the result\n", " if (Serial.availableForWrite()) {\n", " Serial.print(timeMilliseconds);\n", " Serial.print(\",\");\n", " Serial.print(dacReading);\n", " Serial.print(\",\");\n", " Serial.print(highPassReading);\n", " Serial.print(\",\");\n", " Serial.println(lowPassReading);\n", " }\n", " \n", " // Return time of acquisition\n", " return timeMilliseconds;\n", "}\n", "\n", "\n", "void setup() {\n", " dac.begin(MCP4725_ADDR);\n", "\n", " Serial.begin(115200);\n", "}\n", "\n", "\n", "void loop() {\n", " unsigned long currTime = millis();\n", " \n", " if (currTime - lastDACTime > dacDelay) {\n", " // Middle frequency signal\n", " int xMid = (int)(1000 * (1 + sin(2 * PI * highFreq * millis() / 1000.0)) / 2.0);\n", "\n", " // Slowly varying drift\n", " int xLow = (int)(1000 * (1 + sin(2 * PI * lowFreq * millis() / 1000.0)) / 2.0);\n", "\n", " // High-frequency noise\n", " int xRand = (int)(random(0, 2000) - 500);\n", "\n", " // Set the output\n", " dac.setVoltage((uint16_t) max(min(xLow + xMid + xRand, 4095), 0), false);\n", " }\n", "\n", " if (currTime - lastSampleTime > sampleDelay) {\n", " lastSampleTime = printVoltages();\n", " }\n", "}\n", "```\n", "\n", "The first column outputted is the time stamp in milliseconds. The second is the voltage that goes into the filters (a blue line in serial-dashboard). The second is the output of the high-pass filter (an orange line). The third is the output of the low-pass filter (a green line).\n", "\n", "Look at the signals coming out. Are the filters working as expected?\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Do-it-yourself exercise 13: A bandpass filter\n", "\n", "A **bandpass filter** allows intermediate frequencies through while filtering out high and low frequencies. They can be constructed by using a high-pass filter followed by a low-pass filter. In the case of the filters we have just considered, you can take the output of the high-pass filter and make that the input of the low-pass filter. Your task in this exercise is to implement that and see if you get the expected signal. There will be some attenuation, you should amplify the output of the bandpass filter.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we are just scratching the surface of filter design here. It is a rich and interesting field and you can create all kinds of filters with useful properties. What we have shown here for making low-, high-, and bandpass filters is only one (and a rather simple one) of myriad ways of filtering signals." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.9.13" } }, "nbformat": 4, "nbformat_minor": 4 }