(Added December 2017)
In the examples of the manuscript, all of the dynamic clamp conductances were calculated by the Teensy microcontroller itself, by numerically integrating differential equations. This is fine for most intrinsic conductances, which can typically be modeled in the Hodgkin-Huxley way, and for many synaptic conductances. However, there are cases for which numerical integration is unsatisfactory: (1) when one wishes to use conductance waveforms that are generated externally, and (2) when one wishes to model synaptic conductances using a specific form (e.g., difference of exponentials) that does not easily lend itself to numerical integration.
(1) External conductances
A typical experiment would be to measure excitatory and inhibitory currents in voltage clamp, perhaps in vivo or in culture, and then to feed conductances derived from these recordings into a neuron in the more controlled and manipulable environment of a brain slice. To do this, one needs the Teensy microcontroller’s analog inputs to simultaneously measure three quantities: the membrane potential (Vm), the excitatory conductance (gexc), and the inhibitory conductance (ginh). The main dynamic clamp sketch (dynamic_clamp.ino) is sub-optimal for this task because it relies on the built-in analog read function of the Teensyduino version of the Arduino language, namely analogRead(). A call to this function takes several microseconds; three sequential calls to this function limit the maximum possible update rate and introduce undesirable temporal jitter.
Instead, in the Arduino sketch external_conductances.ino (available at the dynamic clamp Github site), we read the analog inputs more directly by addressing the hardware registers. This new sketch would be used in place of dynamic_clamp.ino when one wants to use externally-generated conductances. It does not include the Hodgkin-Huxley and other conductances coded in the main sketch. However, combining the two shouldn’t be difficult — and we leave it as an exercise for the reader 😊. The calibration parameters (for the amplifier and the breadboard) are unchanged from those of dynamic_clamp.ino, as these are independent of the conductances being simulated. All that the user need specify are (A) which channels to use for the external conductances, (B) what their reversal potentials are, and (C) how to scale the voltage inputs representing the arbitrary conductance waveforms so as to convert volts to nanosiemens. About part (C): the voltage waveforms representing the arbitrary conductance waveforms must be between 0 V and 3.3 V. Anything outside this range will damage the Teensy microcontroller’s analog inputs. So, for example, if you wish to use conductances between 0 nS and 33 nS, what you should do is specify a scaling factor of 10. In this case, 1 V read by the Teensy would be interpreted as 10 nS, 2.25 V would be interpreted as 22.5 nS, and so on.
In the default settings of external_conductances.ino, we imagined the following scenario: an excitatory conductance (reversal potential 0 mV) is being fed into Teensy input A1 and an inhibitory conductance (reversal potential -80 mV) is being fed into Teensy input A12. (Teensy input A13 is also being monitored, but its reading is not being used for anything.) For both types of conductances, the voltage signals (V) at these inputs can be transformed into conductances (nS) using a scaling factor of 10 nS/V. The sampling frequency (update rate) is 100 kHz.
Shown above is the first section of the sketch external_conductances.ino. The first two parts (“Scaling for the patch clamp …” and “Calibrating the input/output …”) are unchanged from what was in dynamic_clamp.ino. The third part specifies a sampling frequency of 100000 Hz, indicates that the first two additional input channels (A1 and A12) are in use, whereas the third (A13) is not (A0, the input channel for Vm, is always assumed to be in use); specifies a reversal potential of 0 mV for the first (excitatory) conductance and -80 mV for the second (inhibitory) conductance; and specifies that the scaling factors of the first two channels are 10 nS/V. The very last part indicates that analog input A0 will be used, as always, to measure Vm whereas channels A1 and A12 will be used to measure the excitatory and inhibitory signals, respectively. The dynamic clamp command to the amplifier, as always, goes through A21.
Before using this sketch, you should physically connect whatever the sources of your excitatory and inhibitory conductance waveforms are to analog inputs A1 and A12 of the Teensy microcontroller.
If you find that the recorded data is too noisy given this configuration, the first thing to try is to reduce the sampling frequency (e.g., from 100 kHz to 50 kHz or 25 kHz). Doing this allows the microcontroller to average more samples at its analog inputs. This results in slower (but still fast) signals that are smoother.
(2) Saved conductances
In some cases, experimenters may wish to use a conductance waveform that cannot (easily) be expressed in terms of a differential equation. For example, many papers model synaptic currents or conductances by a difference of exponentials:
The functional form is known, but it’s not straightforward how to translate this into an equation that can be numerically integrated, in the way the Hodgkin-Huxley equations can. One possibility is to generate the waveform on the host computer (as a time series), send it out through the DAQ board, and have it read by the Teensy as an external conductance, as in part (1) above. Another possibility is to generate the waveform on the Teensy microcontroller and have the Teensy read it out element by element in real time.
We demonstrate the second possibility in the Arduino sketch saved_conductances.ino, which is available at the Github site. That sketch simulates a train of EPSCs, each of which is modeled as a difference of exponentials. The EPSC train is created and put in memory when the sketch is first uploaded. Each time a TTL trigger is received at pin 2, the train is read out. The tabbed file EPSC_saved.ino contains the code for creating the train.
Two issues to keep in mind: (i) The Teensy has a limited amount of memory (256 kB) and that limits how long the saved waveform can be. At an update rate of 20 kHz, a 1-second-long waveform takes up nearly a third of available memory. (ii) For the waveform to be read out correctly, the temporal jitter must be as small as possible. In the example sketch, we achieve small jitter (<1 usec) by using a moderate update rate (20 kHz) and using elapsedMicros() to check timing. Another idea, which we haven’t explored yet, is to use Direct Memory Access (DMA). You can read about DMA and DAC in the forums of the Teensy site pjrc.com.