From bbbecb9c740b7840da7e4b773dbbe75cbfb2514b Mon Sep 17 00:00:00 2001
From: Mark Kramer <mak@bu.edu>
Date: Thu, 7 Nov 2024 10:24:23 -0500
Subject: [PATCH] + spike spectra

---
 Analyzing_Rhythms_Lab_3.ipynb          |   6 +-
 Coherence_Lab_Part_1.ipynb             |   2 +-
 Coherence_Lab_Part_2.ipynb             |   2 +-
 Slides/Analyzing_Rhythms_Lecture_3.pdf | Bin 512249 -> 512410 bytes
 docs/Analyzing_Rhythms_Lab_3.html      |   6 +-
 docs/Backpropagation.html              |   2 +-
 docs/HH.html                           |   2 +-
 docs/IF.html                           |   2 +-
 docs/Introduction.html                 |   2 +-
 docs/Perceptron.html                   |   2 +-
 docs/Regression.html                   |   2 +-
 docs/Rhythms_1.html                    |   2 +-
 docs/search.json                       | 109 +++++++++++++++----------
 13 files changed, 80 insertions(+), 59 deletions(-)

diff --git a/Analyzing_Rhythms_Lab_3.ipynb b/Analyzing_Rhythms_Lab_3.ipynb
index 48383e9..5578839 100644
--- a/Analyzing_Rhythms_Lab_3.ipynb
+++ b/Analyzing_Rhythms_Lab_3.ipynb
@@ -106,7 +106,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# Repeat the entire simulation many times, and plot the average spectrum\n",
+    "# Repeat the entire simulation many times, and plot the average autocovariance and spectrum\n",
     "\n",
     "K  = 1000                                       # Number of times to repeat the simulation.\n",
     "lambda_est = np.zeros(K)                        # Vector to store estimate of lambda.\n",
@@ -126,7 +126,7 @@
     "    P[k,:] = Pj                                 # ... and save the result.\n",
     "\n",
     "plt.figure()                                    # Plot it.\n",
-    "plt.plot(lags, np.mean(AC,0))\n",
+    "plt.plot(lags*dt, np.mean(AC,0))\n",
     "plt.xlabel('Lag [s]')\n",
     "plt.ylabel('Autocovariance');\n",
     "\n",
@@ -198,7 +198,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# Repeat the entire simulation many times, and plot the average spectrum"
+    "# Repeat the entire simulation many times, and plot the average autocovariance and spectrum"
    ]
   }
  ],
diff --git a/Coherence_Lab_Part_1.ipynb b/Coherence_Lab_Part_1.ipynb
index 00ff372..4def5b5 100644
--- a/Coherence_Lab_Part_1.ipynb
+++ b/Coherence_Lab_Part_1.ipynb
@@ -124,7 +124,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.12.4"
+   "version": "3.8.18"
   }
  },
  "nbformat": 4,
diff --git a/Coherence_Lab_Part_2.ipynb b/Coherence_Lab_Part_2.ipynb
index 5e079ef..429a9a3 100644
--- a/Coherence_Lab_Part_2.ipynb
+++ b/Coherence_Lab_Part_2.ipynb
@@ -155,7 +155,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.12.4"
+   "version": "3.8.18"
   }
  },
  "nbformat": 4,
