{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# DDA walkthrought example: Chua attractor\n",
"\n",
"What follows is an example of the Chua attractor. It is described in the [Analog Paradigm Application Note 3](http://analogparadigm.com/downloads/alpaca_3.pdf) as well as in section 6.15 in Bernd's new book (Analog Programming II). The attractor is described by a coupled set of three ordinary differential equations,\n",
"\n",
"$$\n",
" \\dot x = c_1 (y-x-f(x)) \\\\\n",
" \\dot y = c_2 (x-y+z) \\\\\n",
" \\dot z = -c_3 y\n",
"$$\n",
"\n",
"with $f(x)$ a simple function decribing the Chua diode (given algebraically) and a number of parameters $c_{1,2,3}$. What follows is the scaling of these equations. The resulting set of equations is slightly more verbose. It's implementation is given in the following *traditional DDA* file:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"#\r\n",
"# Copyright (c) 2020 anabrid GmbH\r\n",
"# Contact: https://www.anabrid.com/licensing/\r\n",
"#\r\n",
"# This file is part of the examples of the PyAnalog toolkit.\r\n",
"#\r\n",
"# ANABRID_BEGIN_LICENSE:GPL\r\n",
"# Commercial License Usage\r\n",
"# Licensees holding valid commercial anabrid licenses may use this file in\r\n",
"# accordance with the commercial license agreement provided with the\r\n",
"# Software or, alternatively, in accordance with the terms contained in\r\n",
"# a written agreement between you and Anabrid GmbH. For licensing terms\r\n",
"# and conditions see https://www.anabrid.com/licensing. For further\r\n",
"# information use the contact form at https://www.anabrid.com/contact.\r\n",
"# \r\n",
"# GNU General Public License Usage\r\n",
"# Alternatively, this file may be used under the terms of the GNU \r\n",
"# General Public License version 3 as published by the Free Software\r\n",
"# Foundation and appearing in the file LICENSE.GPL3 included in the\r\n",
"# packaging of this file. Please review the following information to\r\n",
"# ensure the GNU General Public License version 3 requirements\r\n",
"# will be met: https://www.gnu.org/licenses/gpl-3.0.html.\r\n",
"# ANABRID_END_LICENSE\r\n",
"#\r\n",
"\r\n",
"\r\n",
"# Chua attractor, chapter 6.15 from Bernds book ap2.pdf\r\n",
"# Below is the scaled version (equations 6.40-6.51)\r\n",
"\r\n",
"x0 = const(0.1)\r\n",
"x1 = mult(-10, neg(sum(x, fx)))\r\n",
"x2 = neg(sum(y, mult(0.5, x1)))\r\n",
"x = neg(sum(mult(3.12, neg(int(x2, dt, 0))), x0))\r\n",
"\r\n",
"y1 = neg(sum(z, neg(mult(0.125, y))))\r\n",
"y2 = neg(sum(mult(1.25, x), mult(2, y1)))\r\n",
"y = mult(4, neg(int(y2, dt, 0)))\r\n",
"\r\n",
"z = int(mult(3.5, y), dt, 0)\r\n",
"\r\n",
"f1 = abs(sum(mult(0.7143,x), 0.2857))\r\n",
"f2 = abs(sum(mult(0.7143,x), -0.2857))\r\n",
"f3 = neg(sum(f1, neg(f2)))\r\n",
"fx = sum(mult(0.714, x), mult(0.3003, f3))\r\n",
"\r\n",
"dt = const(0.001)\r\n"
]
}
],
"source": [
"!cat chua.dda"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the following, we use the PyDDA library to read in this DDA file and demonstrate the internal representation."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"State({'dt': const(0.001),\n",
" 'f1': abs(sum(mult(0.7143, x), 0.2857)),\n",
" 'f2': abs(sum(mult(0.7143, x), -0.2857)),\n",
" 'f3': neg(sum(f1, neg(f2))),\n",
" 'fx': sum(mult(0.714, x), mult(0.3003, f3)),\n",
" 'x': neg(sum(mult(3.12, neg(int(x2, dt, 0))), x0)),\n",
" 'x0': const(0.1),\n",
" 'x1': mult(-10, neg(sum(x, fx))),\n",
" 'x2': neg(sum(y, mult(0.5, x1))),\n",
" 'y': mult(4, neg(int(y2, dt, 0))),\n",
" 'y1': neg(sum(z, neg(mult(0.125, y)))),\n",
" 'y2': neg(sum(mult(1.25, x), mult(2, y1))),\n",
" 'z': int(mult(3.5, y), dt, 0)})"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from dda.dsl import read_traditional_dda\n",
"chua_text = open(\"chua.dda\").read()\n",
"state = read_traditional_dda(chua_text)\n",
"state"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Syntax trees: Down into the rabbit hole"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Obviously, the output of the internal data structure *state* and the DDA file itself does not differ so much. That is by intention, both look quite pythonic. The state itself is basically a dictionary (mapping) from strings (the left hand sides in the DDA file) to the expressions (their right hand sides). Let's inspect such an expression."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"int(mult(3.5, y), dt, 0)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"state[\"z\"]"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dda.ast.Symbol"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(state[\"z\"])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"int\n",
"(mult(3.5, y), dt, 0)\n"
]
}
],
"source": [
"print(state[\"z\"].head)\n",
"print(state[\"z\"].tail)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What we are actually looking at is the PyDDA-representation of a mathematical expression tree. We can visualize this tree:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"state[\"z\"].draw_graph()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Given this, we can compute the dependencies of all variables in the sytem:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"graph = state.draw_dependency_graph(export_dot=False)\n",
"graph"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Draw the graph with matlotlib\n",
"import networkx as nx\n",
"from networkx.drawing.nx_agraph import graphviz_layout\n",
"pos = graphviz_layout(graph)\n",
"nx.draw(graph, pos=pos)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# draw the graph with graphviz (requires pydot,graphviz)\n",
"from networkx.drawing.nx_pydot import to_pydot\n",
"from graphviz import Source\n",
"nx2dot = lambda graph: Source(to_pydot(graph).to_string())"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nx2dot(graph)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Based on this dependency analysis, one can *linearize* the state, that is, define an ordering how to compute the state numerically:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"vars = state.variable_ordering()"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The evolved variables are: ['int_1', 'int_2', 'z']\n",
"Auxilliary variables are: ['f1', 'f2', 'f3', 'fx', 'mult_10', 'mult_6', 'mult_9', 'sum_1', 'sum_2', 'sum_3', 'sum_4', 'sum_5', 'sum_6', 'sum_7', 'sum_8', 'x', 'x1', 'x2', 'y', 'y1', 'y2']\n"
]
}
],
"source": [
"print(\"The evolved variables are:\", vars.evolved)\n",
"print(\"Auxilliary variables are:\", vars.aux.all)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One sees a number of new variables. They were introduced by *naming* all *intermediate* expressions. What are these intermediates? Let's review again the variable *z*:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"state[\"z\"].draw_graph()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here, the left most child is an intermediate expression, since it computes `mult(3.5, y)`. We can give this intermediate result a concrete name and replace the whole subtree with this name:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"state.name_computing_elements()[\"z\"].draw_graph()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulating a circuit\n",
"\n",
"In the following, we use the C++ code generator to simulate this simple ordinary differential equation:"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"// This code was generated by PyDDA.\n",
"\n",
"#include /* don't forget -lm for linking */\n",
"#include /* for feraisexcept and friends */\n",
"#include /* for signaling NAN */\n",
"#include \n",
"#include \n",
"#include \n",
"#include \n",
"#include