Matlab 4 Ephys
Matlab 4 Ephys
Introduction to Matlab
— with Examples and Exercises —
(C) 2008–2018 Daniel Wagenaar and Michael Wright. All rights reserved. You may freely distribute
this document in whole or in part and use it in teaching, provided that you properly attribute it by
leaving this copyright notice intact. Many of the examples in this document require a Matlab toolbox
called “WagenaarMBL”, which you may download from http://www.danielwagenaar.net/teaching.
On that website you can also find the latest version of this document.
Introduction
GOAL: The main goal for today’s lab is to give you an introduction to the Matlab programming
environment. You will then use Matlab to analyze the electrophysiological data you collect later in the
day. Although you have been using Matlab for the previous exercises, here we want you to explore more
of the ins ’n’ outs of the program.
Matlab is an interpreted1 computer language intended for data analysis. At first, you don’t really
have to know that it is a full-fledged computer language, because it can be used like a basic calcu-
lator that can also generate graphs. Over time, you will appreciate how well Matlab handles large
data sets, and how easy it is to add your own data analysis functionality to what comes standard.
An introduction to Matlab could easily fill a semester-long course at a university, because the capa-
bilities of the system are very wide-ranging. We don’t have that much time, so we’ll just cover the
very basics, and then proceed to some applications you will need for analysis of electrophysiological
data. The style of this introduction is rather concise; it is our hope that this will allow you to quickly
learn the essentials without getting bogged down in details. For those of you who are unfamiliar
with Matlab, Chapter 1 will provide a gentle introduction to working with the program; those of
you more familiar with Matlab may find that the rest of the introduction adds to your knowledge
of Matlab. Several more extensive introductory texts are available on the Internet (as well as in
bookstores). The following are still available as of May 2017:
There are also many books published about Matlab. Here are just a few, selected by MW:
• “Mastering Matlab” by Hanselman and Littlefield. This book provides the most in-depth cov-
erage of Matlab. There are plenty of worked examples, as well.
1
“Interpreted” in this context means that you can type commands and get immediate responses. This is in opposition
to “compiled” languages, which execute faster, but make program development much harder.
2
for some reason, cutting and pasting this link in a web browser will not bring up the .pdf file; however, a google
search for ”connor matlab griffith” will bring up the pdf file as the first hit
2
• “Getting Started with Matlab” by Rudra Pratap. This book provides a very gentle yet thorough
handling of Matlab.
• “Essential Matlab for Scientists and Engineers” by Brian Hahn. An intermediate-level book
that focuses more on doing.
In MW’s experience, Mastering Matlab has been the most helpful, but it assumes you know what
you want to do. Outside of that, individual books focus on different aspects of Matlab and as such
MW tends to use a combination of books like Pratap and Hahn3 in addition to Hanselman and
Littlefield. DAW likes to point out that the online help system is also very extensive and answers
many questions. You may also look into the book “Matlab for Neuroscientists,” by Wallisch et al.,
Academic Press, 2008.
As you work your way through this tutorial, we strongly encourage you to experiment with each
of the examples: try variations on them; find out what works and what doesn’t. You really can’t
damage anything by typing nonsense at a computer (unless you try hard: the “delete” command,
for instance, is predictably dangerous). If you get stuck, try typing “help”. To learn more about
Matlab’s online help system, type “help help”. You get the picture. There is also an extensive
“help browser” built into Matlab; this you can access from the top menu bar or by typing “doc”.
In the following, text you type at the keyboard is typeset like this; answers given by Matlab
are typeset like this.
3
If those two are not to your liking, you may take a look at McMahon’s “Matlab Demystified”
3
Chapter 1
This chapter teaches you how to use Matlab to perform simple calculations and to draw graphs.
Not much in this chapter is specifically geared toward handling electrophysiological data, but even
if you are eager to start analyzing your recently acquired data, working your way through the
examples and exercises in this chapter will hopefully pay off: they will provide you with a working
knowledge of Matlab, which will not only greatly facilitate understanding the later chapters, but
will also allow you to tailor the examples presented there to your specific needs.
4
1.1.2 Mathematical functions
Matlab defines a long list of mathematical functions (plus you can define your own; see below).
Example 2
>> cos(60*pi/180) >> log(10)
ans = ans =
0.5000 2.3026
Exercise 2
√
Can you make Matlab confirm that 2 is about 1.41? Hint: There is a function called
“sqrt”. Find out about it by typing “help sqrt” or “doc sqrt”.
Example 3
>> 2 > 1 >> 5 > 3 & 5 < 8
ans = ans =
1 1
>> 3 == 7 >> 5 = 3
ans = ??? 5=3
|
0
Error: Incorrect use of ’=’
operator. [...]
Exercise 3
Which is bigger, 37 or 74 ? Hint: You could just ask Matlab to compute the two numbers
separately, and do the comparison yourself, but that’s not the point of the exercise.
Example 4
>> x = 5 >> y = 3 * xˆ2
x = y =
5 75
5
Exercise 4
What happens if you redefine a variable? Do other variables automatically change their
values to match (as in the neural simulator Neuron), or do they remain unaffected (as
in the programming languages Java or C)?
If you don’t want to see intermediate results, simply place a semicolon at the end of a line. To show
the value of a variable, simply type its name.
Example 5
>> spd = 8; >> dist
>> dur = 7;
dist =
>> dist = spd*dur;
56
Exercise 5
Can you think of a reason why this is useful? (Hint: Try example 13 below without
semicolons.)
Matlab calls the collection of all currently defined variables your “workspace.” An overview of
your current workspace is shown in (and can be explored from) a separate panel of Matlab’s main
window.
Example 6
>> x.a = 3; y =
>> x.b = 7;
a: 3
>> y = x
b: 7
Exercise 6
Can you apply this technique recursively? In other words, what happens if you try to
store a structured variable inside another variable? (Try it by typing “rr.xx = x” fol-
lowing the previous example.)
6
1.3.1 Defining matrices
Matrices are defined by putting a series of numbers (or variables) in square brackets. Rows of the
matrix are separated by semicolons.
Example 7
>> x = [ 1 2 3 ] xxx =
x = 1 2 3
7 8 9
1 2 3
>> y = [ 2; 4; 6]
>> xx = [x 4 5 6]
y =
xx =
2
1 2 3 4 5 6
4
>> xxx = [x; 7 8 9] 6
(Note that some people to prefer to place commas between values in a horizontal row of a matrix.
Those are optional.)
As the example suggests, more often than true matrices (which are two-dimensional arrays of
numbers), we will use one-dimensional arrays, or vectors. Matlab treats them all the same; a vector
of length N is just a matrix of size 1xN (as in the case of x in the example) or N x1 (as in the case
of y).
Exercise 7
In example 7, we concatenated the vector “[7 8 9]” to the vector “x” to generate
“xxx”. Can you concatenate “[7 8 9]” to the vector “y” from the example? Why
(not)? How about concatenating “[7; 8; 9]” to “y”?
7
Example 9
>> [4 6 15] ./ [2 3 5]
1 2
ans = 2 4
2 2 3 >> [1 2] * [ 1 2]
??? Error using ==> *
>> [1 2] * [1; 2]
Incorrect dimensions for matrix
ans = multiplication. [...]
5 >> 5 .* 7
>> [1; 2] * [1 2]
ans =
ans =
35
Note: If you do not know what “matrix multiplication” means, don’t worry; you won’t be needing
it in this course. A simple working strategy is to write “.*” and “./” instead of “*” and “/” unless
you have a specific reason not too.
Exercise 9
Construct a matrix named “x2” the elements of which are the squares of the elements
of the matrix “xxx” in Example 7.
8
Example 11
>> spk.tms = [1.5 2.3 7.8]; spk =
>> spk.hei = [13 17 14.3];
tms: [1.5000 2.3000 7.8000]
>> spk.elc = [6 4 4];
hei: [13 17 14.3000]
>> spk
elc: [6 4 4]
Exercise 11
Do all matrices inside a structure need to have the same shape? Can you include a scalar
in the structure “spk” of the previous example? A line of text? Hint: Matlab wants text
(“string literals”) in single quotes, like “’this’”. Why might that be useful?
Exercise 12
Can you find the heights of all spikes that happened within the first 5 seconds of the
recording? (Assume that “spk.tms” is measured in seconds.)
9
Example 13
>> tt = [0:0.1:30]; >> yyc = .3*cos(2*pi*tt/10);
>> yys = .4*sin(2*pi*tt/10); >> plot(tt, yys, ’b’, ...
>> plot(tt, yys); tt, yyc, ’r’);
>> xlabel ’Time’
>> ylabel ’Position’
>> title ’Two waves’
Exercise 13
Create a plot of your favorite mathematical function.
10
Example 14
>> x=3; >> clear
>> y=[7 4]; >> whos
>> z=x+y; >> load sleepy.mat
>> zzz=z.ˆ2; >> whos
>> whos Name Size Bytes Class
Name Size Bytes Class
z 1x2 16 double array
x 1x1 8 double array zzz 1x2 16 double array
y 1x2 16 double array
Grand total is 4 elements
z 1x2 16 double array
using 32 bytes
zzz 1x2 16 double array
>> zzz
Grand total is 7 elements
zzz =
using 56 bytes
100 49
>> save sleepy.mat z zzz
Exercise 14
What happens if you load two files, each of which contains a variable with the name
“x”?
This will open a new window in which you can edit the new function. Here are the contents for the
new file:
function y = triple(x)
% TRIPLE - Multiply numbers by three
% y = TRIPLE(x) sets Y to 3 times X.
% This works for scalar as well as matrix-valued X.
y = 3*x;
Note that lines beginning with “%” are comments, i.e., explanatory text that Matlab will ignore. By
convention, the first comment line in a function gives a brief summary of what the function does,
and the following several lines give more details. Typing such comments is well worth your time,
because otherwise you will soon not remember what any of your beautifully crafted functions do.
If you take the time to write comments, you can always ask Matlab for a reminder:
11
>> help triple
TRIPLE - Multiply numbers by three
y = TRIPLE(x) sets Y to 3 times X.
This works for scalar as well as matrix-valued X.
Using your new function is easy:
Example 15
>> triple(5) >> a=[3 7];
>> b=triple(a)+1
ans =
b =
15
10 22
Exercise 15
Does “triple” work on a matrix (such as “[1 2; 3 4]”)? Does it work on a struc-
tured variable (such as “spk” from example 11) ?
Let’s consider a slightly more involved example. (Type this into a new empty file and save it as
“fibo.m”.)
function ff = fibo(n)
% FIBO - Generate Fibonacci numbers
% ff = FIBO(n) returns a vector containing the first N
% Fibonacci numbers, that is, the first part of the
% sequence (1, 1, 2, 3, 5, 8, ...).
ff = zeros(n, 1);
ff(1) = 1;
if n>1
ff(2) = 1;
end
for k=3:n
ff(k) = ff(k-2) + ff(k-1);
end;
ff = ff’;
This example introduces several new ideas:
• The function “zeros” initializes a matrix to a given size. This is not strictly necessary, but it
will make your code run more efficiently and—in my opinion—easier to read.
• The construct “if cond ... end” makes the code inside execute only if the condition cond
is satisfied (i.e., if n > 1 in the example).
• The construct “for var = range ... end” makes the code inside execute repeatedly; in
the example, once for each value of k from 3 up to (and including) n. (If n < 3, the code will
not execute at all.)
• Finally, the syntax “’” in the last line of your code transposes your vector (or matrix). In this
case you have transformed a column vector to a row vector. Try it without the “’” to see
how this works. (Advanced: for this example, how could you have obtained the same results
without that last statement? Hint: look at the beginning of the code.)
12
Example 16
>> fibo(10)
ans =
1 1 2 3 5 8 13 21 34 55
Exercise 16
Create a function named “evennum” that returns 2 if its argument (i.e., the number fed
into the function) is even, and 1 if its argument is odd. Hint: You could use either the
built-in function “mod”, or the built-in function “floor” as part of your implementation.
Type “help mod” and “help floor” to learn more.
If you’re ambitious, you can try to extend this function to work nicely on matrices
as well as on single numbers, so that for instance “even([5 8 13 21 34])” would
yield “1 2 1 1 2”.
1.7 Conclusion
Here ends the lightning-fast overview of the main features of Matlab. Nobody would expect you to
be proficient at writing your own functions for tensor algebra in curved spaces at this point (and
that’s OK, because we won’t be doing theoretical physics here). However, we hope you have gained
an appreciation of the versatility of Matlab as a tool for analysis, and, most importantly, are starting
to be unafraid of it: despite the fact that Matlab is a full-blown computer language, we hope we
have shown you that it is easy to use for simple things.
The next chapters will introduce some specific techniques useful for analysis of electrophysiological
data, in particular spike detection and spike train analysis. For a more in-depth general introduc-
tion, we recommend trying the texts mentioned earlier.
13
Chapter 2
Spike detection (the process of identifying action potentials in extracellular traces) and spike sort-
ing (the process of assigning those action potentials to individual cells) are topics of a substantial
scientific literature, and are generally outside of the scope of this course.1 We will, however, need to
analyze our recordings, so this chapter introduces a basic spike detector and a manual spike sorter
which we have found useful for leech recordings, and will be relevant for today’s exercise in which
we analyze extracellular recordings.
(Don’t forget the semicolon, or you’ll see a very long stream of numbers scroll by. And don’t worry
about Matlab’s warning about the “daqread” function being deprecated. It works fine.) You don’t
need to know how “loadephys” works internally; just that it loads electrophysiology data, and
returns the recorded voltages as well as the times at which they were recorded.
Let’s take a look at what we loaded:
>> whos
Name Size Bytes Class
tms 1510000x1 12080000 double array
vlt 1510000x8 96640000 double array
As you can see, the variable “vlt” contains data from 8 electrodes. Evidently, the records are rather
long (1,510,000 samples). The variable “tms” contains the time stamps at which each sample was
recorded, measured in seconds. These times are the same for each of the 8 electrodes, so “tms” is
just a vector, not an Nx8 array. If you type “tms(1)” and “tms(end)”, you will see that time starts
1
Those interested in such techniques may want to speak with Dr. Chacron during the 2nd cycle.
2
These data, as well as some other data files used later in this chapter, are available in a zip-file called “WagenaarMBL-
data.zip”, which you may download from http://www.danielwagenaar.net/teaching if it’s not already on your computer.
14
at t = 0 s and ends at t = 151 s. If you type “tms(2)-tms(1)”, you will find that the interval
between successive samples is 0.0001 s, i.e., the sampling frequency was 10 kHz.
The first thing to do now is probably to plot one of the traces, just to get a better sense of the data.
My notebook says that channel 8 corresponds to the right DP1 nerve of ganglion 6:
>> plot(tms, vlt(:,8));
If that took forever, you can opt to plot only every 10th data point, with only minimal loss of
precision:
>> plot(tms(1:10:end), vlt(1:10:end,8));
On the x-axis of the graph is time, in seconds; on the y-axis is voltage, in volts. You can use the
looking glass button to enter zoom mode, then drag a rectangle over the graph to zoom in on a
detail. That way, you can confirm that the thickets are actually bursts of individual spikes:
If you zoom back out (by double clicking on the graph), you will see that there are spikes of various
sizes. From other experiments we know that the largest spikes are from the contralateral dorsal
exciter cell 3 (motor neuron DE-3) and that the intermediate spikes are likely from the annulus
erector (AE on your ganglion map). We don’t know which cell produced the smallest spikes.
We ultimately want to extract the times of the DE-3 spikes. This recording is exceptionally clean,
so it would be easy to just select spikes with amplitude greater than 1 millivolt. Often, however, the
15
amplitudes of spikes from different neurons will not be quite as distinct, so it is useful to start by
first picking up every blip that could possibly be a spike, and select the relevant spikes in a second
step.
The first step is accomplished using the function “detectspike”:
This returns a structured variable with information about each of the spikes:
>> spk
spk =
tms: [1376x1 double]
amp: [1376x1 double]
>> clf
>> plot(tms(1:end), vlt(1:end,8));
>> hold on
>> plot(spk.tms, spk.amp, ’r.’);
>> xlabel ’Time (s)’
>> ylabel ’V (V)’
(The command “clf” clears the current graph; the command “hold on” instructs Matlab to add
subsequent plot commands to the graph rather than to replace what was previously plotted.)
(The second and third graphs are zooms of the first one.)
As you can tell, “detectspike” detected far more “spikes” than are real action potentials from
cell DE-3, and it often detected the negative as well as the positive phase from one action potential.
No problem, our goal was to find everything that could possibly be an action potential. We’ll sort
the wheat from the chaff in the next step.
2.2 Selecting the spikes that truly are DE-3’s action potentials
As we mentioned, automatic spike sorting is a topic of scientific research, and no current methods
are entirely satisfactory. Therefore, we will use a semi-automated technique. If you type:
16
a new window will pop up showing the amplitudes of all the spikes in the recording and threshold
lines. You can use the threshold lines to demarcate the spikes you care about. Notice the little
“handles” on each line. If you drag those, the lines move. By grabbing a line not near a handle,
you can make extra handles appear, so you can deal with situations where the amplitudes of spikes
from a given cell change over time. To make a handle disappear, simply drag it past the next (or
previous) handle. By dragging a rectangle over the graph (start away from the threshold lines), you
can zoom in to see details.
When you are satisfied, click “Done.” The window will disappear, and the selected spikes will be
stored in the new variable “gdspk”. You can plot them on top of the previous graph to see if the
selection criteria were good:
17
As you can see, this successfully selected all the real DE-3 spikes, and no false positives.
This would be a good time to save your work:
Exercise 17
Extract the spikes that belong to DE-3 on the DP-1 nerve on the left of ganglion 6.
They are stored in electrode channel 6 of the same file. Hint: You will notice that these
spikes have greater amplitude in the negative direction. That’s just the result of how
the electrode was wired. You may find it easier to select the negative-going peaks in
“selectspike” instead of the positive-going ones. Your choice shouldn’t significantly
affect the interpretation of your data. The next chapter will teach you techniques to
confirm that claim.
18
Chapter 3
In the previous chapter, we learned how to extract the times of action potentials (also known as
a spike train) from a nerve recording. However, extracting spike trains is just the beginning of
analyzing a recording. In this chapter, we will consider a few useful characteristics that one can
extract from a spike train.
Example 18
>> load selectedspikes6R.mat
>> t_samp = 0.01; % Let’s sample the IFR every 0.01 s.
>> tt = [0:t_samp:151]; % Recall that length of the original
>> % recording was 151 s.
>> ifr = instantfr(gdspk.tms, tt);
>> plot(tt, ifr);
>> xlabel ’Time (s)’
>> ylabel ’IFR (sˆ{-1})’
19
(This example assumes that you saved the results of spike sorting as suggested at the end of chap-
ter 2.)
Exercise 18
What happens if you sample IFR at 0.1-s intervals or 1-s intervals? Do you still get a fair
representation of the data?
A visually more pleasing result which also doesn’t suffer from the random effects of spikes falling
just to the left or to the right of the edge between two bins can be obtained by sampling using
smaller bins, and applying a low-pass filter.
20
Example 19
>> t_samp = 0.01; % Sample in bins of 0.01 s.
>> tau = 1; % Low-pass to τ = 1 s.
>> [fr, tt] = hist(gdspk.tms, [0:t_samp:151]);
>> [b, a] = butterlow1(t_samp / tau); % Prepare the filter.
>> ffr = filtfilt(b, a, fr / t_samp); % Calculate smoothed FR.
>> plot(tt, ffr);
(Note for the curious: “butterlow1(f_0/f_s)” prepares a first-order low-pass Butterworth fil-
ter with cut-off frequency f0 /fs , and “filtfilt” applies that filter twice, once in the forward
direction, and once backwards. The net result is a second-order low-pass filter with zero phase
shift.)
Exercise 19
Create a figure that contains both the IFR from example 18 (in blue) and the smoothed
firing rate from example 19 (in red). Zoom in on a burst. Do you understand the differ-
ences between the two curves? Advanced: Why is it not a good idea to use the IFR as
the starting point for smoothing. (DAW is happy to discuss.)
Depending on your application, various different timescales can be used for the calculation of firing
rates. In the example below, we use τ = 0.1 s, 1 s, 10 s, and 100 s.
21
Exercise 20
Can you add a line to the figure created in the above example that represents the av-
erage firing rate? In calculating the average, does it matter (much) whether you first
apply a low pass filter? Why (not)?
Example 21
>> load selectedspikes6R.mat
>> bi = burstinfo(gdspk.tms, 1.0, 151); % The last parameter ...
% specifies the length of the recording.
>> clf; hold on
>> plot(gdspk.tms, gdspk.amp / max(gdspk.amp), ’k.’);
>> plot(bi.t_start, 1.1, ’r<’);1
>> plot(bi.t_end, 1.1, ’r>’);
>> axis([0 151 0.7 1.2])
>> xlabel ’Time (s)’
1
Note for aficionados: The latest version of Matlab allows you to plot a scalar against a vector (as in
“plot(bi.t_start, 1.1)”). It automatically turns “1.1” into a vector of the right length.
22
In the graph, the beginnings of detected bursts are marked by left-pointing triangles, and the ends
by right-pointing triangles. Note that the final burst in the recording is not marked. This is because
it was still in progress at the time the recording was ended (t = 151 s). Thus, reporting its end time
as the time of the last recorded spike would be inaccurate, and “burstinfo” chooses to not report
on it at all. If you do want to know about it, you can pretend that the recording went on forever
by not specifying an end time: “bi = burstinfo(gdspk.tms, 1.0)”. Note also that the pair
of spikes around t = 43 s was not detected as a burst; this is because “burstinfo” only considers
sequences of at least three spikes to be bursts.
Exercise 21
What is the average duration of bursts in the above example? What is the maximum in-
terval between two consecutive bursts? Is the number of spikes in each burst correlated
with the duration of those bursts? With the preceding interval? Hint: “burstinfo” re-
turns all the parameters you need for this exercise. To investigate correlation, you can
simply plot the relevant parameters against each other, or use the “corrcoef” function.
23
Intermezzo
Congratulations! You have covered all the ground needed to analyze the data from today’s lab
exercise. The remaining chapters of this tutorial introduce several other techniques that you may
find useful for analyzing electrophysiological data, but they are not critical for today’s work. we
suggest you read them at your leisure.
We hope the whirlwind pace of chapters two and three hasn’t overwhelmed you. It is no problem
at all if you have not understood all of the fine points. We just hope you will take home the lesson
that Matlab is a very flexible tool, and that you are now not afraid to further explore it on your
own. For those of you who still feel uncomfortable working with Matlab, that is okay as well; as
you have learned in the various demos, your pClamp software has built-in routines that can cover
some of the basics of the analyses presented here (e.g., spike detection). DAW has used Matlab for
over a decade now, and is still getting better at it, so please do not be discouraged if this tutorial
felt a little (or very) overwhelming; we covered a lot of material in a very short time. Do feel free
to come to us with any questions you may have, even if you’re not sure how to phrase them.
On a final note, although this tutorial has spoken exclusively about Matlab, we do not want to
leave you with the impression that Matlab is the only game in town. In fact, there are several other
software packages that allow you to do this sort of analysis. We would like to mention three by
name, because they are free and open-source software (unlike Matlab which costs money).
The first, “Octave,” is almost a drop-in replacement for Matlab, if you can live without Matlabs’s
polished user interface and many of its toolboxes. Apart from that, Octave is so much like Matlab
that all of the examples from chapter one work just fine in Octave. The current version of Octave
(http://www.gnu.org/software/octave) still misses a few functions so that “selectspike” doesn’t
run, but I have created a special version (called “iselectspike”) that works on the Linux version of
Octave and can probably be made to work on the Mac and Windows versions. Let me know if you
are interested in using this.
The second, “SciPy,” is also similar to Matlab in intent, but quite different in implementation: it
is a collection of extensions to the Python language. SciPy is very much worth exploring, and not
only if your institute doesn’t subscribe to Matlab. A particularly nice way to use SciPy is from within
the “Jupyter” system, which allows you to keep analysis notes right along with your code. A good
starting point to learn about SciPy is http://scipy.org. Most Linux distributions have precompiled
versions available, and Windows downloads are available through the web page. Jupyter is at
http://jupyter.org. If you like Python, you may well love SciPy. Otherwise, Matlab/Octave may be
easier to learn.
Finally, there is “R,” which is targeted specifically at statistics. It contains built-in support for
any statistical test you are ever likely to encounter, good graphics support, and excellent documen-
tation, but its handling of large data sets and general programming support is not quite as good as
Matlab, Octave, or SciPy. R may be found at http://www.r-project.org/, and as part of many Linux
distributions. (For Ubuntu, e.g., the package to install is called “r-base.”)
24
Chapter 4
Note: We do not expect you to get to this chapter before moving on to today’s lab work. You can work
on it later as your schedule permits.
In the previous two chapters, we analyzed extracellularly recorded spikes. What if you have an
intracellular recording? After the initial step of detection, analyzing intracellularly recorded spike
trains is no different from extracellularly recorded ones: in either case, one works with a series
of timestamps. However, the process of detecting intracellular spikes is quite different from the
one for extracellular spikes, because intracellular spikes have a different shape than extracellular
spikes, and intracellular recordings are susceptible to different sources of noise. In this chapter, we
will discuss how to handle these.
For your reference, I have stored all of the following code in a script file called “intracel.m”.
Example 22
>> load intracel.mat
>> figure(1); clf
>> subplot(2, 1, 1);
>> plot(tt, ii);
>> xlabel ’Time (s)’
>> ylabel ’Current (nA)’
>> subplot(2, 1, 2);
>> plot(tt, vv);
>> xlabel ’Time (s)’
>> ylabel ’Voltage (mV)’
Exercise 22
I surreptitiously introduced the function “subplot” in the above example. As you
see, this splits a figure window so that it can contain multiple graphs. Type “help
subplot” to learn more, and create a 2x2 layout of the raster plots and firing rate
plots of the left and right DP1 nerve recordings in the data set we used in the previous
two chapters. Save your code in a “.m” file for future reference.
The data in example 22 are from a recording by Krista Todd. The top trace shows injected current,
the bottom trace recorded voltage from a DE-3 cell in a preparation where the ganglion was left
25
attached to a portion of body wall so that muscle actions could be observed. Looking at the graphs,
you will notice that the voltage trace is badly polluted by at least two artefacts: (1) bridge balance
was incomplete, resulting in a jump near the start and end of the stimulus, and (2) during the be-
ginning of the stimulus, the baseline voltage drifted considerably (due to motion artefacts). Please
note that these problems should not be blamed on Krista; intracellular recording from this kind of
preparation is quite a tour-de-force. Still, we need to remove them in order to reveal the action
potentials.
Example 23
>> L=length(vv); >> figure(2); clf
>> DI=4; >> plot(tt, yy);
>> yy=vv; >> xlabel ’Time (s)’
>> badidx=find([nan ... >> ylabel ’Voltage (mV)’
abs(diff(ii))]>.1);
>> for k=1:length(badidx)
i0=max(badidx(k)-DI, 1);
i1=min(badidx(k)+DI, L);
v0 = yy(i0);
v1 = yy(i1);
yy(i1:end)=yy(i1:end) ...
+ v0-v1;
yy(i0+1:i1-1)=v0;
end
Note for the curious: we measured the recorded voltage DI = 4 samples before and after the step,
and subtracted the difference.
Exercise 23
Why did I write “max(badidx(k)-DI, 1)” in the example? Could I simply have writ-
ten “badidxk-DI”? (What if one of the current steps was very close to the beginning
of the recording?)
26
Example 24
>> dt_s = mean(diff(tt)); >> figure(3); clf
>> f0_hz = 1/dt_s; >> plot(tt, zz);
>> fcut_hz = 50; >> xlabel ’Time (s)’
>> [b, a]=butterhigh1... >> ylabel ’Voltage (mV)’
(fcut_hz/f0_hz);
>> zz=filtfilt(b, a, yy);
Exercise 24
Experiment with different values of the cutoff frequency in the above example. Might
25 Hz or 100 Hz be better than 50 Hz? How would you judge?
Example 25
>> ww = templatefilter(zz, ...
f0_hz/60, 200/f0_hz,
50);
>> figure(4); clf
>> plot(tt, ww);
>> xlabel ’Time (s)’
>> ylabel ’Voltage (mV)’
>> axis([3 4 -1 2])
After removing all these artefacts, the trace looks reasonably clean; time to detect action potentials.
27
4.4 Detecting the actual action potentials
If you zoom around in the trace, you will notice that the amplitude of action potentials is quite
variable, especially during the stimulus. In cases like this, it may take a bit of trial and error to find
the best threshold. We can use the same basic technique as for extracellular spikes, but the firing
rate in this example is so high that we must use a shorter window than before to estimate the RMS
noise, and also a lower initial threshold:
Example 26
>> spk=detectspike(ww, tt, 2, >> figure(5); clf
2); >> plot(tt, ww);
>> gdspk=selectspike(spk); >> hold on
>> plot(spk.tms, spk.amp, ’k.’);
>> plot(gdspk.tms, gdspk.amp,
’r.’);
>> xlabel ’Time (s)’
>> ylabel ’Voltage (mV)’
Exercise 26
Do you agree with where I drew the threshold line in the above example? Can you do
better?
4.5 Conclusion
If you did the last exercise, you will have realized that, in cases like this where the signal-to-noise
ratio is very low, setting a threshold will always be somewhat arbitrary. Still, this method probably
yields a reasonably good estimate of the firing rate. Of course, if you are recording from a Retzius
or sensory cell—with much larger action potentials—your signal-to-noise ratio will be a lot better,
and your confidence in spike detection will be correspondingly greater.
28
Chapter 5
If you have simultaneously recorded data from multiple intracellular or extracellular electrodes,
you can of course use the techniques from the previous chapters to analyze the recordings sep-
arately. Frequently, however, much can be learned from the relationship between two recording
channels. In this chapter, we will consider the example of a simultaneous intracellular and extracel-
lular recording from the same neuron. In particular, we shall be concerned with the delays between
recorded spikes. For the examples below, you may either use your own data, or the test data set
provided.
(These data were stored in a special file format defined by acquisition software created in my lab,
but you don’t need to worry about the details: “loadephys” knows how to load the relevant data.)
Let’s take a look at what we loaded:
>> whos
Name Size Bytes Class
tms 110000x1 880000 double array
vlt 110000x6 5280000 double array
Unlike in the example in Chapter 2, there are only three channels of interest here: Intracellular
voltage is stored in channel 2, intracellular current in channel 4, and extracellular voltage in chan-
nel 6. (Data from a second extracellular electrode is in channel 5, but those data are not of interest
here.)
Scale factors have not been properly preserved (because of a bug in the software I used to record
these data), so let’s avoid confusion by giving better names to the various signals:
With that, let’s start by looking at the various signals. We’ll plot them in three “subplots,” and use a
clever Matlab trick to allow zooming into all three at the same time:
29
>> figure(1); clf
>> subplot(3, 1, 1); plot(tms, Vint mV, ’b’);
>> subplot(3, 1, 2); plot(tms, Iint nA, ’r’);
>> subplot(3, 1, 3); plot(tms, Vext uV, ’k’);
>> linkaxes(get(gcf, ’children’), ’x’);
(If you are using an older version of Matlab at home, you won’t have the “linkaxes” function
available, so you might be better off plotting everything in one plot.)
The results of the previous plot commands (left), and after labeling the axes and zooming in (right).
In the top panel, the “rabbit ears” resulting from the current steps are clearly visible, as are the
evoked action potentials. In the bottom panel, spikes from several different cells can be seen, and
it is hard to tell which ones belong to the neuron with the intracellular electrode in it. Perhaps it
might help to overlay the intracellular and extracellular traces?
30
(I hand-drew those green annotations.) Now, we can clearly see that extracellular spikes of a specific
size tend to follow intracellular spikes.
Exercise 27 (Not Matlab-related.)
What do you think happened during the second stimulus?
Hint: What extracellular event occurred just before the expected spike?
We could now proceed to extract the extracellular spikes as in Chapter 2, and to extract the in-
tracellular spikes as in Chapter 4, but picking out the right extracellular spikes might be difficult
because of the presence of other spikes of similar amplitude. Let’s therefore try something else.
Detecting spikes in very clean intracellular recordings like this one should be easy, and it is. I’ve
written a convenient Matlab function that let’s you pick them out:
>> intspk = selspktrace(Vint mV, tms);
The “selspktrace” window after zooming and dragging the limit lines to appropriate locations.
Now we know when each of the intracellular spikes happened. Thus, we could look at the extracel-
lular trace right around these events. The most direct way to do that might be this:
>> figure(1); clf; hold on
>> N = length(intspk.tms);
>> clr = jet(N);
>> for k=1:N
idx=find(tms==intspk.tms(k));
if idx>200 & idx<length(tms)-200
plot(tms(idx-200:idx+200)-tms(idx), ...
Vext uV(idx-200:idx+200), ’color’, clr(k,:));
end
end
31
The result looks like this:
To take the tedium out of that, I’ve created a a function that automatically extracts data around
events. As a bonus, it also calculates the “event-triggered average”: the average of the data collected
around each of the events. You use it like this:
Exercise 29
Can you overlay the average intracellular trace on the top panel of the above graph?
Based on the output of “trigavg”, calculating things like the average propagation delay is straight-
forward:
32
Exercise 30 (Not Matlab-related).
Why did I consider the time of the extracellular spike to be the time of its negative
peak?
Exercise 31
How can you tell whether any intracellular events did not cause a corresponding extra-
cellular spike? Could you encode your answer as a Matlab function that automatically
finds out which action potentials failed to propagate?
One rather elaborate solution to that last exercise are the functions “trigavgmax” and “trigavgfail”.
Especially “trigavgmax” is more general and more ambitious in its scope than would be strictly
necessary for this application, but you may be interested to read the source code. Regardless, they
work like this:
33
Chapter 6
This chapter contains some notes on further analyzing your data. It is not nearly as thorough as
previous chapters, but hopefully at least somewhat useful.
The bottom trace shows the current applied to an RC circuit; the top trace shows the resulting
voltage. We are going to determine the time constant of each of the transitions. By zooming into
the graphs, it is easy to determine that the transitions occur at 0.12 s, 0.62 s, 1.12 s and 1.62 s.
Alternatively, you can use Matlab to find the transitions:
34
>> [iup, idn] = schmitt(dat(:,3), -0.2, -0.4, 1);
>> iup=iup(iup>1);
>> ttrans = tms(sort([iup; idn]))’
ttrans =
[ 0.1160 0.6160 1.1160 1.6160 ]
(The function “schmitt” reports an upward transition at the beginning of the trace because the
initial voltage is above its threshold; the second line above drops this transition from further con-
sideration.)
Let’s fit an exponential to the first transition:
>> t0 = ttrans(1)
t0 =
0.1160
>> idx = find(tms>t0+0.002 & tms<t0+0.40);
>> [fit, yy] = physfit(’expc’, tms(idx), dat(idx,1));
>> subplot(2, 1, 1); hold on; plot(tms(idx), yy1, ’r’);
>> fit.p
ans =
1.0e+03 *
3.5716 -0.0428 -0.0249
>> fit.form
ans =
A*exp(B*x) + C
In other words, τ = 1/42.8 = 0.0233 s and the trace asymptotes to −24.9 mV. The red trace overlaid
on the data is the fitted curve; evidently, the fit quality is pretty good.
35
Exercise 32
Based on those numbers, can you calculate the values of R and C? Note that the current
injected was:
>> mean(dat(idx, 3))
ans =
-0.5204
i.e., 0.52 nA.
Let’s step back for a moment, and consider what we just did. The main magic was the “physfit”
call. This function is a general function fitter. It can fit straight lines, sinusoids, polynomials, expo-
nentials, and several other predefined functional forms, as well as arbitrary user-defined functions.
Beside returning the fit parameters (in “fit.p”), it also tells you the uncertainty in those parame-
ters (in “fit.s”). If you tell it the uncertainty in your data, it will also report the quality of the fit.
For instance, you could measure the noise inherent in your data:
Since χ2 is close to one, we conclude that the fit is indeed very good. (If you call “physfit” in this
way, “fit(1)” returns a fit of the data that disregards the uncertainties, and “fit(2)” returns a
fit that uses the uncertainties.)
Exercise 33
Fit curves to the other transitions. Do the numbers agree? Hint: The elegant solution
uses a “for” loop.
Obviously, we have only scratched the surface of what “physfit” can do, but hopefully you now
have a basis for further explorations on your own.
36