diff --git a/Slides/Analyzing_Rhythms_Lecture_3.pdf b/Slides/Analyzing_Rhythms_Lecture_3.pdf
index d8d6ef1ab35ab69ac15ea8d8b04956434ffbe258..7a97817935e322f4f459847c79ecd1fa22212c4f 100644
GIT binary patch
delta 18789
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%0DVE_2_gol3RvIxj$Kk
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
azk8dwxc$8yK{x>b0At`_GBHUgN&XM?bzv9)

delta 18711
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
U%MQd+0ssqO;9;|{NUO^HU$MSPi2wiq

diff --git a/docs/Analyzing_Rhythms_Lab_3.html b/docs/Analyzing_Rhythms_Lab_3.html
index 279a89d..17ec556 100644
--- a/docs/Analyzing_Rhythms_Lab_3.html
+++ b/docs/Analyzing_Rhythms_Lab_3.html
@@ -246,7 +246,7 @@ <h1>Example: a randomly spiking neuron</h1>
 <span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>plt.xlabel(<span class="st">'Frequency [Hz]'</span>)<span class="op">;</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
 </div>
 <div id="cell-7" class="cell">
-<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Repeat the entire simulation many times, and plot the average spectrum</span></span>
+<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Repeat the entire simulation many times, and plot the average autocovariance and spectrum</span></span>
 <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
 <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>K  <span class="op">=</span> <span class="dv">1000</span>                                       <span class="co"># Number of times to repeat the simulation.</span></span>
 <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>lambda_est <span class="op">=</span> np.zeros(K)                        <span class="co"># Vector to store estimate of lambda.</span></span>
@@ -266,7 +266,7 @@ <h1>Example: a randomly spiking neuron</h1>
 <span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>    P[k,:] <span class="op">=</span> Pj                                 <span class="co"># ... and save the result.</span></span>
 <span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a></span>
 <span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>plt.figure()                                    <span class="co"># Plot it.</span></span>
-<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>plt.plot(lags, np.mean(AC,<span class="dv">0</span>))</span>
+<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>plt.plot(lags<span class="op">*</span>dt, np.mean(AC,<span class="dv">0</span>))</span>
 <span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>plt.xlabel(<span class="st">'Lag [s]'</span>)</span>
 <span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>plt.ylabel(<span class="st">'Autocovariance'</span>)<span class="op">;</span></span>
 <span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a></span>
@@ -304,7 +304,7 @@ <h1>Example: a randomly spiking neuron + refractory period</h1>
 <div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Compute the spectrum.</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
 </div>
 <div id="cell-13" class="cell">
-<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Repeat the entire simulation many times, and plot the average spectrum</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
+<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Repeat the entire simulation many times, and plot the average autocovariance and spectrum</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
 </div>
 
 
diff --git a/docs/Backpropagation.html b/docs/Backpropagation.html
index 4bb24c8..334eb66 100644
--- a/docs/Backpropagation.html
+++ b/docs/Backpropagation.html
@@ -228,7 +228,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"options":{"warning":"true","label":"","out-width":"700px","context":"interactive","read-only":"false","classes":"","comment":"","message":"true","output":"true","autorun":"","dpi":72,"out-height":"","fig-width":7,"fig-cap":"","fig-height":5,"results":"markup"},"id":1,"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd"},{"options":{"warning":"true","label":"","out-width":"700px","context":"interactive","read-only":"false","classes":"","comment":"","message":"true","output":"true","autorun":"","dpi":72,"out-height":"","fig-width":7,"fig-cap":"","fig-height":5,"results":"markup"},"id":2,"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/backpropagation_example_data.csv\")\n\n# Extract the variables from the loaded data\nin_true = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nout_true = np.array(df.iloc[:,1])  #Get the values associated with the second column of the dataframe"},{"options":{"warning":"true","label":"","out-width":"700px","context":"interactive","read-only":"false","classes":"","comment":"","message":"true","output":"true","autorun":"","dpi":72,"out-height":"","fig-width":7,"fig-cap":"","fig-height":5,"results":"markup"},"id":3,"code":"print(np.transpose([in_true, out_true]))"},{"options":{"warning":"true","label":"","out-width":"700px","context":"interactive","read-only":"false","classes":"","comment":"","message":"true","output":"true","autorun":"","dpi":72,"out-height":"","fig-width":7,"fig-cap":"","fig-height":5,"results":"markup"},"id":4,"code":"def sigmoid(x):\n    return 1/(1+np.exp(-x))     # Define the sigmoid anonymous function.\n\ndef feedforward(w, s0):         # Define feedforward solution.\n    # ... x1 = activity of first neuron,\n    # ... s1 = output of first neuron,\n    # ... x2 = activity of second neuron,\n    # ... s2 = output of second neuron,\n    # ... out = output of neural network.\n    return out,s1,s2"},{"options":{"warning":"true","label":"","out-width":"700px","context":"interactive","read-only":"false","classes":"","comment":"","message":"true","output":"true","autorun":"","dpi":72,"out-height":"","fig-width":7,"fig-cap":"","fig-height":5,"results":"markup"},"id":5,"code":"w     = [0.5,0.5]                  # Choose initial values for the weights.\nalpha = 0.01                    # Set the learning constant.\n\nK = np.size(in_true);\nresults = np.zeros([K,3])        # Define a variable to hold the results of each iteration.    \n\nfor k in np.arange(K):\n    s0     = in_true[k]          # Define the input,\n    target = out_true[k]         # ... and the target output.\n    \n    #Calculate feedforward solution to get output.\n    \n    #Update the weights.\n    w0 = w[0]; w1 = w[1];\n    w[1] = \"SOMETHING\"\n    w[0] = \"SOMETHING\"\n    \n    # Save the results of this step. --------------------------------------\n    # Here we save the 3 weights, and the neural network output.\n    # results[k,:] = [w[0],w[1],  out]\n\n# Plot the NN weights and error during training \n# plt.clf()\n# plt.plot(results[:,1], label='w1')\n# plt.plot(results[:,0], label='w0')\n# plt.plot(results[:,2]-target, label='error')\n# plt.legend()                       #Include a legend,\n# plt.xlabel('Iteration number');    #... and axis label.\n\n# Print the NN weights\n# print(results[-1,0:2])"}];
+globalThis.qpyodideCellDetails = [{"options":{"message":"true","dpi":72,"warning":"true","out-width":"700px","fig-height":5,"classes":"","fig-cap":"","context":"interactive","output":"true","label":"","autorun":"","out-height":"","comment":"","results":"markup","fig-width":7,"read-only":"false"},"id":1,"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd"},{"options":{"message":"true","dpi":72,"warning":"true","out-width":"700px","fig-height":5,"classes":"","fig-cap":"","context":"interactive","output":"true","label":"","autorun":"","out-height":"","comment":"","results":"markup","fig-width":7,"read-only":"false"},"id":2,"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/backpropagation_example_data.csv\")\n\n# Extract the variables from the loaded data\nin_true = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nout_true = np.array(df.iloc[:,1])  #Get the values associated with the second column of the dataframe"},{"options":{"message":"true","dpi":72,"warning":"true","out-width":"700px","fig-height":5,"classes":"","fig-cap":"","context":"interactive","output":"true","label":"","autorun":"","out-height":"","comment":"","results":"markup","fig-width":7,"read-only":"false"},"id":3,"code":"print(np.transpose([in_true, out_true]))"},{"options":{"message":"true","dpi":72,"warning":"true","out-width":"700px","fig-height":5,"classes":"","fig-cap":"","context":"interactive","output":"true","label":"","autorun":"","out-height":"","comment":"","results":"markup","fig-width":7,"read-only":"false"},"id":4,"code":"def sigmoid(x):\n    return 1/(1+np.exp(-x))     # Define the sigmoid anonymous function.\n\ndef feedforward(w, s0):         # Define feedforward solution.\n    # ... x1 = activity of first neuron,\n    # ... s1 = output of first neuron,\n    # ... x2 = activity of second neuron,\n    # ... s2 = output of second neuron,\n    # ... out = output of neural network.\n    return out,s1,s2"},{"options":{"message":"true","dpi":72,"warning":"true","out-width":"700px","fig-height":5,"classes":"","fig-cap":"","context":"interactive","output":"true","label":"","autorun":"","out-height":"","comment":"","results":"markup","fig-width":7,"read-only":"false"},"id":5,"code":"w     = [0.5,0.5]                  # Choose initial values for the weights.\nalpha = 0.01                    # Set the learning constant.\n\nK = np.size(in_true);\nresults = np.zeros([K,3])        # Define a variable to hold the results of each iteration.    \n\nfor k in np.arange(K):\n    s0     = in_true[k]          # Define the input,\n    target = out_true[k]         # ... and the target output.\n    \n    #Calculate feedforward solution to get output.\n    \n    #Update the weights.\n    w0 = w[0]; w1 = w[1];\n    w[1] = \"SOMETHING\"\n    w[0] = \"SOMETHING\"\n    \n    # Save the results of this step. --------------------------------------\n    # Here we save the 3 weights, and the neural network output.\n    # results[k,:] = [w[0],w[1],  out]\n\n# Plot the NN weights and error during training \n# plt.clf()\n# plt.plot(results[:,1], label='w1')\n# plt.plot(results[:,0], label='w0')\n# plt.plot(results[:,2]-target, label='error')\n# plt.legend()                       #Include a legend,\n# plt.xlabel('Iteration number');    #... and axis label.\n\n# Print the NN weights\n# print(results[-1,0:2])"}];
 
 
 </script>
diff --git a/docs/HH.html b/docs/HH.html
index a49949d..8088d37 100644
--- a/docs/HH.html
+++ b/docs/HH.html
@@ -228,7 +228,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"id":1,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"import numpy as np\nimport matplotlib.pyplot as plt"},{"id":2,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"import requests\nurl = \"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/HH_functions.py\"\nresponse = requests.get(url)\nexec(response.text)"},{"id":3,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"I0 = 0"},{"id":4,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"T0 = 100"},{"id":5,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"[V,m,h,n,t]=HH(I0,T0)"},{"id":6,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"I0 = 10"},{"id":7,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"[V,m,h,n,t] = HH(I0,T0)"},{"id":8,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"plt.figure()\nplt.plot(t,V,'k')\nplt.xlim([35, 55])\nplt.ylabel('V [mV]')\nplt.show()"},{"id":9,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"plt.figure()\nplt.plot(t,m,'r', label='m')\nplt.xlim([35, 55])\nplt.show()"},{"id":10,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"plt.figure()\nplt.plot(t,m,'r', label='m')\nplt.plot(t,h,'b', label='h')\nplt.plot(t,n,'g', label='n')\nplt.xlim([35, 55])\nplt.xlabel('Time [ms]');\nplt.legend();\nplt.show()"},{"id":11,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"plt.figure()\nax1 = plt.subplot(211);                 # Define axis for 1st subplot,\nax2 = plt.subplot(212, sharex=ax1);     # ... and link axis of 2nd subplot to the 1st.\nax1.plot(t,V,'k')                   # Plot the voltage in the first subplot,\nplt.xlim([35, 55])\nax2.plot(t,m,'r', label='m')        # ... and the gating variables in the other subplot.\nax2.plot(t,h,'b', label='h')\nax2.plot(t,n,'g', label='n')\nplt.xlabel('Time [ms]')\nplt.legend()\nplt.show()"},{"id":12,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"plt.figure()\nplt.plot(t,V,'k')                   #Plot the voltage,\nplt.xlim([35, 55])\nplt.ylabel('V [mV]')                #... with y-axis labeled.\nplt.show()"},{"id":13,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"gNa0 = 120\n# gNa  = ???                    #Sodium conductance\ngK0  = 36\n# gK   = ???                    #Potassium conductance\ngL0  = 0.3\n# gL   = ???                    #Leak conductance"},{"id":14,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"plt.figure()\nplt.plot(t,gNa,'m', label='gNa')#... and plot the sodium conductance,\nplt.plot(t,gK, 'g', label='gK') #... and plot the potassium conductance,\nplt.plot(t,gL, 'k', label='gL') #... and plot the leak conductance.\nplt.xlim([35, 55])\nplt.xlabel('Time [ms]')             #... label the x-axis.\nplt.ylabel('mS/cm^2')               #... and label the y-axis.\nplt.legend()                        #... make a legend.\nplt.show()"},{"id":15,"options":{"output":"true","results":"markup","read-only":"false","label":"","fig-width":7,"context":"interactive","autorun":"","message":"true","comment":"","dpi":72,"classes":"","warning":"true","out-width":"700px","out-height":"","fig-cap":"","fig-height":5},"code":"gNa0 = 120\nENa  = 115\n# INa  = ??? Sodium current.\ngK0  = 36\nEK   =-12\n# IK   = ??? Potassium current.\ngL0  = 0.3\nEL   = 10.6;\n# IL   = ??? Leak current.\n\nplt.figure()\nplt.plot(t,INa,'m', label='INa')   #... and plot the sodium current,\nplt.plot(t,IK, 'g', label='IK')    #... and plot the potassium current,\nplt.plot(t,IL, 'k', label='IL')    #... and plot the leak current.\nplt.xlim([35, 55])\nplt.xlabel('Time [ms]')            #... label the x-axis.\nplt.ylabel('mA/cm^2')              #... and label the y-axis.\nplt.legend()                      #... make a legend.\nplt.show()"}];
+globalThis.qpyodideCellDetails = [{"id":1,"code":"import numpy as np\nimport matplotlib.pyplot as plt","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":2,"code":"import requests\nurl = \"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/HH_functions.py\"\nresponse = requests.get(url)\nexec(response.text)","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":3,"code":"I0 = 0","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":4,"code":"T0 = 100","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":5,"code":"[V,m,h,n,t]=HH(I0,T0)","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":6,"code":"I0 = 10","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":7,"code":"[V,m,h,n,t] = HH(I0,T0)","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":8,"code":"plt.figure()\nplt.plot(t,V,'k')\nplt.xlim([35, 55])\nplt.ylabel('V [mV]')\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":9,"code":"plt.figure()\nplt.plot(t,m,'r', label='m')\nplt.xlim([35, 55])\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":10,"code":"plt.figure()\nplt.plot(t,m,'r', label='m')\nplt.plot(t,h,'b', label='h')\nplt.plot(t,n,'g', label='n')\nplt.xlim([35, 55])\nplt.xlabel('Time [ms]');\nplt.legend();\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":11,"code":"plt.figure()\nax1 = plt.subplot(211);                 # Define axis for 1st subplot,\nax2 = plt.subplot(212, sharex=ax1);     # ... and link axis of 2nd subplot to the 1st.\nax1.plot(t,V,'k')                   # Plot the voltage in the first subplot,\nplt.xlim([35, 55])\nax2.plot(t,m,'r', label='m')        # ... and the gating variables in the other subplot.\nax2.plot(t,h,'b', label='h')\nax2.plot(t,n,'g', label='n')\nplt.xlabel('Time [ms]')\nplt.legend()\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":12,"code":"plt.figure()\nplt.plot(t,V,'k')                   #Plot the voltage,\nplt.xlim([35, 55])\nplt.ylabel('V [mV]')                #... with y-axis labeled.\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":13,"code":"gNa0 = 120\n# gNa  = ???                    #Sodium conductance\ngK0  = 36\n# gK   = ???                    #Potassium conductance\ngL0  = 0.3\n# gL   = ???                    #Leak conductance","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":14,"code":"plt.figure()\nplt.plot(t,gNa,'m', label='gNa')#... and plot the sodium conductance,\nplt.plot(t,gK, 'g', label='gK') #... and plot the potassium conductance,\nplt.plot(t,gL, 'k', label='gL') #... and plot the leak conductance.\nplt.xlim([35, 55])\nplt.xlabel('Time [ms]')             #... label the x-axis.\nplt.ylabel('mS/cm^2')               #... and label the y-axis.\nplt.legend()                        #... make a legend.\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}},{"id":15,"code":"gNa0 = 120\nENa  = 115\n# INa  = ??? Sodium current.\ngK0  = 36\nEK   =-12\n# IK   = ??? Potassium current.\ngL0  = 0.3\nEL   = 10.6;\n# IL   = ??? Leak current.\n\nplt.figure()\nplt.plot(t,INa,'m', label='INa')   #... and plot the sodium current,\nplt.plot(t,IK, 'g', label='IK')    #... and plot the potassium current,\nplt.plot(t,IL, 'k', label='IL')    #... and plot the leak current.\nplt.xlim([35, 55])\nplt.xlabel('Time [ms]')            #... label the x-axis.\nplt.ylabel('mA/cm^2')              #... and label the y-axis.\nplt.legend()                      #... make a legend.\nplt.show()","options":{"out-width":"700px","fig-width":7,"context":"interactive","output":"true","classes":"","results":"markup","warning":"true","fig-cap":"","read-only":"false","comment":"","label":"","fig-height":5,"dpi":72,"message":"true","out-height":"","autorun":""}}];
 
 
 </script>
diff --git a/docs/IF.html b/docs/IF.html
index 25bf63e..6135342 100644
--- a/docs/IF.html
+++ b/docs/IF.html
@@ -228,7 +228,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"id":1,"code":"import numpy as np\nimport matplotlib.pyplot as plt","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":2,"code":"C=1.0\nI=1.0","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":3,"code":"dt=0.01","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":4,"code":"V = np.zeros([1000,1])\nnp.shape(V)","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":5,"code":"V[0]=0.2","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":6,"code":"for k in range(1,999):\n    V[k+1] = V[k] + dt*(I/C)","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":7,"code":"plt.figure()\nplt.plot(V)\nplt.show()","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":8,"code":"t = np.arange(0,len(V))*dt","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":9,"code":"plt.figure()\nplt.plot(t,V)\nplt.xlabel('Time [s]')\nplt.ylabel('V')\nplt.show()","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":10,"code":"import numpy as np\nimport matplotlib.pyplot as plt\n\nI   = 1                           #Set the parameter I.\nC   = 1                           #Set the parameter C.\ndt  = 0.01                        #Set the timestep.\nV   = np.zeros([1000,1])             #Initialize V.\nV[0]= 0.2;                        #Set the initial value of V.\n\nfor k in range(1,999):            #March forward in time,\n    V[k+1] = V[k] + dt*(I/C)      #... updating V along the way.\n\nt = np.arange(0,len(V))*dt        #Define the time axis.\n\nplt.figure()\nplt.plot(t,V)                         #Plot the results.\nplt.xlabel('Time [s]')\nplt.ylabel('Voltage [mV]')\nplt.show()","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":11,"code":"Vth = 1;        #Define the voltage threshold.\nVreset = 0;     #Define the reset voltage.\n\nfor k in range(1,999):            #March forward in time,\n    V[k+1] = V[k] + dt*(I/C)      #Update the voltage,\n    ### ADD SOMETHING HERE??? --------------------------","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}},{"id":12,"code":"### ADD YOUR CODE!","options":{"label":"","classes":"","fig-cap":"","dpi":72,"comment":"","output":"true","autorun":"","context":"interactive","read-only":"false","results":"markup","fig-width":7,"out-height":"","warning":"true","message":"true","out-width":"700px","fig-height":5}}];
+globalThis.qpyodideCellDetails = [{"code":"import numpy as np\nimport matplotlib.pyplot as plt","id":1,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"C=1.0\nI=1.0","id":2,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"dt=0.01","id":3,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"V = np.zeros([1000,1])\nnp.shape(V)","id":4,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"V[0]=0.2","id":5,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"for k in range(1,999):\n    V[k+1] = V[k] + dt*(I/C)","id":6,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"plt.figure()\nplt.plot(V)\nplt.show()","id":7,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"t = np.arange(0,len(V))*dt","id":8,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"plt.figure()\nplt.plot(t,V)\nplt.xlabel('Time [s]')\nplt.ylabel('V')\nplt.show()","id":9,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"import numpy as np\nimport matplotlib.pyplot as plt\n\nI   = 1                           #Set the parameter I.\nC   = 1                           #Set the parameter C.\ndt  = 0.01                        #Set the timestep.\nV   = np.zeros([1000,1])             #Initialize V.\nV[0]= 0.2;                        #Set the initial value of V.\n\nfor k in range(1,999):            #March forward in time,\n    V[k+1] = V[k] + dt*(I/C)      #... updating V along the way.\n\nt = np.arange(0,len(V))*dt        #Define the time axis.\n\nplt.figure()\nplt.plot(t,V)                         #Plot the results.\nplt.xlabel('Time [s]')\nplt.ylabel('Voltage [mV]')\nplt.show()","id":10,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"Vth = 1;        #Define the voltage threshold.\nVreset = 0;     #Define the reset voltage.\n\nfor k in range(1,999):            #March forward in time,\n    V[k+1] = V[k] + dt*(I/C)      #Update the voltage,\n    ### ADD SOMETHING HERE??? --------------------------","id":11,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}},{"code":"### ADD YOUR CODE!","id":12,"options":{"results":"markup","output":"true","autorun":"","message":"true","context":"interactive","comment":"","fig-cap":"","read-only":"false","fig-width":7,"fig-height":5,"warning":"true","classes":"","out-width":"700px","dpi":72,"out-height":"","label":""}}];
 
 
 </script>
diff --git a/docs/Introduction.html b/docs/Introduction.html
index 5d6aa7e..601cd13 100644
--- a/docs/Introduction.html
+++ b/docs/Introduction.html
@@ -262,7 +262,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\ndf = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/Rhythms_1.csv\")\nd = np.array(df.iloc[:,0])\nt = np.array(df.iloc[:,1])\n\n# Print useful information about the data.\nprint(\"Sampling frequency is \" + str( 1/(t[2]-t[1]))  + ' Hz.')\nprint(\"Total duration of recording is \" + str(t[-1]) + ' s.')\nprint(\"Dimensions of data are \" + str(np.shape(d)) + ' data points.')\n\n# Choose an initial interval of time, from onset to 5 s,\ninitial_time_interval = t < 5        \n\n# ... and plot it.\nplt.plot(t[initial_time_interval], d[initial_time_interval])\nplt.xlabel('Time [s]')\nplt.ylabel('Data')\nplt.title('Initial interval of data');\nplt.show()","id":1,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"4+9","id":2,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"4/3","id":3,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"4/10**2","id":4,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport math","id":5,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"np.sin(2*np.pi)","id":6,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"math.atan(2*np.pi)","id":7,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\na = np.array([[1, 2, 3, 4]])\nprint(a)","id":8,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"a = np.array( [[1, 2, 3, 4]] )\nprint( a * 3 )\nprint( 4 * a )\nprint( a + 1 )","id":9,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\na = np.array([1,2,3,4])\na * a","id":10,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\na = 2\nb = np.array( [[0, 4, 7, 6]] )\nc = np.array( [[1, 5, 6, 8]] )\n\nprint( b * c )\nprint( b / c + a)\nprint( np.multiply( b, c ))","id":11,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"a = np.array([[1,2,3,4]])\nprint(a.shape)\nprint(np.shape(a))","id":12,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\n\np = np.array( [[1,2,3],[4,5,6]] )","id":13,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print( p )","id":14,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print( p + 2 )\nprint( 2 * p )\nprint( p * p )","id":15,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\na = np.array( [1, 2, 3, 4, 5] )\nb = np.array( [6, 7, 8, 9, 10] )","id":16,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print( \"a[1] = \" + str(a[1]) )\nprint( \"b[1] = \" + str(b[1]) )","id":17,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"c = np.array([a,b])\nprint( \"c = \\n\" + str(c) )    # \\n is a newline, or carriage return, which makes the printed matrix lineup better ","id":18,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print( \"shape of c = \" + str( np.shape(c) ) )","id":19,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print( \"c[0,3] = \" + str( c[0,3] ) )","id":20,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print( \"c[0,:] = \" + str( c[0,:] ) )\nprint( \"2nd through 4th columns of the first row are c[0,1:4] = \" + str(c[0,1:4]) )","id":21,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print(\"c[0, :4] = \" + str( c[0,:4]))\nprint(\"c[0, 1:] = \" + str( c[0,1:]))","id":22,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"c[0,::2]","id":23,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"a = np.arange(1,10)    # this creates a vector of increasing values from 1 to 9\na = 2*a \n\nprint( \"a = \" + str(a) )","id":24,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"a[a > 10]","id":25,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"lgIdx = a > 10\nlgIdx","id":26,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"a[lgIdx]","id":27,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"lgIdx.nonzero()","id":28,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"a[ (a > 10).nonzero() ]","id":29,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print(\"a = \" + str(a))\na[a > 10] = 100\nprint(\"a = \" + str(a))","id":30,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"b = np.array([[1,2,3],[4,5,6],[7,8,9]])\nprint( \"b = \\n\" + str(b) )\nprint( \" b > 5 is \\n\" + str(b > 5) )\nprint(\" b[b>5] is an array: \" + str(b[b>5]) )","id":31,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\n\nx = np.linspace(0,10,11)   \nprint( \"x = \" + str(x) )\n\n#   The above line constructs a vector that starts at 0, ends at 10, and\n#   has 11 entries (takes steps of size 1 from 0 to 10). Let\n\ny = np.sin(x)\nprint( \"y = \" + str(y) )","id":32,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import matplotlib.pyplot as plt\nx = ([1, 2, 3, 4])\ny = x\nplt.figure()\nplt.plot(x,y) \nplt.show()          # this is the plotting equivalent of print()","id":33,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"x = np.linspace(0,10,11)   \ny = np.sin(x)\n\nplt.figure()\nplt.plot(x, y)\nplt.show()","id":34,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nx = np.linspace(0,10, 101)\nprint(x)","id":35,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"y = np.sin(x)\nplt.figure()\nplt.plot(x,y,'k')   # the 'k' we've added makes the curve black instead of blue\nplt.show()","id":36,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nx = np.linspace(0,10, 101)\nz = np.cos(x)","id":37,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import matplotlib.pyplot as plt\nplt.figure()\nplt.plot(x,z)\nplt.show()","id":38,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"y = np.sin(x)\nplt.figure()\nplt.plot(x,z)                     # plot z vs x.\nplt.plot(x,y,'r')                 # plot y vs x in red\nplt.show()","id":39,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"plt.figure()\nplt.plot(x,z)                     # plot z vs x\nplt.plot(x,y,'r')                 # plot y vs x in red\nplt.xlabel('x')                   # x-axis label\nplt.ylabel('y or z')              # y-axis label\nplt.title('y vs x and z vs x')    # title\nplt.legend(('y','z'))             # make a legend labeling each line\nplt.show()","id":40,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"plt.figure()\nplt.plot(x,y, label='y')     # sometimes it is easier to name a trace within the plot() call\nplt.plot(x,z, label='z')     # notice without a color matplotlib will assign one\nplt.xlabel('x', fontsize=14)\nplt.ylabel('y', fontsize=14)\nplt.title('y vs x', fontsize=18)\nplt.legend(fontsize=12)\nplt.show()","id":41,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\n\nprint(\"a Gaussian random number (mean=0, variance=1): \" + str( np.random.randn() ))\n\n# a uniform random number on [0,1)\nprint(\"a uniform random number from [0,1): \" + str(np.random.rand()))","id":42,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"r = np.random.randn(1000)","id":43,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import matplotlib.pyplot as plt\nplt.figure()\nplt.hist(r)\nplt.show()","id":44,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nimport matplotlib.pyplot as plt\n\nx = np.arange(0,10,0.1) # Define a vector x that ranges from 0 to 9.9 with step 0.1.\nk = 1                # Fix k=1,\ny = np.sin(x + k*np.pi/4)  # ... and define y at this k.\n\nplt.figure()               # Make a new figure,\nplt.plot(x,y)              # ... and plot y versus x.\n\nk = 2                # Let's repeat this, for k=2,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nk = 3                      # Let's repeat this, for k=3,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nk = 4                      # Let's repeat this, for k=4,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nk = 5                      # Let's repeat this, for k=5,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nplt.show()","id":45,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"x = np.arange(0,10,0.1)     #First, define the vector x.","id":46,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"plt.figure()\nfor k in range(1,6):               \n    y = np.sin(x + k*np.pi/4) #Define y (note the variable 'k' in sin), also note we have indented here!\n    plt.plot(x,y)             #Plot y versus x\n     \n# no indentation now, so this code follows the loop\nplt.show()","id":47,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"def my_square_function(x, c):\n    \"\"\"Square a vector and add a constant.\n\n    Arguments:\n    x -- vector to square\n    c -- constant to add to the square of x\n    \n    Returns:\n    x*x + c\n    \"\"\"\n    \n    return x * x + c","id":48,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nv = np.linspace(0.,10.,11)\nb = 2.5\n\n# Now let's run the code,\nv2 = my_square_function(v, b)\nprint(\"v = \" + str(v))\nprint(\"v*v+2.5 = \" + str(v2))","id":49,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import pandas as pd","id":50,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/Rhythms_1.csv\")\ndf.info()","id":51,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"print(df)","id":52,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nd = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nt = np.array(df.iloc[:,1])  #Get the values associated with the first column of the dataframe","id":53,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import matplotlib.pyplot as plt\n\n# Choose a subset to plot\nt = t[0:500]\nd = d[0:500]\n\nplt.figure()\nplt.plot(t, d)\nplt.title('My plot')\nplt.xlabel('Time [s]')\nplt.ylabel('Voltage [mV]')\nplt.show()","id":54,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt","id":55,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"mu = np.mean(d)\nsd = np.std(d)","id":56,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"samps = np.random.normal(mu, sd, 500)","id":57,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}},{"code":"plt.figure()\nplt.hist(samps)\nplt.hist(d)\nplt.show()","id":58,"options":{"label":"","comment":"","message":"true","classes":"","warning":"true","results":"markup","output":"true","context":"interactive","fig-width":7,"read-only":"false","autorun":"","dpi":72,"fig-height":5,"out-height":"","fig-cap":"","out-width":"700px"}}];
+globalThis.qpyodideCellDetails = [{"id":1,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\ndf = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/Rhythms_1.csv\")\nd = np.array(df.iloc[:,0])\nt = np.array(df.iloc[:,1])\n\n# Print useful information about the data.\nprint(\"Sampling frequency is \" + str( 1/(t[2]-t[1]))  + ' Hz.')\nprint(\"Total duration of recording is \" + str(t[-1]) + ' s.')\nprint(\"Dimensions of data are \" + str(np.shape(d)) + ' data points.')\n\n# Choose an initial interval of time, from onset to 5 s,\ninitial_time_interval = t < 5        \n\n# ... and plot it.\nplt.plot(t[initial_time_interval], d[initial_time_interval])\nplt.xlabel('Time [s]')\nplt.ylabel('Data')\nplt.title('Initial interval of data');\nplt.show()"},{"id":2,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"4+9"},{"id":3,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"4/3"},{"id":4,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"4/10**2"},{"id":5,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport math"},{"id":6,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"np.sin(2*np.pi)"},{"id":7,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"math.atan(2*np.pi)"},{"id":8,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\na = np.array([[1, 2, 3, 4]])\nprint(a)"},{"id":9,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"a = np.array( [[1, 2, 3, 4]] )\nprint( a * 3 )\nprint( 4 * a )\nprint( a + 1 )"},{"id":10,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\na = np.array([1,2,3,4])\na * a"},{"id":11,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\na = 2\nb = np.array( [[0, 4, 7, 6]] )\nc = np.array( [[1, 5, 6, 8]] )\n\nprint( b * c )\nprint( b / c + a)\nprint( np.multiply( b, c ))"},{"id":12,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"a = np.array([[1,2,3,4]])\nprint(a.shape)\nprint(np.shape(a))"},{"id":13,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\n\np = np.array( [[1,2,3],[4,5,6]] )"},{"id":14,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print( p )"},{"id":15,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print( p + 2 )\nprint( 2 * p )\nprint( p * p )"},{"id":16,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\na = np.array( [1, 2, 3, 4, 5] )\nb = np.array( [6, 7, 8, 9, 10] )"},{"id":17,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print( \"a[1] = \" + str(a[1]) )\nprint( \"b[1] = \" + str(b[1]) )"},{"id":18,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"c = np.array([a,b])\nprint( \"c = \\n\" + str(c) )    # \\n is a newline, or carriage return, which makes the printed matrix lineup better "},{"id":19,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print( \"shape of c = \" + str( np.shape(c) ) )"},{"id":20,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print( \"c[0,3] = \" + str( c[0,3] ) )"},{"id":21,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print( \"c[0,:] = \" + str( c[0,:] ) )\nprint( \"2nd through 4th columns of the first row are c[0,1:4] = \" + str(c[0,1:4]) )"},{"id":22,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print(\"c[0, :4] = \" + str( c[0,:4]))\nprint(\"c[0, 1:] = \" + str( c[0,1:]))"},{"id":23,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"c[0,::2]"},{"id":24,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"a = np.arange(1,10)    # this creates a vector of increasing values from 1 to 9\na = 2*a \n\nprint( \"a = \" + str(a) )"},{"id":25,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"a[a > 10]"},{"id":26,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"lgIdx = a > 10\nlgIdx"},{"id":27,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"a[lgIdx]"},{"id":28,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"lgIdx.nonzero()"},{"id":29,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"a[ (a > 10).nonzero() ]"},{"id":30,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print(\"a = \" + str(a))\na[a > 10] = 100\nprint(\"a = \" + str(a))"},{"id":31,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"b = np.array([[1,2,3],[4,5,6],[7,8,9]])\nprint( \"b = \\n\" + str(b) )\nprint( \" b > 5 is \\n\" + str(b > 5) )\nprint(\" b[b>5] is an array: \" + str(b[b>5]) )"},{"id":32,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\n\nx = np.linspace(0,10,11)   \nprint( \"x = \" + str(x) )\n\n#   The above line constructs a vector that starts at 0, ends at 10, and\n#   has 11 entries (takes steps of size 1 from 0 to 10). Let\n\ny = np.sin(x)\nprint( \"y = \" + str(y) )"},{"id":33,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import matplotlib.pyplot as plt\nx = ([1, 2, 3, 4])\ny = x\nplt.figure()\nplt.plot(x,y) \nplt.show()          # this is the plotting equivalent of print()"},{"id":34,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"x = np.linspace(0,10,11)   \ny = np.sin(x)\n\nplt.figure()\nplt.plot(x, y)\nplt.show()"},{"id":35,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nx = np.linspace(0,10, 101)\nprint(x)"},{"id":36,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"y = np.sin(x)\nplt.figure()\nplt.plot(x,y,'k')   # the 'k' we've added makes the curve black instead of blue\nplt.show()"},{"id":37,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nx = np.linspace(0,10, 101)\nz = np.cos(x)"},{"id":38,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import matplotlib.pyplot as plt\nplt.figure()\nplt.plot(x,z)\nplt.show()"},{"id":39,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"y = np.sin(x)\nplt.figure()\nplt.plot(x,z)                     # plot z vs x.\nplt.plot(x,y,'r')                 # plot y vs x in red\nplt.show()"},{"id":40,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"plt.figure()\nplt.plot(x,z)                     # plot z vs x\nplt.plot(x,y,'r')                 # plot y vs x in red\nplt.xlabel('x')                   # x-axis label\nplt.ylabel('y or z')              # y-axis label\nplt.title('y vs x and z vs x')    # title\nplt.legend(('y','z'))             # make a legend labeling each line\nplt.show()"},{"id":41,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"plt.figure()\nplt.plot(x,y, label='y')     # sometimes it is easier to name a trace within the plot() call\nplt.plot(x,z, label='z')     # notice without a color matplotlib will assign one\nplt.xlabel('x', fontsize=14)\nplt.ylabel('y', fontsize=14)\nplt.title('y vs x', fontsize=18)\nplt.legend(fontsize=12)\nplt.show()"},{"id":42,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\n\nprint(\"a Gaussian random number (mean=0, variance=1): \" + str( np.random.randn() ))\n\n# a uniform random number on [0,1)\nprint(\"a uniform random number from [0,1): \" + str(np.random.rand()))"},{"id":43,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"r = np.random.randn(1000)"},{"id":44,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import matplotlib.pyplot as plt\nplt.figure()\nplt.hist(r)\nplt.show()"},{"id":45,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nimport matplotlib.pyplot as plt\n\nx = np.arange(0,10,0.1) # Define a vector x that ranges from 0 to 9.9 with step 0.1.\nk = 1                # Fix k=1,\ny = np.sin(x + k*np.pi/4)  # ... and define y at this k.\n\nplt.figure()               # Make a new figure,\nplt.plot(x,y)              # ... and plot y versus x.\n\nk = 2                # Let's repeat this, for k=2,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nk = 3                      # Let's repeat this, for k=3,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nk = 4                      # Let's repeat this, for k=4,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nk = 5                      # Let's repeat this, for k=5,\ny = np.sin(x + k*np.pi/4)  # ... and redefine y at this k,\nplt.plot(x,y)              # ... and plot it.\n\nplt.show()"},{"id":46,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"x = np.arange(0,10,0.1)     #First, define the vector x."},{"id":47,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"plt.figure()\nfor k in range(1,6):               \n    y = np.sin(x + k*np.pi/4) #Define y (note the variable 'k' in sin), also note we have indented here!\n    plt.plot(x,y)             #Plot y versus x\n     \n# no indentation now, so this code follows the loop\nplt.show()"},{"id":48,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"def my_square_function(x, c):\n    \"\"\"Square a vector and add a constant.\n\n    Arguments:\n    x -- vector to square\n    c -- constant to add to the square of x\n    \n    Returns:\n    x*x + c\n    \"\"\"\n    \n    return x * x + c"},{"id":49,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nv = np.linspace(0.,10.,11)\nb = 2.5\n\n# Now let's run the code,\nv2 = my_square_function(v, b)\nprint(\"v = \" + str(v))\nprint(\"v*v+2.5 = \" + str(v2))"},{"id":50,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import pandas as pd"},{"id":51,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/Rhythms_1.csv\")\ndf.info()"},{"id":52,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"print(df)"},{"id":53,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nd = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nt = np.array(df.iloc[:,1])  #Get the values associated with the first column of the dataframe"},{"id":54,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import matplotlib.pyplot as plt\n\n# Choose a subset to plot\nt = t[0:500]\nd = d[0:500]\n\nplt.figure()\nplt.plot(t, d)\nplt.title('My plot')\nplt.xlabel('Time [s]')\nplt.ylabel('Voltage [mV]')\nplt.show()"},{"id":55,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt"},{"id":56,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"mu = np.mean(d)\nsd = np.std(d)"},{"id":57,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"samps = np.random.normal(mu, sd, 500)"},{"id":58,"options":{"dpi":72,"read-only":"false","context":"interactive","message":"true","comment":"","fig-height":5,"autorun":"","label":"","results":"markup","out-width":"700px","out-height":"","classes":"","fig-cap":"","warning":"true","fig-width":7,"output":"true"},"code":"plt.figure()\nplt.hist(samps)\nplt.hist(d)\nplt.show()"}];
 
 
 </script>
diff --git a/docs/Perceptron.html b/docs/Perceptron.html
index 18c73fe..76e265f 100644
--- a/docs/Perceptron.html
+++ b/docs/Perceptron.html
@@ -228,7 +228,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"id":1,"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport time","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":2,"code":"def my_perceptron(input1, input2, w1, w2, theta):\n    print(\"Do something!\")\n    # Define the activity of the perceptron, x. \n    # Apply a binary threshold.","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":3,"code":"my_perceptron(1,0,0.5,-0.5,0)","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":4,"code":"def known_answer(slope, intercept, x, y):\n    print(\"Do something!\")\n    #Determine yline\n    #Determine if y is above yline","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":5,"code":"x,y       = 0.7,3\nslope     = 2\nintercept = 1\ncorrect_answer = known_answer(slope, intercept, x, y)\nprint(correct_answer)","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":6,"code":"def feedforward(x, y, wx, wy, wb):\n    print(\"Do something!\")\n    # Fix the bias.\n    # Define the activity of the neuron, activity.\n    # Apply the binary threshold.","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":7,"code":"x,y      = 0.7,3\nwx,wy,wb = 3*[0.5]\nperceptron_guess = feedforward(x, y, wx, wy, wb)\nprint(perceptron_guess)","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":8,"code":"error = 'SOMETHING?'\nprint(error)","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":9,"code":"learning_constant = 0.01","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":10,"code":"wx = \"SOMETHING\"\nwy = \"SOMETHING\"\nwb = \"SOMETHING\"\nprint(wx)","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}},{"id":11,"code":"slope     = 2;                      # Define the line with slope, \nintercept = 1;                      # ... and intercept.\n\nwx,wy,wb = 3*[0.5];                 # Choose initial values for the perceptron's weights\n\nlearning_constant = 0.01;           # And, set the learning constant.\n\nestimated_slope = np.zeros(2000)    # Variables to hold the perceptron estimates.\nestimated_intercept = np.zeros(2000)\n\nfor k in np.arange(2000):           # For 2000 iteractions,\n    x = np.random.randn(1);         # Choose a random (x,y) point in the plane\n    y = np.random.randn(1);\n                                    # Step 1: Calculate known answer.\n    \n                                    # Step 2. Ask perceptron to guess an answer.\n    \n                                    # Step 3. Compute the error.\n    \n                                    # Step 4. Adjust weights according to error.\n     \n    estimated_slope[k] = -wx/wy;    # Compute estimated slope from perceptron.\n    estimated_intercept[k] = -wb/wy;# Compute estimated intercept from perceptron.\n\n# Display the results! ------------------------------------------------------------------------\nx_range = np.linspace(-2,2,100);                  # For a range of x-values,\nfig, ax = plt.subplots()\nax.plot(x_range, slope*x_range+intercept, 'k')    # ... plot the true line,\n\nfor k in range(1,2000,100):                       # ... and plot some intermediate perceptron guess\n     ax.plot(x_range, estimated_slope[k]*x_range+estimated_intercept[k], 'r', alpha=0.25)\n                                                  # ... and plot the last perceptron guess\nplt.xlabel('x')\nplt.title('Known answer (black), Perceptron final guess (blue)')\nplt.show()","options":{"context":"interactive","output":"true","read-only":"false","results":"markup","out-height":"","label":"","dpi":72,"message":"true","fig-width":7,"fig-cap":"","autorun":"","classes":"","fig-height":5,"out-width":"700px","comment":"","warning":"true"}}];
+globalThis.qpyodideCellDetails = [{"code":"import numpy as np\nimport matplotlib.pyplot as plt\nimport time","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":1},{"code":"def my_perceptron(input1, input2, w1, w2, theta):\n    print(\"Do something!\")\n    # Define the activity of the perceptron, x. \n    # Apply a binary threshold.","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":2},{"code":"my_perceptron(1,0,0.5,-0.5,0)","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":3},{"code":"def known_answer(slope, intercept, x, y):\n    print(\"Do something!\")\n    #Determine yline\n    #Determine if y is above yline","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":4},{"code":"x,y       = 0.7,3\nslope     = 2\nintercept = 1\ncorrect_answer = known_answer(slope, intercept, x, y)\nprint(correct_answer)","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":5},{"code":"def feedforward(x, y, wx, wy, wb):\n    print(\"Do something!\")\n    # Fix the bias.\n    # Define the activity of the neuron, activity.\n    # Apply the binary threshold.","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":6},{"code":"x,y      = 0.7,3\nwx,wy,wb = 3*[0.5]\nperceptron_guess = feedforward(x, y, wx, wy, wb)\nprint(perceptron_guess)","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":7},{"code":"error = 'SOMETHING?'\nprint(error)","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":8},{"code":"learning_constant = 0.01","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":9},{"code":"wx = \"SOMETHING\"\nwy = \"SOMETHING\"\nwb = \"SOMETHING\"\nprint(wx)","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":10},{"code":"slope     = 2;                      # Define the line with slope, \nintercept = 1;                      # ... and intercept.\n\nwx,wy,wb = 3*[0.5];                 # Choose initial values for the perceptron's weights\n\nlearning_constant = 0.01;           # And, set the learning constant.\n\nestimated_slope = np.zeros(2000)    # Variables to hold the perceptron estimates.\nestimated_intercept = np.zeros(2000)\n\nfor k in np.arange(2000):           # For 2000 iteractions,\n    x = np.random.randn(1);         # Choose a random (x,y) point in the plane\n    y = np.random.randn(1);\n                                    # Step 1: Calculate known answer.\n    \n                                    # Step 2. Ask perceptron to guess an answer.\n    \n                                    # Step 3. Compute the error.\n    \n                                    # Step 4. Adjust weights according to error.\n     \n    estimated_slope[k] = -wx/wy;    # Compute estimated slope from perceptron.\n    estimated_intercept[k] = -wb/wy;# Compute estimated intercept from perceptron.\n\n# Display the results! ------------------------------------------------------------------------\nx_range = np.linspace(-2,2,100);                  # For a range of x-values,\nfig, ax = plt.subplots()\nax.plot(x_range, slope*x_range+intercept, 'k')    # ... plot the true line,\n\nfor k in range(1,2000,100):                       # ... and plot some intermediate perceptron guess\n     ax.plot(x_range, estimated_slope[k]*x_range+estimated_intercept[k], 'r', alpha=0.25)\n                                                  # ... and plot the last perceptron guess\nplt.xlabel('x')\nplt.title('Known answer (black), Perceptron final guess (blue)')\nplt.show()","options":{"results":"markup","fig-height":5,"out-height":"","label":"","comment":"","output":"true","read-only":"false","message":"true","out-width":"700px","fig-cap":"","fig-width":7,"classes":"","autorun":"","context":"interactive","dpi":72,"warning":"true"},"id":11}];
 
 
 </script>
diff --git a/docs/Regression.html b/docs/Regression.html
index a6a16c9..87a58e9 100644
--- a/docs/Regression.html
+++ b/docs/Regression.html
@@ -228,7 +228,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"# Load modules\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom scipy.stats import pearsonr\nimport statsmodels.api as sm","id":1},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/regression_example_data.csv\")\n\n# Extract the variables from the loaded data\ntask_performance = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nfiring_rate = np.array(df.iloc[:,1])  #Get the values associated with the second column of the dataframe","id":2},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"# Plot it ...\nplt.figure()\nplt.plot(firing_rate, task_performance, '.')\nplt.xlabel('Firing rate [Hz]')\nplt.ylabel('Task Performance [a.u.]')\nplt.show()","id":3},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"N       = np.size(firing_rate)\nx       = firing_rate - np.mean(firing_rate)\ny       = task_performance - np.mean(task_performance)\nsigma_x = 'SOMETHING'    #Standard deviation of x\nsigma_y = 'SOMETHING'    #Standard deviation of y\n\ncorrelation = 'SOMETHING'\nprint(correlation)","id":4},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"from statsmodels.formula.api import ols\n\ndata = {\"x\": firing_rate, \"y\": task_performance}\n\nres1 = ols(\"y ~1 + x\", data=data).fit()\nres1.summary()","id":5},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"# Get model prediction.\nfitted_values = res1.fittedvalues\n\n# Sort x values for better plotting of the regression line\nx_sorted = np.sort(firing_rate)\nfitted_sorted = np.sort(fitted_values)\n\n# Plot the regression line (fitted model)\nplt.figure()\nplt.scatter(firing_rate,task_performance)\nplt.plot(x_sorted, fitted_sorted, label=\"Fitted Model\", color=\"red\")\n\nplt.xlabel('Firing rate [Hz]')\nplt.ylabel('Task Performance [a.u.]')\nplt.show()","id":6},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/regression_example_data.csv\")\n\n# Extract the variables from the loaded data\ntask_performance = np.array(df.iloc[:,0])\nfiring_rate = np.array(df.iloc[:,1])\nage = np.array(df.iloc[:,2])","id":7},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"# Plot it ...\nplt.figure()\nplt.plot(age, task_performance, '.')\nplt.xlabel('Age [months]')\nplt.ylabel('Task Performance [a.u.]')\nplt.show()","id":8},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"# Compute the correlation between task performance and age","id":9},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"fig = plt.figure(figsize=(12, 12))\nax  = fig.add_subplot(projection='3d')\nax.scatter(age, firing_rate, task_performance)\nax.set_xlabel('Age [months]')\nax.set_ylabel('Firing Rate [Hz]')\nax.set_zlabel('Task Performance');\nplt.show()","id":10},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"from statsmodels.formula.api import ols\ndata = {\"firing_rate\": firing_rate, \"age\": age, \"y\": task_performance}\n# Write the model and print out the summary","id":11},{"options":{"label":"","fig-height":5,"autorun":"","results":"markup","output":"true","out-height":"","comment":"","read-only":"false","classes":"","out-width":"700px","dpi":72,"message":"true","context":"interactive","fig-width":7,"fig-cap":"","warning":"true"},"code":"# Plot the mean model fit.\n\n# First, plot the data.\nfig = plt.figure(figsize=(10, 10))\nax  = fig.add_subplot(projection='3d')\nax.set_xlabel('Age [months]')\nax.set_ylabel('Firing Rate [Hz]')\nax.set_zlabel('Task Performance')\nax.scatter(age, firing_rate, task_performance)\n\n# Then, define model parameter estimates.\n# REPLACE THESE VALUES WITH YOUR PARAMETER ESTIMATES\nalpha  = 1\nbeta_1 = 1\nbeta_2 = 1\n\n# Finally, plot the model fit.\nx      = np.arange(8, 12, 0.1)          # Firing rate\ny      = np.arange(10,20, 0.1)          # Age\nxx, yy = np.meshgrid(x, y)              # Two dim coordinates\nzz     = alpha + beta_1*xx + beta_2*yy  # Model predictions\nax.plot_surface(yy,xx,zz);\nplt.show()","id":12}];
+globalThis.qpyodideCellDetails = [{"id":1,"code":"# Load modules\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom scipy.stats import pearsonr\nimport statsmodels.api as sm","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":2,"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/regression_example_data.csv\")\n\n# Extract the variables from the loaded data\ntask_performance = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nfiring_rate = np.array(df.iloc[:,1])  #Get the values associated with the second column of the dataframe","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":3,"code":"# Plot it ...\nplt.figure()\nplt.plot(firing_rate, task_performance, '.')\nplt.xlabel('Firing rate [Hz]')\nplt.ylabel('Task Performance [a.u.]')\nplt.show()","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":4,"code":"N       = np.size(firing_rate)\nx       = firing_rate - np.mean(firing_rate)\ny       = task_performance - np.mean(task_performance)\nsigma_x = 'SOMETHING'    #Standard deviation of x\nsigma_y = 'SOMETHING'    #Standard deviation of y\n\ncorrelation = 'SOMETHING'\nprint(correlation)","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":5,"code":"from statsmodels.formula.api import ols\n\ndata = {\"x\": firing_rate, \"y\": task_performance}\n\nres1 = ols(\"y ~1 + x\", data=data).fit()\nres1.summary()","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":6,"code":"# Get model prediction.\nfitted_values = res1.fittedvalues\n\n# Sort x values for better plotting of the regression line\nx_sorted = np.sort(firing_rate)\nfitted_sorted = np.sort(fitted_values)\n\n# Plot the regression line (fitted model)\nplt.figure()\nplt.scatter(firing_rate,task_performance)\nplt.plot(x_sorted, fitted_sorted, label=\"Fitted Model\", color=\"red\")\n\nplt.xlabel('Firing rate [Hz]')\nplt.ylabel('Task Performance [a.u.]')\nplt.show()","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":7,"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/regression_example_data.csv\")\n\n# Extract the variables from the loaded data\ntask_performance = np.array(df.iloc[:,0])\nfiring_rate = np.array(df.iloc[:,1])\nage = np.array(df.iloc[:,2])","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":8,"code":"# Plot it ...\nplt.figure()\nplt.plot(age, task_performance, '.')\nplt.xlabel('Age [months]')\nplt.ylabel('Task Performance [a.u.]')\nplt.show()","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":9,"code":"# Compute the correlation between task performance and age","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":10,"code":"fig = plt.figure(figsize=(12, 12))\nax  = fig.add_subplot(projection='3d')\nax.scatter(age, firing_rate, task_performance)\nax.set_xlabel('Age [months]')\nax.set_ylabel('Firing Rate [Hz]')\nax.set_zlabel('Task Performance');\nplt.show()","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":11,"code":"from statsmodels.formula.api import ols\ndata = {\"firing_rate\": firing_rate, \"age\": age, \"y\": task_performance}\n# Write the model and print out the summary","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}},{"id":12,"code":"# Plot the mean model fit.\n\n# First, plot the data.\nfig = plt.figure(figsize=(10, 10))\nax  = fig.add_subplot(projection='3d')\nax.set_xlabel('Age [months]')\nax.set_ylabel('Firing Rate [Hz]')\nax.set_zlabel('Task Performance')\nax.scatter(age, firing_rate, task_performance)\n\n# Then, define model parameter estimates.\n# REPLACE THESE VALUES WITH YOUR PARAMETER ESTIMATES\nalpha  = 1\nbeta_1 = 1\nbeta_2 = 1\n\n# Finally, plot the model fit.\nx      = np.arange(8, 12, 0.1)          # Firing rate\ny      = np.arange(10,20, 0.1)          # Age\nxx, yy = np.meshgrid(x, y)              # Two dim coordinates\nzz     = alpha + beta_1*xx + beta_2*yy  # Model predictions\nax.plot_surface(yy,xx,zz);\nplt.show()","options":{"context":"interactive","fig-width":7,"message":"true","fig-height":5,"label":"","autorun":"","out-height":"","results":"markup","comment":"","fig-cap":"","dpi":72,"classes":"","warning":"true","read-only":"false","out-width":"700px","output":"true"}}];
 
 
 </script>
diff --git a/docs/Rhythms_1.html b/docs/Rhythms_1.html
index aca8a82..94fe929 100644
--- a/docs/Rhythms_1.html
+++ b/docs/Rhythms_1.html
@@ -228,7 +228,7 @@
 }
 
 // Store cell data
-globalThis.qpyodideCellDetails = [{"id":1,"options":{"output":"true","message":"true","read-only":"false","context":"interactive","warning":"true","dpi":72,"results":"markup","fig-cap":"","comment":"","out-width":"700px","fig-height":5,"label":"","autorun":"","classes":"","fig-width":7,"out-height":""},"code":"# Load modules\nimport scipy.io as sio\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt"},{"id":2,"options":{"output":"true","message":"true","read-only":"false","context":"interactive","warning":"true","dpi":72,"results":"markup","fig-cap":"","comment":"","out-width":"700px","fig-height":5,"label":"","autorun":"","classes":"","fig-width":7,"out-height":""},"code":"t = np.arange(0, 2, 0.001)"},{"id":3,"options":{"output":"true","message":"true","read-only":"false","context":"interactive","warning":"true","dpi":72,"results":"markup","fig-cap":"","comment":"","out-width":"700px","fig-height":5,"label":"","autorun":"","classes":"","fig-width":7,"out-height":""},"code":"x = np.sin(2*np.pi*t)"},{"id":4,"options":{"output":"true","message":"true","read-only":"false","context":"interactive","warning":"true","dpi":72,"results":"markup","fig-cap":"","comment":"","out-width":"700px","fig-height":5,"label":"","autorun":"","classes":"","fig-width":7,"out-height":""},"code":"f1 = 10;\nx1 = np.cos(2*np.pi*t*f1);\n\nf2 = 2;\nx2 = np.cos(2*np.pi*t*f2);"},{"id":5,"options":{"output":"true","message":"true","read-only":"false","context":"interactive","warning":"true","dpi":72,"results":"markup","fig-cap":"","comment":"","out-width":"700px","fig-height":5,"label":"","autorun":"","classes":"","fig-width":7,"out-height":""},"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/Rhythms_1.csv\")\n\n# Extract the variables from the loaded data\ndata = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nt    = np.array(df.iloc[:,1])  #Get the values associated with the second column of the dataframe"}];
+globalThis.qpyodideCellDetails = [{"options":{"label":"","fig-cap":"","read-only":"false","out-height":"","fig-height":5,"results":"markup","message":"true","context":"interactive","out-width":"700px","comment":"","classes":"","warning":"true","dpi":72,"output":"true","autorun":"","fig-width":7},"code":"# Load modules\nimport scipy.io as sio\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt","id":1},{"options":{"label":"","fig-cap":"","read-only":"false","out-height":"","fig-height":5,"results":"markup","message":"true","context":"interactive","out-width":"700px","comment":"","classes":"","warning":"true","dpi":72,"output":"true","autorun":"","fig-width":7},"code":"t = np.arange(0, 2, 0.001)","id":2},{"options":{"label":"","fig-cap":"","read-only":"false","out-height":"","fig-height":5,"results":"markup","message":"true","context":"interactive","out-width":"700px","comment":"","classes":"","warning":"true","dpi":72,"output":"true","autorun":"","fig-width":7},"code":"x = np.sin(2*np.pi*t)","id":3},{"options":{"label":"","fig-cap":"","read-only":"false","out-height":"","fig-height":5,"results":"markup","message":"true","context":"interactive","out-width":"700px","comment":"","classes":"","warning":"true","dpi":72,"output":"true","autorun":"","fig-width":7},"code":"f1 = 10;\nx1 = np.cos(2*np.pi*t*f1);\n\nf2 = 2;\nx2 = np.cos(2*np.pi*t*f2);","id":4},{"options":{"label":"","fig-cap":"","read-only":"false","out-height":"","fig-height":5,"results":"markup","message":"true","context":"interactive","out-width":"700px","comment":"","classes":"","warning":"true","dpi":72,"output":"true","autorun":"","fig-width":7},"code":"df = pd.read_csv(\"https://raw.githubusercontent.com/Mark-Kramer/BU-MA665-MA666/master/Data/Rhythms_1.csv\")\n\n# Extract the variables from the loaded data\ndata = np.array(df.iloc[:,0])  #Get the values associated with the first column of the dataframe\nt    = np.array(df.iloc[:,1])  #Get the values associated with the second column of the dataframe","id":5}];
 
 
 </script>
diff --git a/docs/search.json b/docs/search.json
index 2ad4df3..6a47570 100644
--- a/docs/search.json
+++ b/docs/search.json
@@ -133,18 +133,18 @@
     "text": "from scipy.io import loadmat\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.signal import spectrogram\n\n\ndata = loadmat('EEG-1.mat')    # Load the EEG data\n# Data available here\n# https://github.com/Mark-Kramer/BU-MA665-MA666/tree/master/Data\n#\nEEG  = data['EEG'].reshape(-1) # Extract the EEG variable\nt    = data['t'][0]            # ... and the t variablea\n\n\nplt.plot(t,EEG)\nplt.xlabel('Time [s]')\nplt.ylabel('EEG');\n\n\n\n\n\n\n\n\n\n#dt = t[-1]/len(t)\ndt = t[2]-t[1]\nprint(dt)\n\n0.001\n\n\n\nf0 = 1/dt\nprint(f0)\n\n1000.0\n\n\n\nN = len(t)\nprint(N)\n\n2000\n\n\n\nT = N*dt\nprint(T)\n\n2.0\n\n\n\n# Q. What is the Nyquist frequency and frequency resolution?\nfNQ = f0/2\ndf  = 1/T\n\n# Q. What is the frequency axis?\nfj  = np.arange(0,fNQ,df)\n\n# Then, compute the Fourier transform \"by hand\".\nx = EEG\nX = np.ndarray(np.size(fj), complex);\nfor j in range( np.size(fj) ):\n    X[j] = np.sum(x * np.exp(-2*np.pi*1j*fj[j]*t) )\n\n# And the spectrum,\nSxx = 2*dt**2/T * (X * np.conjugate(X))\n\n# Plot it,\nplt.plot(fj, Sxx.real)\nplt.xlim([0, 100])                          # Select frequency range\nplt.xlabel('Frequency [Hz]')                # Label the axes\nplt.ylabel('Power [mV^2/Hz]');\n\n\n\n\n\n\n\n\n\nx   = EEG\nX   = np.fft.fft(x)                        # Compute Fourier transform of x\nSxx = 2*dt**2/T * (X * np.conjugate(X))    # Compute spectrum\nSxx = Sxx[0:int(N / 2)].real               # Ignore negative frequencies\n\n\n# Plot it,\nplt.plot(fj, Sxx)\nplt.xlim([0, 100])                          # Select frequency range\nplt.xlabel('Frequency [Hz]')                # Label the axes\nplt.ylabel('Power [mV^2/Hz]');\n\n\n\n\n\n\n\n\n\ndf  = 1/T                # Determine frequency resolution\nfNQ = f0/2                  # Determine Nyquist frequency\nfaxis = np.arange(0,fNQ,df)        # Construct frequency axis\n\n\nplt.plot(faxis, Sxx)\nplt.xlim([0, 100])                          # Select frequency range\nplt.xlabel('Frequency [Hz]')                # Label the axes\nplt.ylabel('Power [$\\mu V^2$/Hz]');\n\n&lt;&gt;:4: SyntaxWarning: invalid escape sequence '\\m'\n&lt;&gt;:4: SyntaxWarning: invalid escape sequence '\\m'\n/var/folders/mt/qz9sczyj4ys72smgdmwl7dc00016ry/T/ipykernel_19604/921985069.py:4: SyntaxWarning: invalid escape sequence '\\m'\n  plt.ylabel('Power [$\\mu V^2$/Hz]');\n\n\n\n\n\n\n\n\n\n\nplt.figure()\nplt.plot(faxis, 10*np.log10(Sxx))   # Plot the spectrum in decibels.\n#plt.xlim([0, 100])                               # Select the frequency range.\nplt.ylim([-60, 0])                               # Select the decibel range.\nplt.xlabel('Frequency [Hz]')                     # Label the axes.\nplt.ylabel('Power [dB]');\n\n\n\n\n\n\n\n\n\nplt.figure()\nplt.plot(faxis, Sxx)                    # Plot the spectrum in decibels.\n#plt.xlim([df, 100])                                  # Select frequency range\nplt.ylim([10**-7, 0])                                   # ... and the decibel range.\nplt.xlabel('Frequency [Hz]')                         # Label the axes.\nplt.ylabel('Power [dB]');\n\n/var/folders/mt/qz9sczyj4ys72smgdmwl7dc00016ry/T/ipykernel_19604/1734728637.py:4: UserWarning: Attempt to set non-positive ylim on a log-scaled axis will be ignored.\n  plt.ylim([10**-7, 0])                                   # ... and the decibel range.\n\n\n\n\n\n\n\n\n\n\nx_tapered  = np.hanning(N) * x\nplt.figure()\nplt.plot(t,x)\nplt.plot(t,x_tapered);\n\n\n\n\n\n\n\n\n\nxf_tapered  = np.fft.fft(x_tapered)                        # Compute Fourier transform of x.\nSxx_tapered = 2*dt**2/T*(xf_tapered*np.conj(xf_tapered))                        # Compute the spectrum,\nSxx_tapered = np.real(Sxx_tapered[:int(N / 2)])  # ... and ignore negative frequencies.\n\nplt.figure()\nplt.semilogx(faxis,10*np.log10(Sxx))         # Plot spectrum of untapered signal.  \nplt.semilogx(faxis,10*np.log10(Sxx_tapered)) # Plot spectrum vs tapered signal.\nplt.xlim([faxis[1], 100])                    # Select frequency range,\nplt.ylim([-70, 20])                          # ... and the power range.\nplt.xlabel('Frequency [Hz]')                 # Label the axes\nplt.ylabel('Power [$\\mu V^2$/Hz]')\n\n&lt;&gt;:11: SyntaxWarning: invalid escape sequence '\\m'\n&lt;&gt;:11: SyntaxWarning: invalid escape sequence '\\m'\n/var/folders/mt/qz9sczyj4ys72smgdmwl7dc00016ry/T/ipykernel_19604/3086694082.py:11: SyntaxWarning: invalid escape sequence '\\m'\n  plt.ylabel('Power [$\\mu V^2$/Hz]')\n\n\nText(0, 0.5, 'Power [$\\\\mu V^2$/Hz]')\n\n\n\n\n\n\n\n\n\n\n# Plot the spectrogram.\n\nFs = 1 / dt               # Define the sampling frequency,\ninterval = int(Fs)        # ... the interval size,\noverlap = int(Fs * 0.95)  # ... and the overlap intervals\n\n                          # Compute the spectrogram\nf0, t0, Sxx0 = spectrogram(\n    EEG,                  # Provide the signal,\n    fs=Fs,                # ... the sampling frequency,\n    nperseg=interval,     # ... the length of a segment,\n    noverlap=overlap)     # ... the number of samples to overlap,\nplt.pcolormesh(t0, f0, 10 * np.log10(Sxx0),\n               cmap='jet')# Plot the result\nplt.colorbar()            # ... with a color bar,\nplt.ylim([0, 70])             # ... set the frequency range,\nplt.xlabel('Time [s]')       # ... and label the axes\nplt.ylabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\nN = 1000;\ndt= 0.001;\nT = N*dt;\nx = np.random.randn(N)\nt = np.arange(0,N)*dt\n\n#plt.plot(t,x)\n#plt.xlabel('Time [s]');\n\n\nlags  = np.arange(-N+1,N)\nac_xx = np.zeros(np.size(lags))\nfor index,L in enumerate(lags):\n    if L&gt;= 0:\n        ac_xx[index] = 1/N*np.sum( x[L:N]*x[0:N-L] )\n    else:\n        ac_xx[index] = 1/N*np.sum( x[0:N+L]*x[-L:N] )\nplt.plot(lags, ac_xx)                # ... and plot the result.\nplt.xlabel('Lag')\nplt.ylabel('Autocovariance');\n\n\n\n\n\n\n\n\n\nac_xx = 1/N*np.correlate(x,x,'full')\nplt.plot(lags, ac_xx)\n\n\n\n\n\n\n\n\n\n# Load modules we'll need.\nfrom scipy.io import loadmat\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.signal import spectrogram\n\n\n# Load the data.\ndata = loadmat('AC_Example.mat')  # Load the data,\n# Data available here\n# https://github.com/Mark-Kramer/BU-MA665-MA666/tree/master/Data\n#\nd = data['d'][0]                # ... from the first electrode.\nt = data['t'][0]              # Load the time axis\nN = np.size(d,0)              # Store number of observations.\ndt = t[1]-t[0]                # Store sampling interval.\n\n\nplt.plot(t,d)\n\n\n\n\n\n\n\n\n\nT  = t[-1]\ndf = 1/T\nf0 = 1/dt\nfNQ= f0/2\nfaxis = np.arange(0, fNQ, df)\n\nX = np.fft.fft(d - np.mean(d))\nS = 2*dt**2/T * (np.conj(X)*X)\nS = S[0:int(N/2)]\n\nplt.plot(faxis, S)\nplt.xlabel('Freq [Hz]')\n\nText(0.5, 0, 'Freq [Hz]')\n\n\n\n\n\n\n\n\n\n\nac = 1/N*np.correlate(d,d, 'full')\nlags = np.arange(-N+1,N)\nplt.plot(lags, ac);\n\n\n\n\n\n\n\n\n\ndt = 0.001\nN  = 1000\nt  = np.arange(0,N)*dt\nd  = 1*np.sin(2*np.pi*10.25*t) + 0.1*np.random.randn(N)\nplt.plot(t,d)\n\n\n\n\n\n\n\n\n\nrxx = [];\nlags = np.arange(-int(N/2),int(N/2));\nfor idx,L in enumerate(lags):\n    rxx = np.append(rxx, 1/N*np.sum(np.roll(d,L) * d))\nplt.plot(lags, rxx)\nplt.xlabel('Lags [indices]');\nplt.ylabel('Autocovariance rxx');\n\n\n\n\n\n\n\n\n\n# Compute the spectrum from the FT{rxx}\nSxx_via_rxx = 2*dt*np.fft.fft(rxx)\n\n# Compute the spectrum from the data.\nT   = t[-1];\nxf  = np.fft.fft(d);\nSxx = 2 * dt ** 2 / T * (xf * xf.conj()) \n\nplt.plot(10*np.log10(Sxx))\nplt.plot(10*np.log10(Sxx_via_rxx), 'o')\nplt.xlabel('Freq Index')\nplt.legend({'Direct Sxx', 'Sxx via rxx'})\nplt.xlim([0,150]);"
   },
   {
-    "objectID": "Dont-Sync-2024/12. Bursting Models/Bursting.html",
-    "href": "Dont-Sync-2024/12. Bursting Models/Bursting.html",
+    "objectID": "Dont-Sync-2024/12. Bursting Models/Bursting_Lab-SOLUTION.html",
+    "href": "Dont-Sync-2024/12. Bursting Models/Bursting_Lab-SOLUTION.html",
     "title": "Bursting Neuron",
     "section": "",
     "text": "The goal in this notebook is to update the HH equations to include a new (slow) current and produce bursting activity.\nTo do so, start with the HH code available here.\nUpdate the HH model to include the \\(\\bf{g_K-}\\)“M” current listed in Table A2 of this publication."
   },
   {
-    "objectID": "Dont-Sync-2024/12. Bursting Models/Bursting.html#challenges",
-    "href": "Dont-Sync-2024/12. Bursting Models/Bursting.html#challenges",
+    "objectID": "Dont-Sync-2024/12. Bursting Models/Bursting_Lab-SOLUTION.html#challenges",
+    "href": "Dont-Sync-2024/12. Bursting Models/Bursting_Lab-SOLUTION.html#challenges",
     "title": "Bursting Neuron",
     "section": "1 Challenges",
-    "text": "1 Challenges\n\n1.0.1 1. Plot the steady-state function and time constant for this new current.\nHINT: In Table A2 of this publication, the authors provide the forward rate function (\\(\\alpha[V]\\)) and backward rate function (\\(\\beta[V]\\)) for this current. Use these functions to compute the steady-state function and time constant, and plot both versus V.\n\n\n1.0.2 2. Update the HH model to include this new current.\nHINT: Update the HH model to accept three inputs: HH(I0, T0, gB0), where gB0 is the maximal conductance of the new current.\nHINT: Update the HH model to return six outputs: return V,m,h,n,B,t, where B is the gate variable of the new current.\n\n\n1.0.3 3. Find parameter settings so that the model produces bursting activity.\nHINT: Fix I0=10 and T0=500 and vary the maximal conductance of the new current, gB0, until you find a value that supports bursting in the voltage.\nHINT: Plot the voltage V and the new current gate B to visualize how the dynamics behave.\n\n\n1.0.4 4. Compute the spectrum to characterize the dominant rhythms.\nHINT: Be sure to carefully define T.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\n\n\nCode\ndef alphaM(V):\n    return (2.5-0.1*(V+65)) / (np.exp(2.5-0.1*(V+65)) -1)\n\ndef betaM(V):\n    return 4*np.exp(-(V+65)/18)\n\ndef alphaH(V):\n    return 0.07*np.exp(-(V+65)/20)\n\ndef betaH(V):\n    return 1/(np.exp(3.0-0.1*(V+65))+1)\n\ndef alphaN(V):\n    return (0.1-0.01*(V+65)) / (np.exp(1-0.1*(V+65)) -1)\n\ndef betaN(V):\n    return 0.125*np.exp(-(V+65)/80)\n\ndef alphaB(V):\n    return 0.02 / (1+ np.exp((-V-20)/5))\n\ndef betaB(V):\n    return 0.01 * np.exp((-V-43)/18)\n\ndef HHB(I0,T0,gB0):\n    dt = 0.01;\n    T  = int(np.ceil(T0/dt))  # [ms]\n    gNa0 = 120   # [mS/cm^2]\n    ENa  = 125;  # [mV]\n    gK0  = 36;   # [mS/cm^2]\n    EK   = -12;  # [mV]\n    gL0  = 0.3;  # [mS/cm^2]\n    EL   = 10.6; # [mV]\n\n    t = np.arange(0,T)*dt\n    V = np.zeros([T,1])\n    m = np.zeros([T,1])\n    h = np.zeros([T,1])\n    n = np.zeros([T,1])\n    B = np.zeros([T,1])  ##########################\n\n    V[0]=-70.0\n    m[0]=0.05\n    h[0]=0.54\n    n[0]=0.34\n    B[0]=0.0            #####################\n\n    for i in range(0,T-1):\n        V[i+1] = V[i] + dt*(gNa0*m[i]**3*h[i]*(ENa-(V[i]+65)) + gK0*n[i]**4*(EK-(V[i]+65)) + gL0*(EL-(V[i]+65)) + I0 + gB0*B[i]*(EK-(V[i]+65)));\n        m[i+1] = m[i] + dt*(alphaM(V[i])*(1-m[i]) - betaM(V[i])*m[i]);\n        h[i+1] = h[i] + dt*(alphaH(V[i])*(1-h[i]) - betaH(V[i])*h[i]);\n        n[i+1] = n[i] + dt*(alphaN(V[i])*(1-n[i]) - betaN(V[i])*n[i]);\n        B[i+1] = B[i] + dt*(alphaB(V[i])*(1-B[i]) - betaB(V[i])*B[i]);\n    return V,m,h,n,B,t\n\n\n\n\nCode\nV = np.arange(-100,50,1)\n\nxinfB = alphaB(V) / (alphaB(V) + betaB(V))\ntauB  =         1 / (alphaB(V) + betaB(V))\n\nplt.subplot(2,1,1)\nplt.plot(V,xinfB); plt.xlabel('Voltage [mV]'); plt.ylabel('xinfB')\nplt.subplot(2,1,2)\nplt.plot(V,tauB); plt.xlabel('Voltage [mV]'); plt.ylabel('tauB');\n\n\n\n\n\n\n\n\n\n\n\nCode\nI0 = 10;\nT0 = 1000;\ngB0 = 8\n[V,m,h,n,B,t]=HHB(I0,T0,gB0)\nplt.subplot(2,1,1)\nplt.plot(t,V)\nplt.subplot(2,1,2)\nplt.plot(t,B)\n\n\n\n\n\n\n\n\n\n\n\nCode\nN   = np.size(t)\nT   = t[-1]/1000; print(T)\ndt  = (t[2]-t[1])/1000;\nf0  = 1/dt\ndf  = 1/T;  print(df)\nfNQ = f0/2; print(fNQ)\n\nx = B - np.mean(B);\nX = np.fft.fft(x);\nS = 2*dt**2/T * (X * np.conj(X))\nS = S[0:int(N/2)]\nfaxis = np.arange(0,fNQ,df)\n\nplt.plot(faxis, S)\nplt.xlim([0, 5000])\n\n\n0.99999\n1.000010000100001\n49999.99999999999"
+    "text": "1 Challenges\n\n1.0.1 1. Plot the steady-state function and time constant for this new current.\nHINT: In Table A2 of this publication, the authors provide the forward rate function (\\(\\alpha[V]\\)) and backward rate function (\\(\\beta[V]\\)) for this current. Use these functions to compute the steady-state function and time constant, and plot both versus V.\n\n\n1.0.2 2. Update the HH model to include this new current.\nHINT: Update the HH model to accept three inputs: HH(I0, T0, gB0), where gB0 is the maximal conductance of the new current.\nHINT: Update the HH model to return six outputs: return V,m,h,n,B,t, where B is the gate variable of the new current.\n\n\n1.0.3 3. Find parameter settings so that the model produces bursting activity.\nHINT: Fix I0=10 and T0=500 and vary the maximal conductance of the new current, gB0, until you find a value that supports bursting in the voltage.\nHINT: Plot the voltage V and the new current gate B to visualize how the dynamics behave.\n\n\n1.0.4 4. Compute the spectrum to characterize the dominant rhythms.\nHINT: Be sure to carefully define T.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\n\n\nCode\ndef alphaM(V):\n    return (2.5-0.1*(V+65)) / (np.exp(2.5-0.1*(V+65)) -1)\n\ndef betaM(V):\n    return 4*np.exp(-(V+65)/18)\n\ndef alphaH(V):\n    return 0.07*np.exp(-(V+65)/20)\n\ndef betaH(V):\n    return 1/(np.exp(3.0-0.1*(V+65))+1)\n\ndef alphaN(V):\n    return (0.1-0.01*(V+65)) / (np.exp(1-0.1*(V+65)) -1)\n\ndef betaN(V):\n    return 0.125*np.exp(-(V+65)/80)\n\ndef alphaB(V):\n    return 0.02 / (1+ np.exp((-V-20)/5))\n\ndef betaB(V):\n    return 0.01 * np.exp((-V-43)/18)\n\ndef HHB(I0,T0,gB0):\n    dt = 0.01;\n    T  = int(np.ceil(T0/dt))  # [ms]\n    gNa0 = 120   # [mS/cm^2]\n    ENa  = 125;  # [mV]\n    gK0  = 36;   # [mS/cm^2]\n    EK   = -12;  # [mV]\n    gL0  = 0.3;  # [mS/cm^2]\n    EL   = 10.6; # [mV]\n\n    t = np.arange(0,T)*dt\n    V = np.zeros([T,1])\n    m = np.zeros([T,1])\n    h = np.zeros([T,1])\n    n = np.zeros([T,1])\n    B = np.zeros([T,1])  ##########################\n\n    V[0]=-70.0\n    m[0]=0.05\n    h[0]=0.54\n    n[0]=0.34\n    B[0]=0.0            #####################\n\n    for i in range(0,T-1):\n        V[i+1] = V[i] + dt*(gNa0*m[i]**3*h[i]*(ENa-(V[i]+65)) + gK0*n[i]**4*(EK-(V[i]+65)) + gL0*(EL-(V[i]+65)) + I0 + gB0*B[i]*(EK-(V[i]+65)));\n        m[i+1] = m[i] + dt*(alphaM(V[i])*(1-m[i]) - betaM(V[i])*m[i]);\n        h[i+1] = h[i] + dt*(alphaH(V[i])*(1-h[i]) - betaH(V[i])*h[i]);\n        n[i+1] = n[i] + dt*(alphaN(V[i])*(1-n[i]) - betaN(V[i])*n[i]);\n        B[i+1] = B[i] + dt*(alphaB(V[i])*(1-B[i]) - betaB(V[i])*B[i]);\n    return V,m,h,n,B,t\n\n\n\n\nCode\nV = np.arange(-100,50,1)\n\nxinfB = alphaB(V) / (alphaB(V) + betaB(V))\ntauB  =         1 / (alphaB(V) + betaB(V))\n\nplt.subplot(2,1,1)\nplt.plot(V,xinfB); plt.xlabel('Voltage [mV]'); plt.ylabel('xinfB')\nplt.subplot(2,1,2)\nplt.plot(V,tauB); plt.xlabel('Voltage [mV]'); plt.ylabel('tauB');\n\n\n\n\n\n\n\n\n\n\n\nCode\nI0 = 10;\nT0 = 1000;\ngB0 = 8\n[V,m,h,n,B,t]=HHB(I0,T0,gB0)\nplt.subplot(2,1,1)\nplt.plot(t,V)\nplt.subplot(2,1,2)\nplt.plot(t,B);\n\n\n\n\n\n\n\n\n\n\n\nCode\n# Decimate\nV = V.flatten()\nVd = sig.decimate(V, 50)\ntd  = t[::50]\ndt  = (td[2]-td[1])/1000; print(dt)\nf0  = 1/dt; print(f0)\n\n\n0.0005\n2000.0\n\n\n\n\nCode\n# \nimport scipy.signal as sig\nidx, _ = sig.find_peaks(Vd.flatten(), height=0)\ndn = np.zeros(np.shape(Vd))\ndn[idx] = 1\nplt.plot(td,dn)\nplt.xlim([0, 200])\n\n\n\n\n\n\n\n\n\n\n\nCode\nN   = np.size(td)\nT   = td[-1]/1000; print(T)\ndt  = (td[2]-td[1])/1000; print(dt)\nf0  = 1/dt\ndf  = 1/T;  print(df)\nfNQ = f0/2; print(fNQ)\n\n#x = V - np.mean(V);\n\n#x = x + 0*np.random.randn(np.size(x),1)\n\nX = np.fft.fft(Vd-np.mean(Vd));\nS = 2*dt**2/T * (X * np.conj(X))\nS = S[0:int(N/2)]\nfaxis = np.arange(0,fNQ,df)\n\nplt.plot(faxis, S.real)\nplt.xlim([0, 200])\n\n\n0.9995\n0.0005\n1.0005002501250624\n1000.0\n\n\n\n\n\n\n\n\n\n\n\nCode\ntest = np.random.randn(np.size(x),1)\nprint(test.shape)\nprint(x.shape)\ntest2 = x+test\n\n\n(100000, 1)\n(100000, 1)"
   },
   {
     "objectID": "Dont-Sync-2024/11. Gamma Models/Gamma_Lab.html",
@@ -238,46 +238,25 @@
     "text": "Compute the coherence\n\n# Fourier transforms.\nXf = np.array([np.fft.fft(x0 - x0.mean()) for x0 in x])  # Compute Fourier transform of x for each trial\nYf = np.array([np.fft.fft(y0 - y0.mean()) for y0 in y])  # Compute Fourier transform of y for each trial\n\n# Auto- and cross-spectra.\nSxx = 2*dt**2/T * (Xf * np.conj(Xf))  # Spectrum of E1 trials\nSyy = 2*dt**2/T * (Yf * np.conj(Yf))  # ... and E2 trials\nSxy = 2*dt**2/T * (Xf * np.conj(Yf))  # ... and the cross spectrum\n\n# Trial average.\nSxx = np.mean(Sxx,0)\nSyy = np.mean(Syy,0)\nSxy = np.mean(Sxy,0)\n\n# Calculate coherence.\ncohr_squared = np.abs(Sxy)**2 / (np.abs(Sxx) * np.abs(Syy))\n\nf = np.fft.fftfreq(N, dt)                      # Define a frequency axis.\nplt.plot(f, cohr_squared.real)               # Plot the coherence.\nplt.ylim([0, 1.1])                      # ... with y-axis scaled,\nplt.xlabel('Frequency [Hz]')            # ... and with axes labeled.\nplt.ylabel('Coherence')\nplt.title('Trial averaged coherence between two electrodes');"
   },
   {
-    "objectID": "Analyzing_Rhythms_Lab_2b.html",
-    "href": "Analyzing_Rhythms_Lab_2b.html",
-    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
+    "objectID": "Dont-Sync-2024/13. SHO and Golden Rhythms/SHO_Lab.html",
+    "href": "Dont-Sync-2024/13. SHO and Golden Rhythms/SHO_Lab.html",
+    "title": "Damped harmonic oscillator example",
     "section": "",
-    "text": "# Load modules we'll need.\nfrom scipy.io import loadmat\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.signal import spectrogram\n# Load the data.\ndata = loadmat('AC_Example.mat')  # Load the data,\n# Data available here\n# https://github.com/Mark-Kramer/BU-MA665-MA666/tree/master/Data\n#\nd = data['d'][0]                # ... from the first electrode.\nt = data['t'][0]              # Load the time axis\nN = np.size(d,0)              # Store number of observations.\ndt = t[1]-t[0]                # Store sampling interval."
+    "text": "# Load necessary packages\nimport numpy as np\nimport matplotlib.pyplot as plt"
   },
   {
-    "objectID": "Analyzing_Rhythms_Lab_2b.html#load-the-data-and-look-at-it.",
-    "href": "Analyzing_Rhythms_Lab_2b.html#load-the-data-and-look-at-it.",
-    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
-    "section": "Load the data and look at it.",
-    "text": "Load the data and look at it.\nQ. Do you see rhythms?\n\nConclusions\n\n\n\n\n\n# Code to compute the spectrum."
+    "objectID": "Dont-Sync-2024/13. SHO and Golden Rhythms/SHO_Lab.html#define-a-damped-harmonic-oscillator-noise",
+    "href": "Dont-Sync-2024/13. SHO and Golden Rhythms/SHO_Lab.html#define-a-damped-harmonic-oscillator-noise",
+    "title": "Damped harmonic oscillator example",
+    "section": "Define a damped harmonic oscillator + noise",
+    "text": "Define a damped harmonic oscillator + noise\n\ndef damped_harmonic_oscillator(omega,beta,noise,T0):\n\n    dt = 0.01;\n    T  = int(np.ceil(T0/dt))\n\n    t = np.arange(0,T)*dt\n    F = np.zeros([T,1])         # Set up forcing,\n    F[int(0.25*T)] = 1;         # ... give it a kick 25% of way into simulation.\n    x = np.zeros([T,1])\n    y = np.zeros([T,1])\n\n    x[0]=0\n    y[0]=0\n    \n    for i in range(0,T-1):\n        x[i+1] = x[i] + dt*(y[i]);\n        y[i+1] = y[i] + dt*(-omega**2*x[i] - 2*beta*y[i] + F[i] + noise*np.random.randn());\n\n    return x,t"
   },
   {
-    "objectID": "Analyzing_Rhythms_Lab_2b.html#compute-the-spectrum.",
-    "href": "Analyzing_Rhythms_Lab_2b.html#compute-the-spectrum.",
-    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
-    "section": "Compute the spectrum.",
-    "text": "Compute the spectrum.\nQ. What do you find? What rhythms are present in the data?\n\nConclusions\n\n\n\n\n\n# Code to compute the autocovariance."
-  },
-  {
-    "objectID": "Analyzing_Rhythms_Lab_2b.html#compute-the-autocovariance.",
-    "href": "Analyzing_Rhythms_Lab_2b.html#compute-the-autocovariance.",
-    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
-    "section": "Compute the autocovariance.",
-    "text": "Compute the autocovariance.\nQ. What do you find? Is it consistent with the spectrum?\n\nConclusions"
-  },
-  {
-    "objectID": "Analyzing_Rhythms_Lab_2b.html#example-spectrum-ftautocovariance",
-    "href": "Analyzing_Rhythms_Lab_2b.html#example-spectrum-ftautocovariance",
-    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
-    "section": "Example: Spectrum = FT{Autocovariance}",
-    "text": "Example: Spectrum = FT{Autocovariance}\nMake a simple signal.\n\ndt = 0.001\nN  = 1000\nt  = np.arange(0,N)*dt\nd  = np.sin(2*np.pi*10*t) + np.random.randn(N)\n\nCompute the autocovariance with a modifications: circular-shift the data\n\nrxx = [];\nlags = np.arange(-int(N/2),int(N/2));\nfor idx,L in enumerate(lags):\n    rxx = np.append(rxx, 1/N*np.sum(np.roll(d,L) * d))\nplt.plot(lags, rxx)\nplt.xlabel('Lags [indices]');\nplt.ylabel('Autocovariance rxx');\n\nCompute the spectrum via FT and directly from the data.\n\n# Compute the spectrum from the FT{rxx}\nSxx_via_rxx = 2*dt*np.fft.fft(rxx)\n\n# Compute the spectrum from the data.\nT   = t[-1];\nxf  = np.fft.fft(d);\nSxx = 2 * dt ** 2 / T * (xf * xf.conj()) \n\nplt.plot(10*np.log10(Sxx))\nplt.plot(10*np.log10(Sxx_via_rxx), 'o')\nplt.xlabel('Freq Index')\nplt.legend({'Direct Sxx', 'Sxx via rxx'})\nplt.xlim([0,150]);"
-  },
-  {
-    "objectID": "Introduction.html",
-    "href": "Introduction.html",
-    "title": "Introduction to Python for the practicing neuroscientist",
-    "section": "",
-    "text": "To be frank: this notebook is rather boring. In this class, we will use the software package Python. The best way to learn new software (and probably most things) is when motivated by a particular problem. Would you read assembly instructions for furniture you do not plan to own? Probably not. In other notebooks we will pursue specific questions driven by neuronal data, and use our desire to understand these data to motivate the development and application of computational methods. But not in this notebook. Here, we focus on basic coding techniques and principles in Python in the abstract, without motivation. You - poor learner - must trust that these ideas and techniques will eventually be useful. We begin by dipping our toe into the Python pool, and learning the basic strokes; the fun and interesting parts in the “real world” of neuronal data happen later.\nLet us delay no further. In the following examples, you are asked to execute code in Python. If your Python experience is limited, you should actually do this, not just read the text below. If you intend to ignore this advice - and not execute the code in Python - then instead walk to the local coffee shop, get a double espresso, and return to attempt these examples.\nThis notebook follows in spirit and sometimes in detail notebook 2 of MATLAB for Neuroscientists, an excellent reference for learning to use MATLAB in neuroscience with many additional examples. If you have not used Python before, there are many excellent resources online (e.g., the Python Data Science Handbook).\n\nStarting Python\nThere are two ways to interact with this notebook. First, you could run it locally on your own computer using Jupyter. This is an excellent choice, because you’ll be able to read, edit, and excute the Python code directly and you can save any changes you make or notes that you want to record. The second way is to open this notebook in your browser and execute the examples directly in your browser, without installing additional software on your computer. In any case, we encourage you to execute each line of code in this file!\n\n\n\n\n\n\nNote\n\n\n\nThroughout this notebook, we assume that you are running Python 3. Most of the functions used here are the same in Python 2 and 3. One noteable exception however is division. If you are using Python 2, you will find that the division operator / actually computes the floor of the division if both operands are integers (i.e., no decimal points). For example, in Python 2, 4/3 equals 1. While, in Python 3, 4/3 equals 1.333.\nWe encourage you to use Python 3 for the sake of compatibility with this notebook, as well as for compatibility with future releases of Python.\n\n\n\n\nOn-ramp: analysis of neural data in Python\nWe begin this notebook with an “on-ramp” to analysis in Python. The purpose of this on-ramp is to introduce you immediately to some aspects of Python. You may not understand all aspects of the Python language here, but that’s not the point. Instead, the purpose of this on-ramp is to illustrate what can be done. Our advice is to simply run the code below and see what happens…\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: Try to read the code above. Can you see how it loads data, extracts useful information to print, then selects an interval of data to plot?\nA: If you’ve never used Python before, that’s an especially difficult question. Please continue on to learn more!\n\n\n\n\n\nExample 1: Python is a calculator\nExecute the following commands in Python:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What does Python return? Does it make sense?\n\n\n\n\n\nExample 2. Python can compute complicated quantities.\nEnter the following command in Python:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: Does this answer make sense?\n\n\n\n\n\n\n\n\n\nQ: Can you use parentheses to change the answer?\n\n\n\n\n\nExample 3. Python has useful built in functions.\nA function is a program that operates on arguments. Standard math functions and variables (and other useful things) can be accessed from the math and numpy modules. To use the math and numpy modules, we must first import both:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nNote\n\n\n\nIn this style, we indicate which module, or namespace, contains the function we want to call: x = np.arange(10) or plt.plot(x, y).\n\n\nYou will often begin your data analysis with import statements, to load the functionality you need. We can now call functions from math using numpy.*. For example,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nAbove, sin is the sine function. It operates on the argument 2*pi. Notice that, once we have imported the numpy module, Python knows the value of pi. Here’s another example function that operates on arguments:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What is math.atan?\nA: To answer this, try using Python Help. To start the Python Help, simply put a ? at the end of math.atan and then run this code block.\n\n\n\n\n\nCode\nmath.atan?\n\n\nYou should see a description of the function pop up at the bottom of the window.\n\n\n\n\n\n\nNote\n\n\n\nPython Help is extremely useful, but may not work in a web browser. You can always look there when you have questions about a function, or search the internet for help, i.e., google it.\n\n\n\n\nExample 4. We can use Python to define lists of numbers.\nIn Python, there are several different data structures that are designed to store more than one element. Here we will focus on the array data structure, but if you are curious to know how and when to use other structures, there is a good explanation here. Let’s define an array:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 5. We can manipulate arrays by scalars.\nA scalar is a single number. Consider,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What do you find?\nA: Notice that the scalar operates on each element of the array.\n\n\n\n\n\nExample 6. We can manipulate arrays with arrays.\nLet’s create an array and multiply it by itself,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What does this return?\nA: We see that the operator * performs element-by-element multiplication of the values in array a.\n\n\n\n\n\nExample 7. More examples of manipulating arrays with arrays.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What operation does np.multiply() perform?\n\n\n\n\n\nExample 8. We can probe the variables we’ve defined in Python.\nTo see a list of the variables you’ve defined, type who or whos in a code block by themselves. Notice whos provides more information.\n\n\nCode\nwho\n\n\nInteractive namespace is empty.\n\n\n\n\nCode\nwhos\n\n\nInteractive namespace is empty.\n\n\n\n\n\n\n\n\nNote\n\n\n\nThe functions who and whos can be extremely useful, but may not work in a web browser.\n\n\n\n\nExample 9. Determine the dimensions of an array\nTo examine the dimensions of an array, we can ask for the shape,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe find that the shape of a is (1,4) or 1 row and 4 columns. Notice we have two options to execute the shape function:\n\nIn a.shape we return the attribute shape of the variable a.\nIn np.shape(a) we apply the function shape from numpy to the variable a.\n\nThe result is equivalent.\n\n\nExample 10. Sometimes we need to reset the workspace\nBy doing so, we get rid of all the variables. To do so, type %reset and enter y\n\n\nCode\n%reset\n\n\n\n\n\n\n\n\nQ. What command could we use to confirm there are no variables in the workspace?\nA. Consider who.\n\n\n\n\n\nCode\nwho\n\n\n\n\n\n\n\n\nNote\n\n\n\nThe %reset command is an example of a magic. Magics are commands that start with the % symbol and use a language other than Python. They are only available in the notebook environment. In fact, the set of magics that is available is specific to the notebook kernel. This means that if you have a Jupyter notebook running a Ruby kernel the magics will be different.\n\n\n\n\nExample 11. We can define matrices in Python.\nA matrix is an array with more than one dimensio. Consider the following:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThis creates a matrix with two rows and three columns. Consider,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: Can you see the two rows and three columns?\n\n\n\nWe can manipulate matrices like we manipulate vectors.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 12. Indexing matrices and vectors.\nMatrices and vectors are arrays of numbers, and sometimes we want to access individual elements or small subsets of these lists. That’s easy to do in Python. Consider,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nPython indexes from 0 (like C, C++, Java, and unlike MATLAB and Fortran which start at 1). To access the 2nd element of a or b, type a[1] / b[1]. We’ll be a bit fancier with our printing now to distinguish variables. Calling str(a) converts the variable a to a string that can be printed easily. Adding two strings just concatenates them: \"hi\" + \" bye\" = \"hi bye\".\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Do the results make sense? How would you access the 4th element of each vector?\n\n\n\nWe can combine a and b to form a matrix with a as the first row and b as the second. Note that we apply the function array() to the list [a,b], which it converts to a matrix.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nTo learn the size (or shape) of c we use shape():\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe shape of c is [2 5]. It has two rows and five columns. To access the individual element in the 1st row and 4th column of c, type c[0,3]\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nWe access matrices using ‘row, column’ notation. So c[0,3] means print the element in row 0, column 3 of c.\n\n\n\n\n\n\n\nQ. How would you print all rows in the 2nd column of c?\n\n\n\n\n\nExample 13: We can find subsets of elements in matrices and vectors.\nOften we are interested in only some of the elements of a matrix or vector. For example, we might want to look at the data from a single experimental trial which is stored in a particular row of a matrix. Alternatively, we might want to find out when the values in a time series cross a given boundary. Doing this is simple in Python.\n\nSlicing\nSlicing means that we want to look at a specific portion of a vector or matrix, for example, the first row of a matrix. We will continue with the matrix c from the previous example. The notation ‘:’ means ‘all indices’. To access all columns in the entire first row of c, type c[0,:]. To access the 2nd thru 4th columns of the first row of c, type c[0,1:4].\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nThe notation 1:4 means all integers from 1 up to, but not including 4, which in this case gives columns 1, 2, and 3.\n\nLeaving out the number before the colon tells Python to start at index 0. Leaving out the number after the colon tells Python to continue all the way to the end.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe can also tell Python how to step through the indices. To access only the even columns of c, we can use the following:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThis code tells Python to start at 0, continue to the end, and step by 2. The result should be the values in row 0, columns 0, 2, and 4 of c. We could write this explicitly as c[0,0:5:2].\n#### Selecting elements that satisfy a condition Sometimes we’re interested in locating particular values within a matrix or vector. As an example, let’s first define a vector.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Calculate the shape of a. What is the maximum value of a? Hint: Use the max() function.\n\n\n\nNow let’s find all values in a that exceed 10.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThis is called logical indexing, let’s look at what a&gt;10 returns:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWhen we index a using this array lgIdx we get back only the entries in a corresponding to True, as above:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nSometimes we want to know the actual indices in a where a &gt; 10. We can get them using the nonzero() array method, which returns the index of all entries that were True, or non-zero.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nThe command nonzero() can be used as both a function and a method. A method is called by adding it after the object it is meant to operate on with a period in between ( lgIdx.nonzero() ). A function is called with the argument explicitly provided inside the parentheses ( nonzero(lgIdx) ). Basically, a function and a method do the same thing, but a function needs to be given an argument, while a method assumes that the argument is the object that the method is attached to. Note that if we use nonzero() as a function, we need to tell it to look in NumPy for the definition (i.e. add `` at the beginning of the function call).\n\nNow we have another way to select the desired elements of a:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe can use these two types of indexing to change subsets of the values of a.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: How does a change in the first and second print statements?\n\n\n\nWe can perform these same logical operations for a matrix,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nNotice that the last line collapses the True entries to an array, ordered by row and then by column. If you’ve used MATLAB, this is the opposite of what it does!\n\n\n\n\nExample 14: Plotting data in Python.\nIt’s not easy to look at lists of numbers and gain an intuitive feeling for their behavior, especially when the lists are long. In these cases, it’s better to visualize the lists of numbers by plotting them. Consider\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Looking at the values in ‘y’ printed above, can you tell what’s happending?\nA. Not really … let’s visualize y vs x instead.\n\n\n\n\nmatplotlib\nTo visualize y versus x let’s plot it. To do so, let’s first import some basic plotting routines from matplotlib, which provides a nice 2D plotting library. We’ll also tell Python to show matplotlib graphics inline, in this notebook.\nLet’s start by plotting a simple example for x and y,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Does the plot above make sense for the variables x and y?\n\n\n\nNow, let’s go back to the definitions of x and y that we started this example with and plot y versus x.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe plot of x versus y should look a bit jagged, and not smooth like a sinusoid. To make the curve smoother, let’s redefine x as,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Compare this definition of x to the definition above. How do these two definitions differ?\n\n\n\n\n\n\n\n\n\nQ. What is the size of x? Does this make sense?\n\n\n\nNow let’s replot the sine function.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Does this plot make sense, given your knowledge of x, y, and trigonometry?\n\n\n\n\n\n\nExample 15: What if we want to compare several functions?\nContinuing the example in the previous section, let’s define a second vector\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nand plot it:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe’d now like to compare the two variables y and z. To do this, let’s plot both vectors on the same figure, label the axes, and provide a legend,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNotice that we’ve included a third input to the function plot. Here the third input tells Python to draw the curve in a particular color: 'r' for red. There are many options we can use to plot; to see more, check out the documentation for plot.\nWe can also label the axes, give the figure a title, and provide a legend,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nTo futher edit this plot, you might decide - for example - that the font size for the labels is too small. We can change the default with:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 16: We can make random numbers in Python.\nTo generate a single Gaussian random number in Python, use the function in the NumPy random module.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nLet’s generate a vector of 1000 Gaussian random numbers:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n… and look at a histogram of the vector:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Does this histogram make sense? Is it what you expect for a distribution of Gaussian random variables?\n\n\n\n\nSee Python Help (hist?) to learn about the function hist().\n\n\n\nExample 17: Repeating commands over and over and over . . .\nSometimes we’ll want to repeat the same command over and over again. For example, what if we want to plot sin(x + k*pi/4) where k varies from 1 to 5 in steps of 1; how do we do it? Consider the following:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThat’s horrible code! All I did was cut and paste the same thing four times. As a general rule, if you’re repeatedly cutting and pasting in code, what you’re doing is inefficient and typically error prone. There’s a much more elegant way to do this, and it involves making a for loop. Consider:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNow let’s declare a for loop where k successively takes the values 1, then 2, then 3, …, up to 5. Note, any code we want to execute as part of the loop must be indented one level. The first line of code that is not indented, in this case show() below, executes after the for loop completes\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe small section of code above replaces all the cutting-and-pasting. Instead of cutting and pasting, we update the definition of y with different values of k and plot it within this for-loop.\n\n\n\n\n\n\nQ. Spend some time studying this for-loop. Does it make sense?\n\n\n\n\n\n\n\n\n\nNote\n\n\n\nImportant: Python uses indentation to define for loops.\n\n\n\n\nExample 18: Defining a new function.\nWe’ve spent some time in this notebook writing and executing code. Sometimes we’ll need to write our own Python functions. Let’s do that now.\nOur function will do something very simple: it will take as input a vector and return as output the vector elements squared plus an additive constant.\nIf have a vector, v, and a constant, b, we would like to call:\nvsq = my_square_function(v, b)\nThis won’t work! We first need to define my_square_function. Let’s do so now,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe function begins with the keyword def followed by the function name and the inputs in parentheses. Notice that this first line ends with a colon :. All of the function components that follow this first line should be indented one level. This is just like the for loop we applied earlier; the operations performed by the for loop were indented one leve.\n\nWhen defining the function, the code the function executes should be indented one level.\n\nThe text inside triple quotes provides an optional documentation string that describes our function. While optional, including a ‘doc string’ is an important part of making your code understandable and reuseable.\nThe keyword return exits the function, and in this case returns the expression x * x + c. Note that a return statement with no arguments returns None, indicating the absence of a value.\nWith the function defined, let’s now call it. To do so we first define the inputs, and then run the function, as follows:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Try to make a function, my_power, so that y = power(x,n) evaluates \\(y = x^n\\), (in Python you can use x**n to take the power)\n\n\n\n\n\nExample 19: Load data into Python\nFor our last example let’s load a data file on the web in the .csv format into Python.\nTo do so, let’s first import the pandas module,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNow, let’s load a data file using the function read_csv,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe variable df that holds the loaded data is a Python DataFrame. We can think of it as a simple table that holds our data.\nLet’s print it,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe see that the columns in the dataframe consist of two variables: d and t. Our collaborator who provided the data tells us that these correspond to the voltage recording (d) and a time axis (t) for her data.\nLet’s define variables to hold the data corresponding to each key,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nNote\n\n\n\nHere we convert the data in each column to a numpy array, because we’d (probably) like numpy to function on these values.\n\n\nNow, let’s plot the LFP data versus the time axis,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 20: Compute statistics and compare\nContributed by @mateouma\nLet’s do some statistics. First, our standard imports.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWith numpy, we can find the mean and standard deviation of our LFP data.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNow, let’s use numpy to randomly generate numbers according to a normal distribution with the same mean and standard deviation as the LFP data. The syntax is np.random.normal(mean, sd, size), where mean, sd, and size are variables or numbers.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe can use a histogram to compare the distribution of the data with a normal distribution with the same mean and standard deviation.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nAs we can see, our data doesn’t look normally distributed, but in practice we should use a statistical test to make this assessment."
+    "objectID": "Dont-Sync-2024/13. SHO and Golden Rhythms/SHO_Lab.html#simulate-the-model",
+    "href": "Dont-Sync-2024/13. SHO and Golden Rhythms/SHO_Lab.html#simulate-the-model",
+    "title": "Damped harmonic oscillator example",
+    "section": "Simulate the model",
+    "text": "Simulate the model\n\nf     = 1;\nomega = 2*np.pi*f;\nbeta  = 1;\nnoise = 0;\nT0    = 10\nx,t   = damped_harmonic_oscillator(omega,beta,noise,T0);\nplt.plot(t,x);"
   },
   {
     "objectID": "Coherence_Lab_Part_2.html",
@@ -314,6 +293,48 @@
     "section": "Compute the coherence",
     "text": "Compute the coherence\n\n# Fourier transforms.\nXf = \"SOMETHING\"  # Compute Fourier transform of x for each trial\nYf = \"SOMETHING\"  # Compute Fourier transform of y for each trial\n\n# Auto- and cross-spectra.\nSxx = \"SOMETHING\"  # Spectrum of E1 trials\nSyy = \"SOMETHING\"  # ... and E2 trials\nSxy = \"SOMETHING\"  # ... and the cross spectrum\n\n# Trial average.\nSxx = np.mean(Sxx,0)\nSyy = np.mean(Syy,0)\nSxy = np.mean(Sxy,0)\n\n# Calculate coherence.\ncohr_squared = \"SOMETHING\"\n\nf = np.fft.fftfreq(N, dt)                      # Define a frequency axis.\nplt.plot(f, cohr_squared.real)               # Plot the coherence.\nplt.ylim([0, 1.1])                      # ... with y-axis scaled,\nplt.xlabel('Frequency [Hz]')            # ... and with axes labeled.\nplt.ylabel('Coherence')\nplt.title('Trial averaged coherence between two electrodes');"
   },
+  {
+    "objectID": "Introduction.html",
+    "href": "Introduction.html",
+    "title": "Introduction to Python for the practicing neuroscientist",
+    "section": "",
+    "text": "To be frank: this notebook is rather boring. In this class, we will use the software package Python. The best way to learn new software (and probably most things) is when motivated by a particular problem. Would you read assembly instructions for furniture you do not plan to own? Probably not. In other notebooks we will pursue specific questions driven by neuronal data, and use our desire to understand these data to motivate the development and application of computational methods. But not in this notebook. Here, we focus on basic coding techniques and principles in Python in the abstract, without motivation. You - poor learner - must trust that these ideas and techniques will eventually be useful. We begin by dipping our toe into the Python pool, and learning the basic strokes; the fun and interesting parts in the “real world” of neuronal data happen later.\nLet us delay no further. In the following examples, you are asked to execute code in Python. If your Python experience is limited, you should actually do this, not just read the text below. If you intend to ignore this advice - and not execute the code in Python - then instead walk to the local coffee shop, get a double espresso, and return to attempt these examples.\nThis notebook follows in spirit and sometimes in detail notebook 2 of MATLAB for Neuroscientists, an excellent reference for learning to use MATLAB in neuroscience with many additional examples. If you have not used Python before, there are many excellent resources online (e.g., the Python Data Science Handbook).\n\nStarting Python\nThere are two ways to interact with this notebook. First, you could run it locally on your own computer using Jupyter. This is an excellent choice, because you’ll be able to read, edit, and excute the Python code directly and you can save any changes you make or notes that you want to record. The second way is to open this notebook in your browser and execute the examples directly in your browser, without installing additional software on your computer. In any case, we encourage you to execute each line of code in this file!\n\n\n\n\n\n\nNote\n\n\n\nThroughout this notebook, we assume that you are running Python 3. Most of the functions used here are the same in Python 2 and 3. One noteable exception however is division. If you are using Python 2, you will find that the division operator / actually computes the floor of the division if both operands are integers (i.e., no decimal points). For example, in Python 2, 4/3 equals 1. While, in Python 3, 4/3 equals 1.333.\nWe encourage you to use Python 3 for the sake of compatibility with this notebook, as well as for compatibility with future releases of Python.\n\n\n\n\nOn-ramp: analysis of neural data in Python\nWe begin this notebook with an “on-ramp” to analysis in Python. The purpose of this on-ramp is to introduce you immediately to some aspects of Python. You may not understand all aspects of the Python language here, but that’s not the point. Instead, the purpose of this on-ramp is to illustrate what can be done. Our advice is to simply run the code below and see what happens…\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: Try to read the code above. Can you see how it loads data, extracts useful information to print, then selects an interval of data to plot?\nA: If you’ve never used Python before, that’s an especially difficult question. Please continue on to learn more!\n\n\n\n\n\nExample 1: Python is a calculator\nExecute the following commands in Python:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What does Python return? Does it make sense?\n\n\n\n\n\nExample 2. Python can compute complicated quantities.\nEnter the following command in Python:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: Does this answer make sense?\n\n\n\n\n\n\n\n\n\nQ: Can you use parentheses to change the answer?\n\n\n\n\n\nExample 3. Python has useful built in functions.\nA function is a program that operates on arguments. Standard math functions and variables (and other useful things) can be accessed from the math and numpy modules. To use the math and numpy modules, we must first import both:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nNote\n\n\n\nIn this style, we indicate which module, or namespace, contains the function we want to call: x = np.arange(10) or plt.plot(x, y).\n\n\nYou will often begin your data analysis with import statements, to load the functionality you need. We can now call functions from math using numpy.*. For example,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nAbove, sin is the sine function. It operates on the argument 2*pi. Notice that, once we have imported the numpy module, Python knows the value of pi. Here’s another example function that operates on arguments:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What is math.atan?\nA: To answer this, try using Python Help. To start the Python Help, simply put a ? at the end of math.atan and then run this code block.\n\n\n\n\n\nCode\nmath.atan?\n\n\nYou should see a description of the function pop up at the bottom of the window.\n\n\n\n\n\n\nNote\n\n\n\nPython Help is extremely useful, but may not work in a web browser. You can always look there when you have questions about a function, or search the internet for help, i.e., google it.\n\n\n\n\nExample 4. We can use Python to define lists of numbers.\nIn Python, there are several different data structures that are designed to store more than one element. Here we will focus on the array data structure, but if you are curious to know how and when to use other structures, there is a good explanation here. Let’s define an array:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 5. We can manipulate arrays by scalars.\nA scalar is a single number. Consider,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What do you find?\nA: Notice that the scalar operates on each element of the array.\n\n\n\n\n\nExample 6. We can manipulate arrays with arrays.\nLet’s create an array and multiply it by itself,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What does this return?\nA: We see that the operator * performs element-by-element multiplication of the values in array a.\n\n\n\n\n\nExample 7. More examples of manipulating arrays with arrays.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: What operation does np.multiply() perform?\n\n\n\n\n\nExample 8. We can probe the variables we’ve defined in Python.\nTo see a list of the variables you’ve defined, type who or whos in a code block by themselves. Notice whos provides more information.\n\n\nCode\nwho\n\n\nInteractive namespace is empty.\n\n\n\n\nCode\nwhos\n\n\nInteractive namespace is empty.\n\n\n\n\n\n\n\n\nNote\n\n\n\nThe functions who and whos can be extremely useful, but may not work in a web browser.\n\n\n\n\nExample 9. Determine the dimensions of an array\nTo examine the dimensions of an array, we can ask for the shape,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe find that the shape of a is (1,4) or 1 row and 4 columns. Notice we have two options to execute the shape function:\n\nIn a.shape we return the attribute shape of the variable a.\nIn np.shape(a) we apply the function shape from numpy to the variable a.\n\nThe result is equivalent.\n\n\nExample 10. Sometimes we need to reset the workspace\nBy doing so, we get rid of all the variables. To do so, type %reset and enter y\n\n\nCode\n%reset\n\n\n\n\n\n\n\n\nQ. What command could we use to confirm there are no variables in the workspace?\nA. Consider who.\n\n\n\n\n\nCode\nwho\n\n\n\n\n\n\n\n\nNote\n\n\n\nThe %reset command is an example of a magic. Magics are commands that start with the % symbol and use a language other than Python. They are only available in the notebook environment. In fact, the set of magics that is available is specific to the notebook kernel. This means that if you have a Jupyter notebook running a Ruby kernel the magics will be different.\n\n\n\n\nExample 11. We can define matrices in Python.\nA matrix is an array with more than one dimensio. Consider the following:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThis creates a matrix with two rows and three columns. Consider,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: Can you see the two rows and three columns?\n\n\n\nWe can manipulate matrices like we manipulate vectors.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 12. Indexing matrices and vectors.\nMatrices and vectors are arrays of numbers, and sometimes we want to access individual elements or small subsets of these lists. That’s easy to do in Python. Consider,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nPython indexes from 0 (like C, C++, Java, and unlike MATLAB and Fortran which start at 1). To access the 2nd element of a or b, type a[1] / b[1]. We’ll be a bit fancier with our printing now to distinguish variables. Calling str(a) converts the variable a to a string that can be printed easily. Adding two strings just concatenates them: \"hi\" + \" bye\" = \"hi bye\".\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Do the results make sense? How would you access the 4th element of each vector?\n\n\n\nWe can combine a and b to form a matrix with a as the first row and b as the second. Note that we apply the function array() to the list [a,b], which it converts to a matrix.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nTo learn the size (or shape) of c we use shape():\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe shape of c is [2 5]. It has two rows and five columns. To access the individual element in the 1st row and 4th column of c, type c[0,3]\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nWe access matrices using ‘row, column’ notation. So c[0,3] means print the element in row 0, column 3 of c.\n\n\n\n\n\n\n\nQ. How would you print all rows in the 2nd column of c?\n\n\n\n\n\nExample 13: We can find subsets of elements in matrices and vectors.\nOften we are interested in only some of the elements of a matrix or vector. For example, we might want to look at the data from a single experimental trial which is stored in a particular row of a matrix. Alternatively, we might want to find out when the values in a time series cross a given boundary. Doing this is simple in Python.\n\nSlicing\nSlicing means that we want to look at a specific portion of a vector or matrix, for example, the first row of a matrix. We will continue with the matrix c from the previous example. The notation ‘:’ means ‘all indices’. To access all columns in the entire first row of c, type c[0,:]. To access the 2nd thru 4th columns of the first row of c, type c[0,1:4].\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nThe notation 1:4 means all integers from 1 up to, but not including 4, which in this case gives columns 1, 2, and 3.\n\nLeaving out the number before the colon tells Python to start at index 0. Leaving out the number after the colon tells Python to continue all the way to the end.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe can also tell Python how to step through the indices. To access only the even columns of c, we can use the following:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThis code tells Python to start at 0, continue to the end, and step by 2. The result should be the values in row 0, columns 0, 2, and 4 of c. We could write this explicitly as c[0,0:5:2].\n#### Selecting elements that satisfy a condition Sometimes we’re interested in locating particular values within a matrix or vector. As an example, let’s first define a vector.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Calculate the shape of a. What is the maximum value of a? Hint: Use the max() function.\n\n\n\nNow let’s find all values in a that exceed 10.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThis is called logical indexing, let’s look at what a&gt;10 returns:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWhen we index a using this array lgIdx we get back only the entries in a corresponding to True, as above:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nSometimes we want to know the actual indices in a where a &gt; 10. We can get them using the nonzero() array method, which returns the index of all entries that were True, or non-zero.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nThe command nonzero() can be used as both a function and a method. A method is called by adding it after the object it is meant to operate on with a period in between ( lgIdx.nonzero() ). A function is called with the argument explicitly provided inside the parentheses ( nonzero(lgIdx) ). Basically, a function and a method do the same thing, but a function needs to be given an argument, while a method assumes that the argument is the object that the method is attached to. Note that if we use nonzero() as a function, we need to tell it to look in NumPy for the definition (i.e. add `` at the beginning of the function call).\n\nNow we have another way to select the desired elements of a:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe can use these two types of indexing to change subsets of the values of a.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ: How does a change in the first and second print statements?\n\n\n\nWe can perform these same logical operations for a matrix,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\nNotice that the last line collapses the True entries to an array, ordered by row and then by column. If you’ve used MATLAB, this is the opposite of what it does!\n\n\n\n\nExample 14: Plotting data in Python.\nIt’s not easy to look at lists of numbers and gain an intuitive feeling for their behavior, especially when the lists are long. In these cases, it’s better to visualize the lists of numbers by plotting them. Consider\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Looking at the values in ‘y’ printed above, can you tell what’s happending?\nA. Not really … let’s visualize y vs x instead.\n\n\n\n\nmatplotlib\nTo visualize y versus x let’s plot it. To do so, let’s first import some basic plotting routines from matplotlib, which provides a nice 2D plotting library. We’ll also tell Python to show matplotlib graphics inline, in this notebook.\nLet’s start by plotting a simple example for x and y,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Does the plot above make sense for the variables x and y?\n\n\n\nNow, let’s go back to the definitions of x and y that we started this example with and plot y versus x.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe plot of x versus y should look a bit jagged, and not smooth like a sinusoid. To make the curve smoother, let’s redefine x as,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Compare this definition of x to the definition above. How do these two definitions differ?\n\n\n\n\n\n\n\n\n\nQ. What is the size of x? Does this make sense?\n\n\n\nNow let’s replot the sine function.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Does this plot make sense, given your knowledge of x, y, and trigonometry?\n\n\n\n\n\n\nExample 15: What if we want to compare several functions?\nContinuing the example in the previous section, let’s define a second vector\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nand plot it:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe’d now like to compare the two variables y and z. To do this, let’s plot both vectors on the same figure, label the axes, and provide a legend,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNotice that we’ve included a third input to the function plot. Here the third input tells Python to draw the curve in a particular color: 'r' for red. There are many options we can use to plot; to see more, check out the documentation for plot.\nWe can also label the axes, give the figure a title, and provide a legend,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nTo futher edit this plot, you might decide - for example - that the font size for the labels is too small. We can change the default with:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 16: We can make random numbers in Python.\nTo generate a single Gaussian random number in Python, use the function in the NumPy random module.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nLet’s generate a vector of 1000 Gaussian random numbers:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n… and look at a histogram of the vector:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Does this histogram make sense? Is it what you expect for a distribution of Gaussian random variables?\n\n\n\n\nSee Python Help (hist?) to learn about the function hist().\n\n\n\nExample 17: Repeating commands over and over and over . . .\nSometimes we’ll want to repeat the same command over and over again. For example, what if we want to plot sin(x + k*pi/4) where k varies from 1 to 5 in steps of 1; how do we do it? Consider the following:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThat’s horrible code! All I did was cut and paste the same thing four times. As a general rule, if you’re repeatedly cutting and pasting in code, what you’re doing is inefficient and typically error prone. There’s a much more elegant way to do this, and it involves making a for loop. Consider:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNow let’s declare a for loop where k successively takes the values 1, then 2, then 3, …, up to 5. Note, any code we want to execute as part of the loop must be indented one level. The first line of code that is not indented, in this case show() below, executes after the for loop completes\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe small section of code above replaces all the cutting-and-pasting. Instead of cutting and pasting, we update the definition of y with different values of k and plot it within this for-loop.\n\n\n\n\n\n\nQ. Spend some time studying this for-loop. Does it make sense?\n\n\n\n\n\n\n\n\n\nNote\n\n\n\nImportant: Python uses indentation to define for loops.\n\n\n\n\nExample 18: Defining a new function.\nWe’ve spent some time in this notebook writing and executing code. Sometimes we’ll need to write our own Python functions. Let’s do that now.\nOur function will do something very simple: it will take as input a vector and return as output the vector elements squared plus an additive constant.\nIf have a vector, v, and a constant, b, we would like to call:\nvsq = my_square_function(v, b)\nThis won’t work! We first need to define my_square_function. Let’s do so now,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe function begins with the keyword def followed by the function name and the inputs in parentheses. Notice that this first line ends with a colon :. All of the function components that follow this first line should be indented one level. This is just like the for loop we applied earlier; the operations performed by the for loop were indented one leve.\n\nWhen defining the function, the code the function executes should be indented one level.\n\nThe text inside triple quotes provides an optional documentation string that describes our function. While optional, including a ‘doc string’ is an important part of making your code understandable and reuseable.\nThe keyword return exits the function, and in this case returns the expression x * x + c. Note that a return statement with no arguments returns None, indicating the absence of a value.\nWith the function defined, let’s now call it. To do so we first define the inputs, and then run the function, as follows:\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nQ. Try to make a function, my_power, so that y = power(x,n) evaluates \\(y = x^n\\), (in Python you can use x**n to take the power)\n\n\n\n\n\nExample 19: Load data into Python\nFor our last example let’s load a data file on the web in the .csv format into Python.\nTo do so, let’s first import the pandas module,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNow, let’s load a data file using the function read_csv,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nThe variable df that holds the loaded data is a Python DataFrame. We can think of it as a simple table that holds our data.\nLet’s print it,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe see that the columns in the dataframe consist of two variables: d and t. Our collaborator who provided the data tells us that these correspond to the voltage recording (d) and a time axis (t) for her data.\nLet’s define variables to hold the data corresponding to each key,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\n\n\n\n\nNote\n\n\n\nHere we convert the data in each column to a numpy array, because we’d (probably) like numpy to function on these values.\n\n\nNow, let’s plot the LFP data versus the time axis,\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\n\n\nExample 20: Compute statistics and compare\nContributed by @mateouma\nLet’s do some statistics. First, our standard imports.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWith numpy, we can find the mean and standard deviation of our LFP data.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nNow, let’s use numpy to randomly generate numbers according to a normal distribution with the same mean and standard deviation as the LFP data. The syntax is np.random.normal(mean, sd, size), where mean, sd, and size are variables or numbers.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nWe can use a histogram to compare the distribution of the data with a normal distribution with the same mean and standard deviation.\n\nPlease enable JavaScript to experience the dynamic code cell content on this page.\nAs we can see, our data doesn’t look normally distributed, but in practice we should use a statistical test to make this assessment."
+  },
+  {
+    "objectID": "Analyzing_Rhythms_Lab_2b.html",
+    "href": "Analyzing_Rhythms_Lab_2b.html",
+    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
+    "section": "",
+    "text": "# Load modules we'll need.\nfrom scipy.io import loadmat\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.signal import spectrogram\n# Load the data.\ndata = loadmat('AC_Example.mat')  # Load the data,\n# Data available here\n# https://github.com/Mark-Kramer/BU-MA665-MA666/tree/master/Data\n#\nd = data['d'][0]                # ... from the first electrode.\nt = data['t'][0]              # Load the time axis\nN = np.size(d,0)              # Store number of observations.\ndt = t[1]-t[0]                # Store sampling interval."
+  },
+  {
+    "objectID": "Analyzing_Rhythms_Lab_2b.html#load-the-data-and-look-at-it.",
+    "href": "Analyzing_Rhythms_Lab_2b.html#load-the-data-and-look-at-it.",
+    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
+    "section": "Load the data and look at it.",
+    "text": "Load the data and look at it.\nQ. Do you see rhythms?\n\nConclusions\n\n\n\n\n\n# Code to compute the spectrum."
+  },
+  {
+    "objectID": "Analyzing_Rhythms_Lab_2b.html#compute-the-spectrum.",
+    "href": "Analyzing_Rhythms_Lab_2b.html#compute-the-spectrum.",
+    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
+    "section": "Compute the spectrum.",
+    "text": "Compute the spectrum.\nQ. What do you find? What rhythms are present in the data?\n\nConclusions\n\n\n\n\n\n# Code to compute the autocovariance."
+  },
+  {
+    "objectID": "Analyzing_Rhythms_Lab_2b.html#compute-the-autocovariance.",
+    "href": "Analyzing_Rhythms_Lab_2b.html#compute-the-autocovariance.",
+    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
+    "section": "Compute the autocovariance.",
+    "text": "Compute the autocovariance.\nQ. What do you find? Is it consistent with the spectrum?\n\nConclusions"
+  },
+  {
+    "objectID": "Analyzing_Rhythms_Lab_2b.html#example-spectrum-ftautocovariance",
+    "href": "Analyzing_Rhythms_Lab_2b.html#example-spectrum-ftautocovariance",
+    "title": "Analyzing Rhythms Part 2b (Autocovariance)",
+    "section": "Example: Spectrum = FT{Autocovariance}",
+    "text": "Example: Spectrum = FT{Autocovariance}\nMake a simple signal.\n\ndt = 0.001\nN  = 1000\nt  = np.arange(0,N)*dt\nd  = np.sin(2*np.pi*10*t) + np.random.randn(N)\n\nCompute the autocovariance with a modifications: circular-shift the data\n\nrxx = [];\nlags = np.arange(-int(N/2),int(N/2));\nfor idx,L in enumerate(lags):\n    rxx = np.append(rxx, 1/N*np.sum(np.roll(d,L) * d))\nplt.plot(lags, rxx)\nplt.xlabel('Lags [indices]');\nplt.ylabel('Autocovariance rxx');\n\nCompute the spectrum via FT and directly from the data.\n\n# Compute the spectrum from the FT{rxx}\nSxx_via_rxx = 2*dt*np.fft.fft(rxx)\n\n# Compute the spectrum from the data.\nT   = t[-1];\nxf  = np.fft.fft(d);\nSxx = 2 * dt ** 2 / T * (xf * xf.conj()) \n\nplt.plot(10*np.log10(Sxx))\nplt.plot(10*np.log10(Sxx_via_rxx), 'o')\nplt.xlabel('Freq Index')\nplt.legend({'Direct Sxx', 'Sxx via rxx'})\nplt.xlim([0,150]);"
+  },
   {
     "objectID": "Dont-Sync-2024/9. Coherence/Coherence_Lab_Part_1-SOLUTION.html",
     "href": "Dont-Sync-2024/9. Coherence/Coherence_Lab_Part_1-SOLUTION.html",
@@ -340,7 +361,7 @@
     "href": "Dont-Sync-2024/9. Coherence/Spike-Field-Coherence-Lab.html",
     "title": "Dependence on rate (Part 1)",
     "section": "",
-    "text": "Dependence on rate (Part 1)\n\nimport scipy.io as io\nimport scipy.signal as signal\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\n# Load the data and plot it.\ndata = io.loadmat('spikes-LFP-1.mat')       # Load the multiscale data,\ny = data['y']                                # ... get the LFP data,\nn = data['n']                                # ... get the spike data,\nt = data['t'].reshape(-1)                    # ... get the time axis,\nK = np.shape(n)[0]                           # Get the number of trials,\nN = np.shape(n)[1]                           # ... and the number of data points in each trial,\ndt = t[1]-t[0]                               # Get the sampling interval.\n\n\nFor convenience, make a function to compute the cohernece.\n\ndef coherence(n,y,t):                           #INPUT (spikes, fields, time)\n    K = np.shape(n)[0]                          #... where spikes and fields are arrays [trials, time]\n    N = np.shape(n)[1]\n    T = t[-1]\n    SYY = np.zeros(int(N/2+1))\n    SNN = np.zeros(int(N/2+1))\n    SYN = np.zeros(int(N/2+1), dtype=complex)\n    \n    for k in np.arange(K):\n        yf = np.fft.rfft((y[k,:]-np.mean(y[k,:])) *np.hanning(N))    # Hanning taper the field,\n        nf = np.fft.rfft((n[k,:]-np.mean(n[k,:])))                   # ... but do not taper the spikes.\n        SYY = SYY + ( np.real( yf*np.conj(yf) ) )/K                  # Field spectrum\n        SNN = SNN + ( np.real( nf*np.conj(nf) ) )/K                  # Spike spectrum\n        SYN = SYN + (          yf*np.conj(nf)   )/K                  # Cross spectrum\n\n    cohr = np.abs(SYN) / np.sqrt(SYY) / np.sqrt(SNN)                 # Coherence\n    f = np.fft.rfftfreq(N, dt)                                       # Frequency axis for plotting\n    \n    return (cohr, f, SYY, SNN, SYN)\n\nLet’s try it:\n\n[cohr, f, SYY, SNN, SYN] = coherence(n,y,t)\nplt.plot(f,cohr)\nplt.xlim([0, 100]); plt.xlabel('Frequency [Hz]'); plt.ylabel('Coherence');\n\n\n\n\n\n\n\n\n\n\nMake a function to thin a spike train.\n\ndef thinned_spike_train(n, thinning_factor):              # Thin the spike train (n) by the thinning_factor.\n    n_thinned = np.copy(n)                                # Make a copy of the spike train data.\n    for k in np.arange(K):                                # For each trial,\n        spike_times = np.where(n[k,:]==1)                 # ...find the spikes.\n        n_spikes = np.size(spike_times)                   # ...determine number of spikes.\n        spike_times_random = spike_times[0][np.random.permutation(n_spikes)]    # ...permute spikes indices,\n        n_remove=int(np.floor(thinning_factor*n_spikes))  # ... determine number of spikes to remove,\n        n_thinned[k,spike_times_random[1:n_remove]]=0     # remove the spikes.\n    return n_thinned\n\nLet’s try it:\n\nplt.clf()\nplt.plot(t, n[0,:], 'k')\nplt.plot(t, thinned_spike_train(n,0.5)[0,:], 'r');\nplt.xlim([0.2, 0.3])\nplt.legend(['Original', 'Thinned']);\n\n\n\n\n\n\n\n\n\n\nCompare the spike-field coherence for original and thinned data.\n\n[cohr, f, SYY, SNN, SYN] = coherence(n,y,t)                          # Coherence for original spike train.\nplt.clf()\nplt.plot(f,cohr, 'b')\n[cohr, f, SYY, SNN, SYN] = coherence(thinned_spike_train(n,0.5),y,t) # ... and for the thinned spike train.\nplt.plot(f,cohr, 'r')\nplt.xlim([40, 50])\nplt.legend(['Original', 'Thinned'])\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\n\n\n\n\n\n\n\n\n\n\nRepeat for different thinning factors.\n\nplt.figure(1); plt.clf(); plt.figure(2); plt.clf()\ncounter=1\nfor thinner in np.arange(0,1,0.25):\n    thinned = thinned_spike_train(n,thinner)\n    [cohr, f, SYY, SNN, SYN] = coherence(thinned,y,t) # ... and for the thinned spike train.\n    plt.figure(1)\n    plt.plot(f,cohr,label=str(thinner))\n    \nplt.figure(1)\nplt.xlim([40, 50])\nplt.legend()\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\n\n&lt;Figure size 640x480 with 0 Axes&gt;\n\n\n\n\n\n\n\n\n\n\n\n\n\nDependence on rate (Part 2)\n\nSimulate two simple spiking neurons, with activity dependent on a field.\n\ndef sim_two_neurons(baseline_rate_A, baseline_rate_B, field_coupling_A, field_coupling_B):\n    K = 100                            # Number of trials.\n    N = 1000                           # Points per trial.\n    A = np.zeros([K,N])                # Array to hold spikes A.\n    B = np.zeros([K,N])                # Array to hold spikes B.\n    y = np.zeros([K,N])                # Array to hold field.\n    for k in np.arange(K):             # For each trial,\n        y[k,:] = np.sin(2*np.pi*t*10) + 0.1*np.random.randn(N)    # ... generate a field,\n        A[k,:] = np.random.binomial(1,0.001*np.exp(baseline_rate_A+field_coupling_A*y[k,:]))      # ... generate spikes #A that depend on the field,\n        B[k,:] = np.random.binomial(1,0.001*np.exp(baseline_rate_B+field_coupling_B*y[k,:]))      # ... generate spikes #B that depend on the field.\n    return A,B,y\n\n\n\nVisualize example trials.\n\nplt.clf()\nrate_A = 1.0;  coupling_A = 1             # Fix the rates and coupling to field for each neuron.\nrate_B = 0.5;  coupling_B = 1           # Simulate the two neurons.\nA,B,y = sim_two_neurons(rate_A, rate_B, coupling_A, coupling_B)\nn_trial = 0;                                # Select a trial to plot.\nplt.plot(t,A[n_trial,:])\nplt.plot(t,B[n_trial,:])\nplt.plot(t,y[n_trial,:])\nplt.legend([\"Neuron A\", \"Neuron B\", \"Field\"]);\n\n\n\n\n\n\n\n\n\n\nCompute the average rate of each neuron\n\nrateA = np.mean(sum(A,1)/t[-1])\nrateB = np.mean(sum(B,1)/t[-1])\n\nprint(\"A(Rate) = \", rateA, \", B(Rate) = \", rateB)\n\nA(Rate) =  1.344 , B(Rate) =  1.192\n\n\n\n\nCompute the spike-field coherence.\n\nplt.clf()\n\n[cohr, f, SYY, SNN, SYN] = coherence(A,y,t); plt.plot(f,cohr)\n\n[cohr, f, SYY, SNN, SYN] = coherence(B,y,t); plt.plot(f,cohr)\n\nplt.xlim([0,20])\nplt.ylim([0,1])\nplt.legend(['Neuron A', 'Neuron B'])\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\n\n\n\n\n\n\n\n\n\n\nRepeat coherence calculation for many realizations\n\nbaseline_A = 2.0;  coupling_A = 0.5   # Fix the rates and coupling to field for each neuron.\nbaseline_B = 1.0;  coupling_B = 0.5\ncohr_A = np.zeros([501,100])\ncohr_B = np.zeros([501,100])\nfor k in np.arange(100):              # For 100 realizations, simulate the neurons & compute coherence.\n    A,B,y = sim_two_neurons(baseline_A, baseline_B, coupling_A, coupling_B)\n    [cohr, f, SYY, SNN, SYN] = coherence(A,y,t); cohr_A[:,k] = cohr\n    [cohr, f, SYY, SNN, SYN] = coherence(B,y,t); cohr_B[:,k] = cohr\n\n\n# Plot the coherence results.\nplt.clf()\nmn = np.mean(cohr_A,1); se = np.std( cohr_A,1)/np.sqrt(np.shape(cohr_A)[1])\nplt.plot(f,mn,'b',label=\"Neuron A\"); plt.plot(f,mn-2*se, 'b:'); plt.plot(f,mn+2*se, 'b:');\nmn = np.mean(cohr_B,1); se = np.std( cohr_B,1)/np.sqrt(np.shape(cohr_B)[1])\nplt.plot(f,mn,'r',label=\"Neuron B\"); plt.plot(f,mn-2*se, 'r:'); plt.plot(f,mn+2*se, 'r:');\nplt.xlim([5,15]); plt.ylim([0,1]);\nplt.legend()\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\nplt.title('Neuron A Rate: Baseline=' + str(baseline_A) + ', Coupling=' + str(coupling_A) + '\\n'\n          'Neuron B Rate: Baseline=' + str(baseline_B) + ', Coupling=' + str(coupling_B));"
+    "text": "Dependence on rate (Part 1)\n\nimport scipy.io as io\nimport scipy.signal as signal\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\n# Load the data and plot it.\ndata = io.loadmat('spikes-LFP-1.mat')       # Load the multiscale data,\ny = data['y']                                # ... get the LFP data,\nn = data['n']                                # ... get the spike data,\nt = data['t'].reshape(-1)                    # ... get the time axis,\nK = np.shape(n)[0]                           # Get the number of trials,\nN = np.shape(n)[1]                           # ... and the number of data points in each trial,\ndt = t[1]-t[0]                               # Get the sampling interval.\n\n\nplt.stem(t,2*n[0,:], 'k')\nplt.xlim([0, 0.25])\nplt.ylim([0, 2.1])\n\n\n\n\n\n\n\n\n\nFor convenience, make a function to compute the cohernece.\n\ndef coherence(n,y,t):                           #INPUT (spikes, fields, time)\n    K = np.shape(n)[0]                          #... where spikes and fields are arrays [trials, time]\n    N = np.shape(n)[1]\n    T = t[-1]\n    SYY = np.zeros(int(N/2+1))\n    SNN = np.zeros(int(N/2+1))\n    SYN = np.zeros(int(N/2+1), dtype=complex)\n    \n    for k in np.arange(K):\n        yf = np.fft.rfft((y[k,:]-np.mean(y[k,:])) *np.hanning(N))    # Hanning taper the field,\n        nf = np.fft.rfft((n[k,:]-np.mean(n[k,:])))                   # ... but do not taper the spikes.\n        SYY = SYY + ( np.real( yf*np.conj(yf) ) )/K                  # Field spectrum\n        SNN = SNN + ( np.real( nf*np.conj(nf) ) )/K                  # Spike spectrum\n        SYN = SYN + (          yf*np.conj(nf)   )/K                  # Cross spectrum\n\n    cohr = np.abs(SYN) / np.sqrt(SYY) / np.sqrt(SNN)                 # Coherence\n    f = np.fft.rfftfreq(N, dt)                                       # Frequency axis for plotting\n    \n    return (cohr, f, SYY, SNN, SYN)\n\nLet’s try it:\n\n[cohr, f, SYY, SNN, SYN] = coherence(n,y,t)\nplt.plot(f,cohr)\nplt.xlim([0, 100]); plt.xlabel('Frequency [Hz]'); plt.ylabel('Coherence');\n\n\n\n\n\n\n\n\n\n\nMake a function to thin a spike train.\n\ndef thinned_spike_train(n, thinning_factor):              # Thin the spike train (n) by the thinning_factor.\n    n_thinned = np.copy(n)                                # Make a copy of the spike train data.\n    for k in np.arange(K):                                # For each trial,\n        spike_times = np.where(n[k,:]==1)                 # ...find the spikes.\n        n_spikes = np.size(spike_times)                   # ...determine number of spikes.\n        spike_times_random = spike_times[0][np.random.permutation(n_spikes)]    # ...permute spikes indices,\n        n_remove=int(np.floor(thinning_factor*n_spikes))  # ... determine number of spikes to remove,\n        n_thinned[k,spike_times_random[1:n_remove]]=0     # remove the spikes.\n    return n_thinned\n\nLet’s try it:\n\nplt.clf()\nplt.plot(t, n[0,:], 'k')\nplt.plot(t, thinned_spike_train(n,0.5)[0,:], 'r');\nplt.xlim([0.2, 0.3])\nplt.legend(['Original', 'Thinned']);\n\n\n\n\n\n\n\n\n\n\nCompare the spike-field coherence for original and thinned data.\n\n[cohr, f, SYY, SNN, SYN] = coherence(n,y,t)                          # Coherence for original spike train.\nplt.clf()\nplt.plot(f,cohr, 'b')\n[cohr, f, SYY, SNN, SYN] = coherence(thinned_spike_train(n,0.5),y,t) # ... and for the thinned spike train.\nplt.plot(f,cohr, 'r')\nplt.xlim([40, 50])\nplt.legend(['Original', 'Thinned'])\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\n\n\n\n\n\n\n\n\n\n\nRepeat for different thinning factors.\n\nplt.figure(1); plt.clf(); plt.figure(2); plt.clf()\ncounter=1\nfor thinner in np.arange(0,1,0.25):\n    thinned = thinned_spike_train(n,thinner)\n    [cohr, f, SYY, SNN, SYN] = coherence(thinned,y,t) # ... and for the thinned spike train.\n    plt.figure(1)\n    plt.plot(f,cohr,label=str(thinner))\n    \nplt.figure(1)\nplt.xlim([40, 50])\nplt.legend()\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\n\n&lt;Figure size 640x480 with 0 Axes&gt;\n\n\n\n\n\n\n\n\n\n\n\n\n\nDependence on rate (Part 2)\n\nSimulate two simple spiking neurons, with activity dependent on a field.\n\ndef sim_two_neurons(baseline_rate_A, baseline_rate_B, field_coupling_A, field_coupling_B):\n    K = 100                            # Number of trials.\n    N = 1000                           # Points per trial.\n    A = np.zeros([K,N])                # Array to hold spikes A.\n    B = np.zeros([K,N])                # Array to hold spikes B.\n    y = np.zeros([K,N])                # Array to hold field.\n    for k in np.arange(K):             # For each trial,\n        y[k,:] = np.sin(2*np.pi*t*10) + 0.1*np.random.randn(N)    # ... generate a field,\n        A[k,:] = np.random.binomial(1,0.001*np.exp(baseline_rate_A+field_coupling_A*y[k,:]))      # ... generate spikes #A that depend on the field,\n        B[k,:] = np.random.binomial(1,0.001*np.exp(baseline_rate_B+field_coupling_B*y[k,:]))      # ... generate spikes #B that depend on the field.\n    return A,B,y\n\n\n\nVisualize example trials.\n\nplt.clf()\nrate_A = 1.0;  coupling_A = 1             # Fix the rates and coupling to field for each neuron.\nrate_B = 0.5;  coupling_B = 1           # Simulate the two neurons.\nA,B,y = sim_two_neurons(rate_A, rate_B, coupling_A, coupling_B)\nn_trial = 0;                                # Select a trial to plot.\nplt.plot(t,A[n_trial,:])\nplt.plot(t,B[n_trial,:])\nplt.plot(t,y[n_trial,:])\nplt.legend([\"Neuron A\", \"Neuron B\", \"Field\"]);\n\n\n\n\n\n\n\n\n\n\nCompute the average rate of each neuron\n\nrateA = np.mean(sum(A,1)/t[-1])\nrateB = np.mean(sum(B,1)/t[-1])\n\nprint(\"A(Rate) = \", rateA, \", B(Rate) = \", rateB)\n\nA(Rate) =  1.344 , B(Rate) =  1.192\n\n\n\n\nCompute the spike-field coherence.\n\nplt.clf()\n\n[cohr, f, SYY, SNN, SYN] = coherence(A,y,t); plt.plot(f,cohr)\n\n[cohr, f, SYY, SNN, SYN] = coherence(B,y,t); plt.plot(f,cohr)\n\nplt.xlim([0,20])\nplt.ylim([0,1])\nplt.legend(['Neuron A', 'Neuron B'])\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\n\n\n\n\n\n\n\n\n\n\nRepeat coherence calculation for many realizations\n\nbaseline_A = 2.0;  coupling_A = 0.5   # Fix the rates and coupling to field for each neuron.\nbaseline_B = 1.0;  coupling_B = 0.5\ncohr_A = np.zeros([501,100])\ncohr_B = np.zeros([501,100])\nfor k in np.arange(100):              # For 100 realizations, simulate the neurons & compute coherence.\n    A,B,y = sim_two_neurons(baseline_A, baseline_B, coupling_A, coupling_B)\n    [cohr, f, SYY, SNN, SYN] = coherence(A,y,t); cohr_A[:,k] = cohr\n    [cohr, f, SYY, SNN, SYN] = coherence(B,y,t); cohr_B[:,k] = cohr\n\n\n# Plot the coherence results.\nplt.clf()\nmn = np.mean(cohr_A,1); se = np.std( cohr_A,1)/np.sqrt(np.shape(cohr_A)[1])\nplt.plot(f,mn,'b',label=\"Neuron A\"); plt.plot(f,mn-2*se, 'b:'); plt.plot(f,mn+2*se, 'b:');\nmn = np.mean(cohr_B,1); se = np.std( cohr_B,1)/np.sqrt(np.shape(cohr_B)[1])\nplt.plot(f,mn,'r',label=\"Neuron B\"); plt.plot(f,mn-2*se, 'r:'); plt.plot(f,mn+2*se, 'r:');\nplt.xlim([5,15]); plt.ylim([0,1]);\nplt.legend()\nplt.xlabel('Frequency [Hz]')\nplt.ylabel('Coherence');\nplt.title('Neuron A Rate: Baseline=' + str(baseline_A) + ', Coupling=' + str(coupling_A) + '\\n'\n          'Neuron B Rate: Baseline=' + str(baseline_B) + ', Coupling=' + str(coupling_B));"
   },
   {
     "objectID": "Dont-Sync-2024/10. CFC/CFC_Lab.html",
@@ -436,9 +457,9 @@
   {
     "objectID": "Dont-Sync-2024/8. Analyzing Rhythms/Analyzing_Rhythms_Lab_3_spikes-SOULTION.html",
     "href": "Dont-Sync-2024/8. Analyzing Rhythms/Analyzing_Rhythms_Lab_3_spikes-SOULTION.html",
-    "title": "Getting started with spike-field coherence",
+    "title": "Spectra of spike trains",
     "section": "",
-    "text": "# Load modules we'll need.\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\nExample: a randomly spiking neuron\nTo start, let’s create a fake spike train for a randomly spiking neuron, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n\n\n\n\n\n\n\n# Compute the autocovariance.\n\nac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\nlags = np.arange(-N + 1, N)                # Create a lag axis,\nplt.plot(lags * dt, ac_xx)                 # ... and plot the result.\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nprint('lambda0*dt = ',lambda0*dt)\nprint('r_{nn}[0]  = ',ac_xx[N-1])\n\nlambda0*dt =  0.005\nr_{nn}[0]  =  0.005172959999999988\n\n\n\n\n\n\n\n\n\n\n# Compute the spectrum.\n\nDj = np.fft.fft(dn - dn.mean())            # Compute the FT,\nPj = 2 * dt**2 / T * (Dj * Dj.conj())      # ... and the spectrum.\n\nf = np.fft.fftfreq(N, dt)                         # Create frequency axis.\n\nplt.plot(f, np.real(Pj))                   # Plot the spectrum.\nplt.plot(f,2*dt**2*lambda0*np.ones(N), 'b')# And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\n# Repeat the entire simulation many times, and plot the average spectrum\n\nK = 1000\nlambda_est = np.zeros(K)\nP  = np.zeros([K,np.size(Pj)])\nAC = np.zeros([K,2*N-1])\nfor k in np.arange(K):                          # For each repeat,\n    dn = np.random.binomial(1,p0,N)             # ... create a new spike train.\n\n    lambda_est[k] = np.sum(dn)/T;\n                                                # Compute the AC,\n    ac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\n    AC[k,:] = ac_xx                             # ... and save the result.\n    \n    Dj = np.fft.fft(dn - dn.mean())             # Compute the FT,\n    Pj = np.real(2*dt**2/T*(Dj*Dj.conj()))      # ... and the spectrum,\n    P[k,:] = Pj                                 # ... and save the result.\n\nplt.figure()\nplt.plot(lags, np.mean(AC,0))\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nplt.figure()\nplt.plot(f, np.mean(P,0))                      # Plot the spectrum, averaged over repeats\nplt.plot(f,2*dt**2*np.mean(lambda_est)*np.ones(N), 'b')     # And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nExample: a randomly spiking neuron + refractory period\nNow, let’s create a fake spike train for a randomly spiking neuron with a refractory period, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\n\nrefractory_period = 10              # Add a refractory period\nfor i in np.arange(N):\n    if dn[i]==1:\n        dn[i+1:i+refractory_period] = 0\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n\n\n\n\n\n\n\n# Compute the autocovariance.\n\nac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\nlags = np.arange(-N + 1, N)                # Create a lag axis,\nplt.plot(lags * dt, ac_xx)                 # ... and plot the result.\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\n\n\n\n\n\n\n\n\n# Compute the spectrum.\n\nDj = np.fft.fft(dn - dn.mean())            # Compute the FT,\nPj = 2 * dt**2 / T * (Dj * Dj.conj())      # ... and the spectrum.\n\nf = np.fft.fftfreq(N, dt)                         # Create frequency axis.\n\nplt.plot(f, np.real(Pj))                   # Plot the spectrum.\nplt.plot(f,2*dt**2*lambda0*np.ones(N), 'b')# And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\n# Repeat the entire simulation many times, and plot the average spectrum\n\nK = 1000\nlambda_est = np.zeros(K)\nP  = np.zeros([K,np.size(Pj)])\nAC = np.zeros([K,2*N-1])\nfor k in np.arange(K):                          # For each repeat,\n    dn = np.random.binomial(1,p0,N)             # ... create a new spike train.\n\n    refractory_period = 10              # Add a refractory period\n    for i in np.arange(N):\n        if dn[i]==1:\n            dn[i+1:i+refractory_period] = 0\n\n    lambda_est[k] = np.sum(dn)/T;\n                                                # Compute the AC,\n    ac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\n    AC[k,:] = ac_xx                             # ... and save the result.\n    \n    Dj = np.fft.fft(dn - dn.mean())             # Compute the FT,\n    Pj = np.real(2*dt**2/T*(Dj*Dj.conj()))      # ... and the spectrum,\n    P[k,:] = Pj                                 # ... and save the result.\n\nplt.figure()\nplt.plot(lags, np.mean(AC,0))\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nplt.figure()\nplt.plot(f, np.mean(P,0))                      # Plot the spectrum, averaged over repeats\nplt.plot(f,2*dt**2*np.mean(lambda_est)*np.ones(N), 'b')     # And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');"
+    "text": "# Load modules we'll need.\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\nExample: a randomly spiking neuron\nTo start, let’s create a fake spike train for a randomly spiking neuron, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n\n\n\n\n\n\n\n# Compute the autocovariance.\n\nac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\nlags = np.arange(-N + 1, N)                # Create a lag axis,\nplt.plot(lags * dt, ac_xx)                 # ... and plot the result.\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nprint('lambda0*dt = ',lambda0*dt)\nprint('r_{nn}[0]  = ',ac_xx[N-1])\n\nlambda0*dt =  0.005\nr_{nn}[0]  =  0.005172959999999988\n\n\n\n\n\n\n\n\n\n\n# Compute the spectrum.\n\nDj = np.fft.fft(dn - dn.mean())            # Compute the FT,\nPj = 2 * dt**2 / T * (Dj * Dj.conj())      # ... and the spectrum.\n\nf = np.fft.fftfreq(N, dt)                         # Create frequency axis.\n\nplt.plot(f, np.real(Pj))                   # Plot the spectrum.\nplt.plot(f,2*dt**2*lambda0*np.ones(N), 'b')# And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\n# Repeat the entire simulation many times, and plot the average spectrum\n\nK = 1000\nlambda_est = np.zeros(K)\nP  = np.zeros([K,np.size(Pj)])\nAC = np.zeros([K,2*N-1])\nfor k in np.arange(K):                          # For each repeat,\n    dn = np.random.binomial(1,p0,N)             # ... create a new spike train.\n\n    lambda_est[k] = np.sum(dn)/T;\n                                                # Compute the AC,\n    ac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\n    AC[k,:] = ac_xx                             # ... and save the result.\n    \n    Dj = np.fft.fft(dn - dn.mean())             # Compute the FT,\n    Pj = np.real(2*dt**2/T*(Dj*Dj.conj()))      # ... and the spectrum,\n    P[k,:] = Pj                                 # ... and save the result.\n\nplt.figure()\nplt.plot(lags, np.mean(AC,0))\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nplt.figure()\nplt.plot(f, np.mean(P,0))                      # Plot the spectrum, averaged over repeats\nplt.plot(f,2*dt**2*np.mean(lambda_est)*np.ones(N), 'b')     # And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nExample: a randomly spiking neuron + refractory period\nNow, let’s create a fake spike train for a randomly spiking neuron with a refractory period, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\n\nrefractory_period = 10              # Add a refractory period\nfor i in np.arange(N):\n    if dn[i]==1:\n        dn[i+1:i+refractory_period] = 0\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n\n\n\n\n\n\n\n# Compute the autocovariance.\n\nac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\nlags = np.arange(-N + 1, N)                # Create a lag axis,\nplt.plot(lags * dt, ac_xx)                 # ... and plot the result.\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\nplt.xlim([-0.5, 0.5])\n\n\n\n\n\n\n\n\n\n# Compute the spectrum.\n\nDj = np.fft.fft(dn - dn.mean())            # Compute the FT,\nPj = 2 * dt**2 / T * (Dj * Dj.conj())      # ... and the spectrum.\n\nf = np.fft.fftfreq(N, dt)                         # Create frequency axis.\n\nplt.plot(f, np.real(Pj))                   # Plot the spectrum.\nplt.plot(f,2*dt**2*lambda0*np.ones(N), 'b')# And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');\n\n\n\n\n\n\n\n\n\n# Repeat the entire simulation many times, and plot the average spectrum\n\nK = 1000\nlambda_est = np.zeros(K)\nP  = np.zeros([K,np.size(Pj)])\nAC = np.zeros([K,2*N-1])\nfor k in np.arange(K):                          # For each repeat,\n    dn = np.random.binomial(1,p0,N)             # ... create a new spike train.\n\n    refractory_period = 10              # Add a refractory period\n    for i in np.arange(N):\n        if dn[i]==1:\n            dn[i+1:i+refractory_period] = 0\n\n    lambda_est[k] = np.sum(dn)/T;\n                                                # Compute the AC,\n    ac_xx = 1 / N * np.correlate(dn-dn.mean(),dn-dn.mean(), 'full')\n    AC[k,:] = ac_xx                             # ... and save the result.\n    \n    Dj = np.fft.fft(dn - dn.mean())             # Compute the FT,\n    Pj = np.real(2*dt**2/T*(Dj*Dj.conj()))      # ... and the spectrum,\n    P[k,:] = Pj                                 # ... and save the result.\n\nplt.figure()\nplt.plot(lags*dt, np.mean(AC,0))\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\nplt.xlim([-0.5, 0.5])\n\nplt.figure()\nplt.plot(f, np.mean(P,0))                      # Plot the spectrum, averaged over repeats\nplt.plot(f,2*dt**2*np.mean(lambda_est)*np.ones(N), 'b')     # And our guess from in-class analysis.\nplt.xlabel('Frequency [Hz]');"
   },
   {
     "objectID": "Dont-Sync-2024/8. Analyzing Rhythms/Analyzing_Rhythms_Lab_2b-SOLUTION.html",
@@ -508,7 +529,7 @@
     "href": "Analyzing_Rhythms_Lab_3.html",
     "title": "Analyzing Rhythms Part 3 (Spectra of spike trains)",
     "section": "",
-    "text": "# Load modules we'll need.\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\nExample: a randomly spiking neuron\nTo start, let’s create a fake spike train for a randomly spiking neuron, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n# Compute the autocovariance.\n\nac_xx = \"SOMETHING\n\n                                    # Plot it.\nlags  = np.arange(-N + 1, N)        # Create a lag axis,\nplt.plot(lags * dt, ac_xx)          # ... and plot the result.\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nprint('lambda0*dt = ',lambda0*dt)  # Compare expected r_{nn}[0] to computed value.\nprint('r_{nn}[0]  = ',ac_xx[N-1])\n\n\n# Compute the spectrum.\n\nDj = \"SOMETHING\"                            # Compute the FT,\nPj = \"SOMETHING\"                            # ... and the spectrum.\n\nf = np.fft.fftfreq(N, dt)                   # Create frequency axis.\n\nplt.plot(f, np.real(Pj))                    # Plot the spectrum.\nin_class_guess = \"SOMETHING\"                # And our guess from in-class analysis.\nplt.plot(f,in_class_guess*np.ones(N), 'b')\nplt.xlabel('Frequency [Hz]');\n\n\n# Repeat the entire simulation many times, and plot the average spectrum\n\nK  = 1000                                       # Number of times to repeat the simulation.\nlambda_est = np.zeros(K)                        # Vector to store estimate of lambda.\nP  = np.zeros([K,np.size(Pj)])                  # Matrix to store spectra,\nAC = np.zeros([K,2*N-1])                        # ... and AC.\n\nfor k in np.arange(K):                          # For each repeat,\n    dn = np.random.binomial(1,p0,N)             # ... create a new spike train.\n\n    lambda_est[k] = \"SOMETHING\"\n                                                # Compute the AC,\n    ac_xx = \"SOMETHING\"\n    AC[k,:] = ac_xx                             # ... and save the result.\n    \n    Dj = \"SOMETHING\"                            # Compute the FT,\n    Pj = \"SOMETHING\"                            # ... and the spectrum,\n    P[k,:] = Pj                                 # ... and save the result.\n\nplt.figure()                                    # Plot it.\nplt.plot(lags, np.mean(AC,0))\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nplt.figure()\nplt.plot(f, np.mean(P,0))                       # Plot the spectrum, averaged over repeats\nin_class_guess = \"SOMETHING\"                    # Use lambda_est to compute our guess from in-class analysis.\nplt.plot(f,in_class_guess*np.ones(N), 'b')\nplt.xlabel('Frequency [Hz]');\n\n\n\nExample: a randomly spiking neuron + refractory period\nNow, let’s create a fake spike train for a randomly spiking neuron with a refractory period, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\nrefractory_period = 10              # Add a refractory period\nfor i in np.arange(N):\n    if dn[i]==1:\n        dn[i+1:i+refractory_period] = 0\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n# Compute the autocovariance.\n\n\n# Compute the spectrum.\n\n\n# Repeat the entire simulation many times, and plot the average spectrum"
+    "text": "# Load modules we'll need.\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\nExample: a randomly spiking neuron\nTo start, let’s create a fake spike train for a randomly spiking neuron, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n# Compute the autocovariance.\n\nac_xx = \"SOMETHING\n\n                                    # Plot it.\nlags  = np.arange(-N + 1, N)        # Create a lag axis,\nplt.plot(lags * dt, ac_xx)          # ... and plot the result.\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nprint('lambda0*dt = ',lambda0*dt)  # Compare expected r_{nn}[0] to computed value.\nprint('r_{nn}[0]  = ',ac_xx[N-1])\n\n\n# Compute the spectrum.\n\nDj = \"SOMETHING\"                            # Compute the FT,\nPj = \"SOMETHING\"                            # ... and the spectrum.\n\nf = np.fft.fftfreq(N, dt)                   # Create frequency axis.\n\nplt.plot(f, np.real(Pj))                    # Plot the spectrum.\nin_class_guess = \"SOMETHING\"                # And our guess from in-class analysis.\nplt.plot(f,in_class_guess*np.ones(N), 'b')\nplt.xlabel('Frequency [Hz]');\n\n\n# Repeat the entire simulation many times, and plot the average autocovariance and spectrum\n\nK  = 1000                                       # Number of times to repeat the simulation.\nlambda_est = np.zeros(K)                        # Vector to store estimate of lambda.\nP  = np.zeros([K,np.size(Pj)])                  # Matrix to store spectra,\nAC = np.zeros([K,2*N-1])                        # ... and AC.\n\nfor k in np.arange(K):                          # For each repeat,\n    dn = np.random.binomial(1,p0,N)             # ... create a new spike train.\n\n    lambda_est[k] = \"SOMETHING\"\n                                                # Compute the AC,\n    ac_xx = \"SOMETHING\"\n    AC[k,:] = ac_xx                             # ... and save the result.\n    \n    Dj = \"SOMETHING\"                            # Compute the FT,\n    Pj = \"SOMETHING\"                            # ... and the spectrum,\n    P[k,:] = Pj                                 # ... and save the result.\n\nplt.figure()                                    # Plot it.\nplt.plot(lags*dt, np.mean(AC,0))\nplt.xlabel('Lag [s]')\nplt.ylabel('Autocovariance');\n\nplt.figure()\nplt.plot(f, np.mean(P,0))                       # Plot the spectrum, averaged over repeats\nin_class_guess = \"SOMETHING\"                    # Use lambda_est to compute our guess from in-class analysis.\nplt.plot(f,in_class_guess*np.ones(N), 'b')\nplt.xlabel('Frequency [Hz]');\n\n\n\nExample: a randomly spiking neuron + refractory period\nNow, let’s create a fake spike train for a randomly spiking neuron with a refractory period, and compute the autocovariance and spectrum.\n\nN  = 5000;                          # Number of bins.                   \ndt = 0.001;                         # Duration of each bin [s].\nT  = N*dt;                          # Total time of observation [s].\ntm = np.arange(0,N)*dt;             # Time axis for plotting\n\nlambda0 = 5                         # Average firing rate [Hz]\np0      = lambda0*dt;               # Probability of a spike in a time bin\ndn      = np.random.binomial(1,p0,N)# Create the spike train as \"coin flips\"\nrefractory_period = 10              # Add a refractory period\nfor i in np.arange(N):\n    if dn[i]==1:\n        dn[i+1:i+refractory_period] = 0\n\nplt.plot(tm, dn)                    # Plot it.\nplt.xlabel('Time [s]');\n\n\n# Compute the autocovariance.\n\n\n# Compute the spectrum.\n\n\n# Repeat the entire simulation many times, and plot the average autocovariance and spectrum"
   },
   {
     "objectID": "index.html",