├── src └── pyNCS │ ├── changes │ ├── api │ ├── __init__.py │ ├── loopbackAPI.py │ ├── BaseConfAPI.py │ ├── ComAPI.py │ ├── BaseComAPI.py │ ├── IFSLWTA_brian_model.py │ ├── paramTranslation.py │ ├── BrianAPI.py │ └── ConfAPI.py │ ├── pyST │ ├── pyST_globals.py │ ├── __init__.py │ └── STsl.py │ ├── data │ ├── setuptype.dtd │ └── setup.dtd │ ├── __init__.py │ ├── connection.py │ └── experimentTools.py ├── docs ├── general │ ├── api.txt │ ├── modules.txt │ ├── new_hardware.txt │ ├── pytune_xml_file_template.txt │ ├── pytune_plugin.txt │ ├── pyNCS.AerViewer.txt │ ├── pyNCS.pyST.txt │ ├── pyNCS.txt │ ├── experiments.txt │ ├── hardware_setup.txt │ ├── pyst.txt │ ├── aex_reprogramming.txt │ ├── learning.txt │ ├── pyosc.txt │ ├── pytune_python_file_template.txt │ ├── introduction.txt │ ├── spcm.txt │ ├── tutorial.txt │ └── installation.txt ├── images │ ├── fig1.png │ ├── pytune.png │ ├── raw_data.png │ ├── software.jpg │ ├── software.png │ ├── mapping_2d.png │ ├── mapping_all.png │ ├── amda_and_aex.jpg │ ├── decorated_data.png │ ├── zenzero_setup.png │ ├── raster_tutorial.png │ ├── meanrate_tutorial.png │ └── normalized_data_zoomed.png ├── examples │ ├── examples.txt │ └── reservoir.txt ├── index.txt ├── Makefile └── conf.py ├── .gitmodules ├── test ├── pyST_testbed.py ├── pyNCS_testbed.py ├── chipfiles │ ├── linear.xml │ ├── tmpdiff64.csv │ ├── linear.csv │ ├── ifmem.xml │ ├── tmpdiff64.xml │ ├── sac.xml │ ├── sac.csv │ ├── ifmem.csv │ ├── if2dwta.xml │ ├── if2dwta.csv │ └── ifslwta.csv ├── setupfiles │ ├── test.xml │ ├── test_performance.xml │ └── test_setuptype.xml ├── testComAPI.py ├── biases │ ├── defaultBiases_if2dwta │ └── defaultBiases_ifslwta ├── test_performance.py ├── expSetup.py └── pyNCS_unittest.py ├── README.md ├── .gitignore ├── .project ├── .pydevproject └── setup.py /src/pyNCS/changes: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/general/api.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/fig1.png -------------------------------------------------------------------------------- /docs/images/pytune.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/pytune.png -------------------------------------------------------------------------------- /docs/images/raw_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/raw_data.png -------------------------------------------------------------------------------- /docs/images/software.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/software.jpg -------------------------------------------------------------------------------- /docs/images/software.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/software.png -------------------------------------------------------------------------------- /docs/images/mapping_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/mapping_2d.png -------------------------------------------------------------------------------- /docs/images/mapping_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/mapping_all.png -------------------------------------------------------------------------------- /docs/general/modules.txt: -------------------------------------------------------------------------------- 1 | pyNCS 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | pyNCS 8 | -------------------------------------------------------------------------------- /docs/images/amda_and_aex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/amda_and_aex.jpg -------------------------------------------------------------------------------- /docs/images/decorated_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/decorated_data.png -------------------------------------------------------------------------------- /docs/images/zenzero_setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/zenzero_setup.png -------------------------------------------------------------------------------- /docs/images/raster_tutorial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/raster_tutorial.png -------------------------------------------------------------------------------- /docs/images/meanrate_tutorial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/meanrate_tutorial.png -------------------------------------------------------------------------------- /src/pyNCS/api/__init__.py: -------------------------------------------------------------------------------- 1 | #import BrianAPI 2 | from __future__ import absolute_import 3 | from . import ComAPI,ConfAPI 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/pyNCS/data/NHML"] 2 | path = src/pyNCS/data/NHML 3 | url = https://github.com/inincs/NHML.git 4 | -------------------------------------------------------------------------------- /docs/images/normalized_data_zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inincs/pyNCS/HEAD/docs/images/normalized_data_zoomed.png -------------------------------------------------------------------------------- /test/pyST_testbed.py: -------------------------------------------------------------------------------- 1 | import pyST_unittest 2 | 3 | test=pyST_unittest.TestSequenceFunctions(methodName='setUp') 4 | test.setUp() 5 | -------------------------------------------------------------------------------- /test/pyNCS_testbed.py: -------------------------------------------------------------------------------- 1 | import pyNCS_unittest 2 | 3 | test=pyNCS_unittest.TestSequenceFunctions(methodName='setUp') 4 | test.setUp() 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pyNCS 2 | ===== 3 | 4 | pyNCS is a python library that allows easy access to Neuromorphic Chips and Setups 5 | 6 | Documentation is available at [http://inincs.github.com/pyNCS/] 7 | 8 | The Wiki page is at [https://github.com/inincs/pyNCS/wiki] 9 | 10 | Requires: 11 | Python >= 2.6 12 | 13 | Does NOT require: 14 | traits-gui 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | .*.sw[a-z] 3 | 4 | # Packages 5 | *.egg 6 | *.egg-info 7 | dist 8 | build 9 | _build 10 | eggs 11 | parts 12 | bin 13 | var 14 | sdist 15 | develop-eggs 16 | .installed.cfg 17 | 18 | # Installer logs 19 | pip-log.txt 20 | 21 | # Unit test / coverage reports 22 | .coverage 23 | .tox 24 | 25 | #Translations 26 | *.mo 27 | 28 | #Mr Developer 29 | .mr.developer.cfg 30 | -------------------------------------------------------------------------------- /test/chipfiles/linear.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | pyNCS 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/general/new_hardware.txt: -------------------------------------------------------------------------------- 1 | Controlling new hardware with pyNCS 2 | =================================== 3 | 4 | Neuromorphic chips 5 | ------------------ 6 | 7 | In order to use new chips with the existing software, a bunch of files need to 8 | be written. 9 | 10 | - csv 11 | - xml 12 | 13 | ... 14 | 15 | New oscillocope 16 | --------------- 17 | 18 | - how to import drivers into pyOsc 19 | 20 | New anything else 21 | ----------------- 22 | -------------------------------------------------------------------------------- /src/pyNCS/pyST/pyST_globals.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: Emre Neftci 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | 10 | 11 | DefaultMonChannelAddress = None 12 | DefaultSeqChannelAddress = None 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/general/pytune_xml_file_template.txt: -------------------------------------------------------------------------------- 1 | :: 2 | 3 | 4 | 5 | inf 6 | 0 7 | Hz 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | python 2.7 6 | Default 7 | 8 | /pyNCS/src 9 | /pyNCS/test 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/general/pytune_plugin.txt: -------------------------------------------------------------------------------- 1 | pyTune plugins explained 2 | ======================== 3 | 4 | pyTune controls neuromorphic system by means of plugins. A plugin basically 5 | translates pyTune informations (classes, methods, attributes, keywords, ...) 6 | into system-specific ones. For example, the pyNCS plugin for pyTune contains 7 | methods for setting the biases of the chips when calling ``set`` functions. 8 | Once a new plugin is implemented, all the features of pyTune should be 9 | available right away. 10 | 11 | -------------------------------------------------------------------------------- /test/chipfiles/tmpdiff64.csv: -------------------------------------------------------------------------------- 1 | "chipclass" "TMPDIFF64" 2 | 3 | "aerOut" 4 | "id" "x" "range" "range(2**6)" "type" "1" func "X" 5 | "id" "y" "range" "range(2**6)" "type" "1" func "Y>>1" 6 | "id" "p" "range" "range(2)" "type" "-1" func "Y&1" 7 | 8 | 9 | pinid X func x 10 | pinid Y func (y<<1)+p 11 | "pinlayout" "X4 X3 X2 X1 X0 X5 Y6 Y5 Y4 Y3 Y2 Y1 Y0" 12 | 13 | "Count" "Pad#" "Pin#" "Circuit Block" "Signal Name" "FET" "BIAS type" "PAD type" "Range" "Simulation value" "Description" "Channel#" 14 | 15 | -------------------------------------------------------------------------------- /test/setupfiles/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/setupfiles/test_performance.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/chipfiles/linear.csv: -------------------------------------------------------------------------------- 1 | "chipclass" "LINEAR" 2 | 3 | "aerIn" 4 | "id" "x" "range" "range(2**12)" "type" "1" "f" "X" 5 | "id" "s" "range" "range(1)" "type" "-1" "f" "Y" 6 | 7 | 8 | "pinid" "X" "f" "x" 9 | "pinid" "Y" "f" "s" 10 | "pinlayout" "X11 X10 X9 X8 X7 X6 X5 X4 X3 X2 X1 X0 Y0" 11 | 12 | "aerOut" 13 | "id" "x" "range" "range(2**12)" "type" "'1'" "f" "X" 14 | 15 | 16 | "pinid" "X" "f" "x" 17 | "pinlayout" "X11 X10 X9 X8 X7 X6 X5 X4 X3 X2 X1 X0" 18 | 19 | Count PIN PKG CircuitBlock SignalName FET BiasType PadType Range SimulationValue Description Channel Shared with 20 | -------------------------------------------------------------------------------- /test/testComAPI.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | #----------------------------------------------------------------------------- 3 | # File Name : testComAPI.py 4 | # Purpose: 5 | # 6 | # Author: Emre Neftci 7 | # 8 | # Creation Date : 05-06-2013 9 | # Last Modified : Wed 05 Jun 2013 06:47:18 PM PDT 10 | # 11 | # Copyright : (c) 12 | # Licence : GPLv2 13 | #----------------------------------------------------------------------------- 14 | 15 | from pyNCS.ComAPI import * 16 | 17 | class Communicator(BatchCommunicatorBase): 18 | def run(self, stimulus=None, duration=None, context_manager=None): 19 | return stimulus 20 | 21 | -------------------------------------------------------------------------------- /docs/examples/examples.txt: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | Contents: 5 | 6 | .. :toctree: 7 | :maxdepth: 2 8 | 9 | reservoir.txt 10 | 11 | Hello world 12 | ----------- 13 | 14 | Feed-forward network: Antennal Lobe of insects 15 | ---------------------------------------------- 16 | 17 | Recurrent network: Winner-Take-All 18 | ---------------------------------- 19 | 20 | Recurrent network: reservoir 21 | ---------------------------- 22 | 23 | Learning: attractors 24 | -------------------- 25 | 26 | Learning: perceptron 27 | -------------------- 28 | 29 | Learning: thalamo-cortical model 30 | -------------------------------- 31 | -------------------------------------------------------------------------------- /src/pyNCS/data/setuptype.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/setupfiles/test_setuptype.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/chipfiles/ifmem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from distutils.core import setup 3 | import os 4 | 5 | setup(name='pythonNCS', 6 | version='20170129', 7 | description='Python Neurormophic Chips and Systems', 8 | author='Sadique Sheik, Emre Neftci, Fabio Stefanini, Giacomo Indiveri', 9 | author_email='sadique@ini.phys.ethz.ch, eneftci@uci.edu, giacomo@ini.phys.ethz.ch, fabios@ini.phys.ethz.ch', 10 | url='https://github.com/inincs/pyNCS', 11 | download_url='https://github.com/inincs/pyNCS/tarball/stable_20170129', 12 | packages = ['pyNCS', 'pyNCS.pyST', 'pyNCS.api'], 13 | package_dir={'pyNCS' : 'src/pyNCS'}, 14 | package_data={'pyNCS' : ['data/*.dtd', 15 | 'data/chipfiles/*.csv', 16 | 'data/chipfiles/*.nhml', 17 | 'data/chipfiles/*.xml']}, 18 | ) 19 | -------------------------------------------------------------------------------- /test/biases/defaultBiases_if2dwta: -------------------------------------------------------------------------------- 1 | Aepd 0.6 2 | req_puY 2 3 | req_puX 2 4 | selpu 2.5 5 | selx0 0 6 | selx1 0 7 | selx2 0 8 | selx3 0 9 | selx4 0 10 | selx5 0 11 | sely0 0 12 | sely1 0 13 | sely2 0 14 | sely3 0 15 | sely4 0 16 | muxx0 0 17 | muxx1 0 18 | muxx2 0 19 | muxy0 0 20 | muxy1 0 21 | ringonoff 3.3 22 | nadap 0 23 | nlk 0.17 24 | nlkadap 0.30001 25 | nrf 0.25 26 | nsf 0.6 27 | inj 3.3 28 | nsynlocplswdt 0.45 29 | nsynlocselfw 0 30 | nsynlocselfth 2.75 31 | psynlocselftau 2.4 32 | nsynlocth 2.9 33 | psynloctau 3.05 34 | nsynloclat1 0.0 35 | nsynlocvert1 0 36 | nsynlocvert2 0 37 | nsynaerinhplswdt 0.14 38 | psynaerinhth 0.3 39 | nsynaerinhtau 0.05 40 | psynaerinhw 3.3 41 | nsynaerexcplswdt 0.45 42 | nsynaerexcth0 2.95 43 | psynaerexcw0 0 44 | nsynaerexcwd0 0 45 | psynaerexctau0 3.05 46 | nsynaerexcth1 2.95 47 | psynaerexcw1 0 48 | nsynaerexcwd1 0 49 | psynaerexctau1 3.05 50 | FollBias 0.5 51 | llGnd 0.3 52 | -------------------------------------------------------------------------------- /test/test_performance.py: -------------------------------------------------------------------------------- 1 | from expSetup import * 2 | import time 3 | #stas=STcsMon[0] 4 | #addrPhysicalExtractDecode(stas,[3073]*10000000); 5 | # 6 | #ad=np.random.randint(0, 10000, 10000000) 7 | #tm=np.random.ranf(10000000) 8 | #t=np.column_stack([ad, tm]) 9 | #st=SpikeList(t, range(0,20000)) 10 | # 11 | 12 | nsetup = build_setup(setupfile = 'test_performance.xml') 13 | 14 | seq_pop = pyNCS.Population('default', 'Default Population') 15 | seq_pop.populate_all(nsetup, 'seq', 'excitatory') 16 | 17 | fps = 1 18 | stim = seq_pop.soma.spiketrains_poisson(rate=100, duration=1000/fps) 19 | t0 = time.time() 20 | for i in range(max(fps,0)): 21 | out = nsetup.run(stim) 22 | out[0] 23 | 24 | t1 = time.time()-t0 25 | print t1 26 | 27 | print 'Performance is {0} events per second'.format(float(stim[0].raw_data().__len__())/t1*fps) 28 | 29 | 30 | #2**15 neurons, 100 Hz, 1s. Coding, Decoding. 298682 events/second 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/general/pyNCS.AerViewer.txt: -------------------------------------------------------------------------------- 1 | AerViewer Package 2 | ================= 3 | 4 | :mod:`AerViewer` Package 5 | ------------------------ 6 | 7 | .. automodule:: pyNCS.AerViewer 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | :mod:`Aer1DViewer` Module 13 | ------------------------- 14 | 15 | .. automodule:: pyNCS.AerViewer.Aer1DViewer 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | :mod:`Aer2DViewer` Module 21 | ------------------------- 22 | 23 | .. automodule:: pyNCS.AerViewer.Aer2DViewer 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | :mod:`Updater1D` Module 29 | ----------------------- 30 | 31 | .. automodule:: pyNCS.AerViewer.Updater1D 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | 36 | :mod:`Updater2D` Module 37 | ----------------------- 38 | 39 | .. automodule:: pyNCS.AerViewer.Updater2D 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | -------------------------------------------------------------------------------- /src/pyNCS/data/setup.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/chipfiles/tmpdiff64.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/general/pyNCS.pyST.txt: -------------------------------------------------------------------------------- 1 | pyST Package 2 | ============ 3 | 4 | :mod:`pyST` Package 5 | ------------------- 6 | 7 | .. automodule:: pyNCS.pyST 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | :mod:`STas` Module 13 | ------------------ 14 | 15 | .. automodule:: pyNCS.pyST.STas 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | :mod:`STsl` Module 21 | ------------------ 22 | 23 | .. automodule:: pyNCS.pyST.STsl 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | :mod:`pyST_globals` Module 29 | -------------------------- 30 | 31 | .. automodule:: pyNCS.pyST.pyST_globals 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | 36 | :mod:`spikes` Module 37 | -------------------- 38 | 39 | .. automodule:: pyNCS.pyST.spikes 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | :mod:`stgen` Module 45 | ------------------- 46 | 47 | .. automodule:: pyNCS.pyST.stgen 48 | :members: 49 | :undoc-members: 50 | :show-inheritance: 51 | 52 | -------------------------------------------------------------------------------- /src/pyNCS/pyST/__init__.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: Emre Neftci 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | from __future__ import absolute_import 10 | from .STas import events, channelEvents, RawOutput, channelAddressing, addrSpec 11 | from .STas import setDefaultMonChannelAddress, setDefaultSeqChannelAddress,\ 12 | getDefaultMonChannelAddress, getDefaultSeqChannelAddress 13 | from .STsl import STCreate 14 | from .spikes import SpikeList, SpikeTrain, merge, merge_spikelists, \ 15 | merge_sequencers 16 | from . import pyST_globals 17 | import numpy as np 18 | 19 | 20 | def loadtxt(filename, comments, format='t'): 21 | data = np.loadtxt(filename, comments=comments) 22 | if format == 't': 23 | data = np.fliplr(data) 24 | ev = events(data, atype='l') 25 | id_list = np.unique(ev.get_ad()) 26 | return SpikeList(ev.get_adtmev(), id_list) 27 | -------------------------------------------------------------------------------- /test/chipfiles/sac.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/biases/defaultBiases_ifslwta: -------------------------------------------------------------------------------- 1 | psynaerinhw 2.5 2 | nbuf 0.5 3 | psynlocinhth 0. 4 | nsynloclat1 0. 5 | nwta 1.00004577706569009e-01 6 | thmem 0.00000000000000000e+00 7 | pbuf 2.50001373311970676e+00 8 | synaerlo 0.00000000000000000e+00 9 | nsf 0.75 10 | thk1 3.29999999999999982e+00 11 | llGnd 5.99926756694895813e-01 12 | nlpfth 2.99993591210803379e+00 13 | thk2 2.99993591210803379e+00 14 | mux1 0.00000000000000000e+00 15 | nsynaerinhtau 0.1 16 | pinj2 3.3 17 | pinj3 3.3 18 | nlk 0.02 19 | pinj1 3.3 20 | nsynlocinhtau 0.06 21 | pinj4 3.3 22 | nadap 0.0 23 | pinj 3.3 24 | nsynaerpls 0.4 25 | Aepd 6.99981689173723942e-01 26 | nsynstdwd0 0.0 27 | ScanPD 5.99926756694895813e-01 28 | nsynloclat2 0.0 29 | llVdd 3.2 30 | nLearnW 0.00000000000000000e+00 31 | FollBias 3.99967956054016915e-01 32 | psynstdtau 3.08 33 | mux2 0.00000000000000000e+00 34 | mux0 0.00000000000000000e+00 35 | nsynlocth 2.98 36 | nsynaerth 2.85 37 | nplsloc 0.4 38 | nsynexcinh 0. 39 | synaerth 0.00000000000000000e+00 40 | nrf 0.5 41 | thk3 2.79992675669489577e+00 42 | plpftau 2.39995880064087874e+00 43 | nlpfw 0.00000000000000000e+00 44 | psynaertau 2.99993591210803379e+00 45 | synaerhi 1.99999084458686172e+00 46 | nsynstdw1 0. 47 | nsynstdw0 0. 48 | SynPU 2.39995880064087874e+00 49 | nsynaerinhpls 0.14 50 | nsynlocginh 0.5 51 | psynloctau 3.11 52 | pcmp 2.89998168917372379e+00 53 | nplslocinh 0.14 54 | ring1 0.00000000000000000e+00 55 | psynaerlk 3.09999084458686180e+00 56 | nsynlocself 0.00000000000000000e+00 57 | nsynstdwd1 0.00000000000000000e+00 58 | nlkadap 4.99972533760585869e-01 59 | psynaernmda 2.39995880064087874e+00 60 | psynlocinhw 3.3 61 | nsynstdth 2.85 62 | -------------------------------------------------------------------------------- /docs/index.txt: -------------------------------------------------------------------------------- 1 | .. NCS documentation master file, created by 2 | sphinx-quickstart on Mon Nov 23 16:07:25 2009. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | pyNCS documentation 7 | =================== 8 | 9 | 10 | General 11 | ------- 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | 16 | general/introduction.txt 17 | general/installation.txt 18 | general/tutorial.txt 19 | general/experiments.txt 20 | 21 | Technical 22 | --------- 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | 27 | general/new_hardware.txt 28 | 29 | 30 | Examples 31 | -------- 32 | 33 | .. toctree:: 34 | :maxdepth: 1 35 | 36 | examples/attractor.txt 37 | examples/reservoir.txt 38 | 39 | API reference 40 | ------------- 41 | 42 | .. toctree:: 43 | :maxdepth: 99 44 | 45 | general/modules.txt 46 | 47 | 48 | .. Indices and tables 49 | .. ================== 50 | .. 51 | .. * :ref:`genindex` 52 | .. * :ref:`modindex` 53 | .. * :ref:`search` 54 | 55 | 56 | NCS specific documentation 57 | ========================== 58 | 59 | Please refer to http://ncs.ethz.ch/ncs for more information. 60 | 61 | Measurement and tuning 62 | ---------------------- 63 | 64 | .. toctree:: 65 | :maxdepth: 2 66 | 67 | general/pyosc.txt 68 | general/pytune.txt 69 | 70 | 71 | Plasticity on hardware 72 | ---------------------- 73 | 74 | .. toctree:: 75 | :maxdepth: 2 76 | 77 | general/learning.txt 78 | 79 | Technical 80 | --------- 81 | 82 | .. toctree:: 83 | :maxdepth: 2 84 | 85 | general/hardware_setup.txt 86 | general/spcm.txt 87 | general/troubleshooting.txt 88 | -------------------------------------------------------------------------------- /docs/general/pyNCS.txt: -------------------------------------------------------------------------------- 1 | pyNCS Package 2 | ============= 3 | 4 | :mod:`pyNCS` Package 5 | -------------------- 6 | 7 | .. automodule:: pyNCS.__init__ 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | :mod:`ComAPI` Module 13 | -------------------- 14 | 15 | .. automodule:: pyNCS.api.ComAPI 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | :mod:`ConfAPI` Module 21 | --------------------- 22 | 23 | .. automodule:: pyNCS.api.ConfAPI 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | :mod:`chip_v2` Module 29 | --------------------- 30 | 31 | .. automodule:: pyNCS.chip_v2 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | 36 | :mod:`connection` Module 37 | ------------------------ 38 | 39 | .. automodule:: pyNCS.connection 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | :mod:`experimentTools` Module 45 | ----------------------------- 46 | 47 | .. automodule:: pyNCS.experimentTools 48 | :members: 49 | :undoc-members: 50 | :show-inheritance: 51 | 52 | :mod:`group` Module 53 | ------------------- 54 | 55 | .. automodule:: pyNCS.group 56 | :members: 57 | :undoc-members: 58 | :show-inheritance: 59 | 60 | :mod:`mapping` Module 61 | --------------------- 62 | 63 | .. automodule:: pyNCS.mapping 64 | :members: 65 | :undoc-members: 66 | :show-inheritance: 67 | 68 | :mod:`monitors` Module 69 | ---------------------- 70 | 71 | .. automodule:: pyNCS.monitors 72 | :members: 73 | :undoc-members: 74 | :show-inheritance: 75 | 76 | :mod:`neurosetup` Module 77 | ------------------------ 78 | 79 | .. automodule:: pyNCS.neurosetup 80 | :members: 81 | :undoc-members: 82 | :show-inheritance: 83 | 84 | :mod:`population` Module 85 | ------------------------ 86 | 87 | .. automodule:: pyNCS.population 88 | :members: 89 | :undoc-members: 90 | :show-inheritance: 91 | 92 | Subpackages 93 | ----------- 94 | 95 | .. toctree:: 96 | 97 | pyNCS.pyST 98 | 99 | -------------------------------------------------------------------------------- /test/chipfiles/sac.csv: -------------------------------------------------------------------------------- 1 | "chipclass" "SAC" 2 | 3 | "aerIn" 4 | "id" "x" "range" "range(32)" "type" "1" "f" "X" 5 | "id" "y" "range" "range(32)" "type" "1" "f" "Y" 6 | "id" "s" "range" "range(1)" "type" "-1" "f" "0*X" 7 | 8 | 9 | "pinid" "X" "f" "x" 10 | "pinid" "Y" "f" "y" 11 | "pinlayout" "X4 X3 X2 X1 X0 Y4 Y3 Y2 Y1 Y0" 12 | 13 | "aerOut" 14 | "id" "x" "range" "range(2**5)" "type" "1" "f" "X" 15 | "id" "y" "range" "range(2**5)" "type" "1" "f" "Y" 16 | 17 | 18 | "pinid" "X" "f" "x" 19 | "pinid" "Y" "f" "y 20 | "pinlayout" "X4 X3 X2 X1 X0 Y4 Y3 Y2 Y1 Y0" 21 | 22 | Count PIN # PKG # Circuit Block Signal Name FET Bias Type Pad Type Range Simulation value Description Channel Shared with 23 | 1 50 aer ReqpuX dac 2.2 58 24 | 2 49 aer ReqpuY dac 2.2 59 25 | 3 66 aer AERpd dac 0.483 56 26 | 4 2 aer PIXpd dac 0.6 94 27 | 5 1 aer PIXpu dac 2.6 95 28 | 6 23 scanner SX0 dac 0.0 88 29 | 7 22 scanner SX1 dac 0.0 89 30 | 8 21 scanner SX2 dac 0.0 90 31 | 9 20 scanner SX3 dac 0.0 91 32 | 10 19 scanner SX4 dac 0.0 92 33 | 11 101 scanner SY0 dac 0.0 7 34 | 12 102 scanner SY1 dac 0.0 8 35 | 13 103 scanner SY2 dac 0.0 9 36 | 14 104 scanner SY3 dac 0.0 10 37 | 15 105 scanner SY4 dac 0.0 11 38 | 16 82 aer NETpu dac 2.79 0 39 | 17 31 wta ADAP dac 3.3 79 40 | 18 33 wta LK dac 0.194 77 41 | 19 32 wta LKCA dac 0.0 78 42 | 20 29 wta RF dac 0.285 82 43 | 21 30 wta SF dac 0.598 80 44 | 22 39 wta THRinh dac 0.3 67 45 | 23 40 wta Winh dac 2.253 66 46 | 24 41 wta TAUinh dac 0.2 65 47 | 25 44 wta W0exc dac 2.38 86 48 | 26 46 aer SYNpu dac 2.9 60 49 | 27 45 wta Wstd dac 0.369 62 50 | 28 43 wta THR dac 2.9 63 51 | 29 42 wta TAU dac 3.0 64 52 | 30 35 wta WTAbias dac 0.405 74 53 | 31 34 wta exc_wta dac 0.0 76 54 | 32 36 wta inh_wta dac 3.3 72 55 | 33 37 wta LIM dac 2.635 70 56 | 34 38 wta HYST dac 2.55 68 57 | 35 28 aer FollowBias dac 0.616 84 58 | 36 84 wta STIM dac 3.3 1 59 | 37 98 test pen dac 0.0 6 60 | 38 97 test pep dac 3.3 5 61 | 39 93 test gthr dac 3.3 4 62 | 40 92 test nmdathr dac 3.3 3 63 | 41 121 wta ref dac 3.3 2 64 | -------------------------------------------------------------------------------- /test/chipfiles/ifmem.csv: -------------------------------------------------------------------------------- 1 | "chipclass" "ifmem" 2 | 3 | "aerIn" 4 | "id" "x" "range" "range(32)" "type" "1" func X 5 | "id" "s" "range" "range(32)" "type" "-1" func Y 6 | "id" "t" "range" "range(8)" "type" "-1" func Z 7 | pinid X func x 8 | pinid Y func s 9 | pinid Z func t 10 | "pinlayout" " X4 X3 X2 X1 X0 Y4 Y3 Y2 Y1 Y0 Z2 Z1 Z0 " 11 | 12 | "aerOut" 13 | "id" "x" "range" "range(32)" "type" "1" func X 14 | pinid X func x 15 | "pinlayout" "X4 X3 X2 X1 X0" 16 | 17 | 18 | 19 | "Count" "Pad#" "Pin#" "Circuit Block" "Signal Name" "FET" "BIAS type" "PAD type" "Range" "Simulation value" "Description" "Channel#" 20 | 1 "gbNSath" "dac" 0 21 | 2 "gbSEtau" "dac" 1 22 | 3 "gbSEnmda" "dac" 2 23 | 4 "gbSEg" "dac" 3 24 | 5 "gbSEdh" "dac" 4 25 | 6 "gbSEdv" "dac" 5 26 | 7 "gbSItau" "dac" 6 27 | 8 "gbSIg" "dac" 7 28 | 9 "gbsynwex" "dac" 8 29 | 10 "gbsynwex0" "dac" 9 30 | 11 "gbsynwex1" "dac" 10 31 | 12 "gbsynwex2" "dac" 11 32 | 13 "gbsynwex3" "dac" 12 33 | 14 "gbsynwex4" "dac" 14 34 | 15 "gbSIdv" "dac" 15 35 | 16 "gbSIdh" "dac" 16 36 | 17 "gbNSaw" "dac" 17 37 | 18 "gbNScas" "dac" 18 38 | 19 "gbNSin" "dac" 19 39 | 20 "gbNSrefr" "dac" 20 40 | 21 "gbNSreset" "dac" 21 41 | 22 "gbNStau" "dac" 22 42 | 23 "gbNSth" "dac" 23 43 | 24 "gbSEthr" "dac" 24 44 | 25 "gbNSatau" "dac" 25 45 | 26 "gbSEtauDiff" "dac" 26 46 | 27 "gbSItauDiff" "dac" 27 47 | 28 "gbSIthr" "dac" 28 48 | 29 "gbsynwinh0" "dac" 35 49 | 30 "gbsynwinh1" "dac" 34 50 | 31 "gbsynwinh2" "dac" 33 51 | 32 "gbsynwinh3" "dac" 32 52 | 33 "gbsynwinh4" "dac" 32 53 | 34 "folbias" "dac" 29 54 | 35 "gbAEpd" "dac" 36 55 | 36 "b0" "dac" 52 56 | 37 "b1" "dac" 51 57 | 38 "b2" "dac" 50 58 | 39 "b3" "dac" 49 59 | 40 "b4" "dac" 48 60 | 41 "currentconv" "dac" 47 61 | 42 "scanbias" "bg" 14 62 | 43 "bsynwex0" "bg" 25 63 | 44 "bsynwex1" "bg" 28 64 | 45 "bsynwex2" "bg" 31 65 | 46 "bsynwex3" "bg" 32 66 | 47 "bsynwex4" "bg" 37 67 | 48 "inject" "bg" 9 68 | -------------------------------------------------------------------------------- /test/expSetup.py: -------------------------------------------------------------------------------- 1 | import pyNCS.pyST as pyST 2 | import time,sys,random 3 | import pyNCS 4 | import numpy as np 5 | import pylab 6 | from pyNCS.neurosetup import NeuroSetup 7 | import warnings 8 | 9 | # C O N F I G # # # # # # # # # # # # # # # # # # # # # # 10 | 11 | et=pyNCS.et 12 | 13 | # set dirnames 14 | def set_default_biases(nsetup=None, biases_dir='biases/'): 15 | for c in nsetup.chips.itervalues(): 16 | 17 | filename='' 18 | try: 19 | if not c.virtual: 20 | filename=biases_dir+'defaultBiases_'+c.chipclass.lower() 21 | c.load_parameters(filename) 22 | except IOError as (errno, strerror): 23 | warnings.warn("I/O error({0}): {1}".format(errno, strerror)) 24 | warnings.warn("Could not find file {0}".format(filename)) 25 | pass 26 | 27 | def build_setup(setupfile = 'test.xml'): 28 | nsetup = NeuroSetup( 29 | 'setupfiles/test_setuptype.xml', 30 | 'setupfiles/'+setupfile, 31 | offline=False) 32 | set_default_biases(nsetup=nsetup, biases_dir='biases/') 33 | return nsetup 34 | 35 | if __name__ == '__main__': 36 | nsetup = build_setup() 37 | nsetup.chips['ifslwta'].set_parameter('pinj', 2.82) 38 | 39 | seq_pop = pyNCS.Population('default', 'Default Population') 40 | seq_pop.populate_by_number(nsetup, 'seq', 'excitatory', 60) 41 | 42 | seq_pop1= seq_pop[:30] 43 | seq_pop2= seq_pop[30:] 44 | 45 | exc_pop = pyNCS.Population('default', 'Default Population') 46 | exc_pop.populate_by_number(nsetup, 'ifslwta', 'excitatory', 60) 47 | 48 | exc_pop1= exc_pop[:30] 49 | exc_pop2= exc_pop[30:] 50 | 51 | mon = nsetup.monitors.import_monitors_otf([exc_pop1, exc_pop2]) 52 | 53 | c1=pyNCS.PConnection(seq_pop1, exc_pop1,'excitatory0', 'random_all2all',{'p':1.0}) 54 | c2=pyNCS.PConnection(seq_pop2, exc_pop2,'excitatory1', 'random_all2all',{'p':.1}) 55 | 56 | nsetup.chips['ifslwta'].set_parameter('nsynstdw0',.45) 57 | nsetup.chips['ifslwta'].set_parameter('nsynstdw1',.45) 58 | stim = seq_pop.soma.spiketrains_inh_poisson(np.array([np.linspace(1,1000,10)]*60), np.linspace(0,1000,10)) 59 | 60 | out = nsetup.run(stim) 61 | from pylab import * 62 | ion() 63 | pyNCS.monitors.RasterPlot(mon) 64 | pyNCS.monitors.MeanRatePlot(mon) 65 | -------------------------------------------------------------------------------- /src/pyNCS/api/loopbackAPI.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | 10 | #Path for recording experimental data 11 | from ComAPI import * 12 | import collections 13 | 14 | class BatchCommunicator(BatchCommunicatorBase): 15 | def __init__(self): 16 | ''' 17 | The BatchCommunicator API defined by the NCS tools. 18 | 19 | Usage: 20 | >>> c = Communicator(host = 'localhost', devnum = 0) 21 | >>> c.run() 22 | ''' 23 | 24 | # Inputs: 25 | # *host:* the hostname of the computer where the hardware is attached (default: 26 | # localhost). 27 | ResourceManagerBase.__init__(self) 28 | RecordableCommunicatorBase.__init__(self) 29 | self.t_last = 0. 30 | self.queue = collections.deque() 31 | 32 | def run(self, stimulus=None, duration=None, context_manager=None): 33 | ''' 34 | Loopback API simply puts an event packet in the API, and reads it back 35 | ''' 36 | stimulus[:,1] = stimulus[:,1].cumsum()+self.t_last 37 | t_last = stimulus[-1,1] 38 | self.queue.appendleft(stimulus) 39 | return self.queue.pop() 40 | 41 | 42 | class ContinuousCommunicator(BatchCommunicator): 43 | 44 | def mon(self, duration=None): 45 | #IMPLEMENT 46 | ''' 47 | Returns one event packet from the queue independent of the durection 48 | ''' 49 | return self.queue.pop() 50 | 51 | 52 | def stim(self, stimulus, duration=None, context_manager=None, **stim_kwargs): 53 | #IMPLEMENT 54 | ''' 55 | Adds an event packet to the queue, independent of duration and reads it. 56 | ''' 57 | stimulus[:,1] = stimulus[:,1].cumsum()+ self.t_last 58 | t_last = stimulus[-1,1] 59 | self.queue.appendleft(stimulus) 60 | return self.mon() 61 | 62 | def run(self, stimulus=None, duration=None, context_manager=None): 63 | ''' 64 | Loopback API simply puts an event packet in the API, and reads it back 65 | ''' 66 | return self.stim(stimulus) 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Communicator = ContinuousCommunicator 75 | -------------------------------------------------------------------------------- /docs/examples/reservoir.txt: -------------------------------------------------------------------------------- 1 | Reservoir 2 | ========= 3 | 4 | Description 5 | ----------- 6 | 7 | A reservoir is a pool of units with random connections. The connections are 8 | such that the activity of the network is "at the edge of chaos". This concept 9 | forms the basis of a particular type of neural networks called 10 | liquid-state-machines (LSM). 11 | 12 | - liquid state machine 13 | - input 14 | - read-out 15 | - LSM with LIF neurons? 16 | 17 | Implementation 18 | -------------- 19 | 20 | - preliminary operations:: 21 | 22 | import blabla 23 | import pyNCS 24 | 25 | nsetup = pyNCS.NeuroSetup('my_setuptype.xml', 'my_setup.xml') 26 | 27 | - create a population:: 28 | 29 | number_of_units = 500 30 | res = pyNCS.Population('', '') 31 | res.populate_by_number(nsetup, 32 | 'my_chip', 33 | 'my_neuron', 34 | number_of_units) 35 | 36 | - connect the units:: 37 | 38 | C_res = pyNCS.Connection(res, res, 'excitatory0', fashion='random_all2all') 39 | 40 | - create input:: 41 | 42 | inp = pyNCS.Population('', '') 43 | inp.populate_by_id(nsetup, 44 | 'my_sequencer', 45 | 'my_neuron', 46 | range(5, 10)) 47 | 48 | - connect the input to the reservoir:: 49 | 50 | C_inp = pyNCS.Connection(inp, res, 'excitatory1') # default fashion is one2one 51 | 52 | - make the input spike:: 53 | 54 | pattern1 = inp.soma.spiketrains_poisson(random(len(inp)), duration=500) 55 | 56 | - prepare the hardware:: 57 | 58 | nsetup.chips[res.neuronblock.neurochip.id].loadBiases('biases/reservoir.biases') 59 | # the following is equivalent to the previous statement 60 | res.neuronblock.neurochip.loadBiases('biases/reservoir.biases') 61 | 62 | nsetup.mapping.write() # connections where automatically appended 63 | 64 | - unleash hell:: 65 | 66 | # stimulus lasts for 500ms but we want to record more, say 5s 67 | out = nsetup.stimulate(pattern1, tDuration=5000) 68 | 69 | - plot (with monitors is a lot easier and faster!):: 70 | 71 | # the output 72 | out[out.soma.channel].raster_plot() 73 | # external input and recurrent input 74 | imshow(out[out.synapses.channel].firing_rate(50)) # 50ms time-bin 75 | # input stimulus 76 | pattern1[inp.soma.channel].raster_plot() 77 | 78 | Parameters 79 | ---------- 80 | 81 | The parameters for a good reservoir are... ? 82 | -------------------------------------------------------------------------------- /docs/general/experiments.txt: -------------------------------------------------------------------------------- 1 | Doing real experiments 2 | ====================== 3 | 4 | Structure 5 | --------- 6 | 7 | For highly complex experiments it is useful to split the scripts 8 | into several files. We normally try to follow the scheme below. 9 | 10 | Folders: 11 | 12 | :Results: 13 | contains pickles of the results under nicely-named folders 14 | :biases: 15 | bias (text) files of the chips 16 | :setupfiles: 17 | xml files of the setups (*) 18 | :chipfiles: 19 | csv and xml files representing the chips (*) 20 | 21 | (*) these folders are usually in a common folder somewhere else because they are 22 | not experiment dependent. 23 | 24 | Files and correspondent actions: 25 | 26 | :expSetup: 27 | load the setup 28 | :expMap: 29 | prepare connectivity 30 | :expPop: 31 | create populations 32 | :expStim: 33 | load data set and convert into AER 34 | :expTools: 35 | useful functions, code snippets, ... 36 | :expOsc: 37 | prepare acquisition of analog signals if needed 38 | :expMon: 39 | define monitors (?) 40 | :expRun: 41 | run the experiment and save values 42 | :expData: 43 | analysis of the data 44 | :expPlot: 45 | plot data 46 | 47 | Experiment tools 48 | ---------------- 49 | 50 | We developed a specific class to save the data of our experiments. 51 | 52 | Save 53 | ~~~~ 54 | 55 | :: 56 | 57 | et = pyNCS.et 58 | et.mksavedir() # creates a new folder under Results/ 59 | et.globaldata.variable_to_be_saved = v1 60 | et.globaldata.an_other_one = v4 61 | et.save() # saves everything from globaldata and all expXXX scripts. 62 | 63 | Some comments. The ``Results`` folder has to be created in advance. The function 64 | ``mksavedir`` creates, by default, a folder of the format ``NNN__DD-MM-YYYY``. 65 | You can assign every `pickable` variable you want to globaldata attributes. The 66 | ``save`` function saves: 67 | 68 | - all the python files starting by ``exp`` in a single ``tar.gz`` 69 | file inside the new folder 70 | - a single pickle of ``et.globaldata`` 71 | - an empty file with the time of the experiment as name 72 | 73 | .. warning:: Don't forget to save chip biases! 74 | 75 | Load 76 | ~~~~ 77 | 78 | :: 79 | 80 | loaded_data = pyNCS.et 81 | et.globaldata.directory = 'Results/128__19-04-2011' 82 | et.globaldata = et.globaldata.load() 83 | 84 | The ``load`` functions grabs the pickle from the specified directory. You can 85 | find the variables you saved in ``et.globaldata``. 86 | -------------------------------------------------------------------------------- /src/pyNCS/api/BaseConfAPI.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | #ConfAPI 10 | #Biases and mapper 11 | #Api for modules having pyAMDA-like functionality 12 | #Api for modules having pyAEX-like functionality 13 | 14 | from types import GeneratorType # For checking generator type 15 | from contextlib import contextmanager 16 | from lxml import etree 17 | import warnings 18 | 19 | class Parameter: 20 | def __init__(self, parameters, configurator): 21 | ''' 22 | Parameter(parameters, configurator) 23 | parameters: dictionary of parameters and values 24 | This object is designed to be used with the configurator to set parameters 25 | ''' 26 | self.param_data = dict(parameters) 27 | self.configurator = configurator 28 | self.SignalName = self.param_data['SignalName'] 29 | 30 | def __str__(self): 31 | return str(self.param_data) 32 | 33 | def __getNHML__(self): 34 | ''' 35 | Returns lxml.etree.Element representatoin of this parameter 36 | ''' 37 | doc = etree.Element('parameter') 38 | for n, v in self.param_data.items(): 39 | doc.attrib[n] = str(v) 40 | return doc 41 | 42 | def __parseNHML__(self, doc): 43 | ''' 44 | Parse xml file or element tree to generate the object 45 | ''' 46 | if isinstance(doc, str): 47 | # parse the file 48 | doc = etree.parse(doc).getroot() 49 | else: 50 | # assuming doc is an lxml Element object. 51 | assert doc.tag == 'parameter' 52 | self.param_data = dict(doc.attrib) 53 | for k, v in self.param_data.items(): 54 | try: 55 | v = float(v) 56 | except: 57 | pass 58 | self.param_data[k] = v 59 | self.SignalName = self.param_data['SignalName'] 60 | 61 | def getValue(self): 62 | return self.configurator.get_parameter(self.param_data['SignalName']) 63 | 64 | def setValue(self, value): 65 | x = self.configurator.set_parameter(self.param_data['SignalName'], value) 66 | return x 67 | 68 | v = property(getValue, setValue) 69 | 70 | -------------------------------------------------------------------------------- /test/chipfiles/if2dwta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/pyNCS/__init__.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | # -*- coding: utf-8 -*- 10 | from __future__ import absolute_import 11 | 12 | from .chip_v2 import Chip, NeuronBlock, NeuroChip, Block 13 | from . import experimentTools as et 14 | from .group import AddrGroup, AddrGroupBase 15 | from .population import Population 16 | from .connection import Connection, PConnection 17 | from .mapping import Mapping, PMapping 18 | from .neurosetup import NeuroSetup 19 | from .monitors import Monitors, SpikeMonitor 20 | from .api import ComAPI 21 | from .api import ConfAPI 22 | from . import pyST 23 | 24 | ###################### Utility functions 25 | from functools import wraps 26 | 27 | 28 | class DocInherit(object): 29 | ## {{{ http://code.activestate.com/recipes/576862/ (r1) 30 | """ 31 | Docstring inheriting method descriptor 32 | 33 | The class itself is also used as a decorator 34 | 35 | doc_inherit decorator 36 | 37 | Usage: 38 | 39 | class Foo(object): 40 | def foo(self): 41 | "Frobber" 42 | pass 43 | 44 | class Bar(Foo): 45 | @doc_inherit 46 | def foo(self): 47 | pass 48 | 49 | Now, Bar.foo.__doc__ == Bar().foo.__doc__ == Foo.foo.__doc__ == "Frobber" 50 | """ 51 | 52 | def __init__(self, mthd): 53 | self.mthd = mthd 54 | self.name = mthd.__name__ 55 | 56 | def __get__(self, obj, cls): 57 | if obj: 58 | return self.get_with_inst(obj, cls) 59 | else: 60 | return self.get_no_inst(cls) 61 | 62 | def get_with_inst(self, obj, cls): 63 | 64 | overridden = getattr(super(cls, obj), self.name, None) 65 | 66 | @wraps(self.mthd, assigned=('__name__', '__module__')) 67 | def f(*args, **kwargs): 68 | return self.mthd(obj, *args, **kwargs) 69 | 70 | return self.use_parent_doc(f, overridden) 71 | 72 | def get_no_inst(self, cls): 73 | 74 | for parent in cls.__mro__[1:]: 75 | overridden = getattr(parent, self.name, None) 76 | if overridden: 77 | break 78 | 79 | @wraps(self.mthd, assigned=('__name__', '__module__')) 80 | def f(*args, **kwargs): 81 | return self.mthd(*args, **kwargs) 82 | 83 | return self.use_parent_doc(f, overridden) 84 | 85 | def use_parent_doc(self, func, source): 86 | if source is None: 87 | raise NameError("Can't find {o} in parents".format(self.name)) 88 | func.__doc__ = source.__doc__ 89 | return func 90 | 91 | doc_inherit = DocInherit 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/chipfiles/if2dwta.csv: -------------------------------------------------------------------------------- 1 | chipclass IF2DWTA 2 | 3 | aerIn 4 | id x range range(64) type 1 func X>>1 5 | id y range range(32) type 1 func ((Y-(Y%3))<<1)/3+(X&1) 6 | id s range range(3) type -1 func Y%3 7 | 8 | 9 | pinid X func 2*x+(y&1) 10 | pinid Y func s+3*(y>>1) 11 | pinlayout Y0 Y1 Y2 Y3 Y4 Y5 X6 X5 X4 X3 X2 X1 X0 12 | 13 | aerOut 14 | id x range range(64) type 1 func X 15 | id y range range(32) type 1 func Y 16 | 17 | 18 | pinid X func x 19 | pinid Y func y 20 | pinlayout Y4 Y3 Y2 Y1 Y0 X5 X4 X3 X2 X1 X0 21 | 22 | Count PIN PKG CircuitBlock SignalName FET BiasType PadType Range SimulationValue Description Channel Shared with 23 | 1 80 Arbiter Aepd dac 0.8 56 24 | 2 79 Arbiter req_puY dac 2.8 58 25 | 3 78 Arbiter req_puX dac 2.8 60 26 | 4 2 Select selpu dac 2.8 29 27 | 5 64 Select selx0 dac 0 72 28 | 6 65 Select selx1 dac 0 70 29 | 7 66 Select selx2 dac 0 68 30 | 8 67 Select selx3 dac 0 66 31 | 9 68 Select selx4 dac 0 64 32 | 10 69 Select selx5 dac 0 62 33 | 11 96 Select sely0 dac 0 8 34 | 12 97 Select sely1 dac 0 6 35 | 13 98 Select sely2 dac 0 4 36 | 14 99 Select sely3 dac 0 2 37 | 15 100 Select sely4 dac 0 0 38 | 16 9 MUX muxx0 dac 0 35 39 | 17 8 MUX muxx1 dac 0 33 40 | 18 7 MUX muxx2 dac 0 31 41 | 19 36 MUX muxy0 dac 0 37 42 | 20 37 MUX muxy1 dac 0 39 43 | 21 53 RING ringonoff dac 0 74 44 | 22 119 Soma nadap dac 3.3 23 45 | 23 1 Soma nlk dac 0 27 46 | 24 120 Soma nlkadap dac 0 25 47 | 25 117 Soma nrf dac 0.4 19 48 | 26 118 Soma nsf dac 0.7 21 49 | 27 39 Soma inj dac 3.3 41 50 | 28 115 SYNLOC nsynlocplswdt dac 0 15 51 | 29 79 SYNLOC nsynlocselfw dac 0 58 52 | 30 108 SYNLOC nsynlocselfth dac 0 1 53 | 31 110 SYNLOC psynlocselftau dac 3.3 5 54 | 32 109 SYNLOC nsynlocth dac 3.3 3 55 | 33 111 SYNLOC psynloctau dac 3.3 7 56 | 34 116 SYNLOC nsynloclat1 dac 0 17 57 | 35 114 SYNLOC nsynlocvert1 dac 0 13 58 | 36 113 SYNLOC nsynlocvert2 dac 0 11 59 | 37 52 SYNAERINH nsynaerinhplswdt dac 0.3 76 60 | 38 48 SYNAERINH psynaerinhth dac 0 84 61 | 39 49 SYNAERINH nsynaerinhtau dac 0.3 82 62 | 40 50 SYNAERINH psynaerinhw dac 3.3 80 63 | 41 51 SYNAEREXC nsynaerexcplswdt dac 0 78 64 | 42 47 SYNAEREXC nsynaerexcth0 dac 3.3 86 65 | 43 44 SYNAEREXC psynaerexcw0 dac 0.5 92 66 | 44 45 SYNAEREXC nsynaerexcwd0 dac 0.2 90 67 | 45 46 SYNAEREXC psynaerexctau0 dac 2.9 88 68 | 46 43 SYNAEREXC nsynaerexcth1 dac 3.3 94 69 | 47 40 SYNAEREXC psynaerexcw1 dac 0.5 43 70 | 48 41 SYNAEREXC nsynaerexcwd1 dac 0.2 45 71 | 49 42 SYNAEREXC psynaerexctau1 dac 2.9 47 72 | 50 86 Power FollBias dac 0.4 54 73 | 51 54 Power llGnd dac 0 49 74 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | 15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " pickle to make pickle files" 22 | @echo " json to make JSON files" 23 | @echo " htmlhelp to make HTML files and a HTML help project" 24 | @echo " qthelp to make HTML files and a qthelp project" 25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 26 | @echo " changes to make an overview of all changed/added/deprecated items" 27 | @echo " linkcheck to check all external links for integrity" 28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 29 | 30 | clean: 31 | -rm -rf $(BUILDDIR)/* 32 | 33 | html: 34 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 35 | @echo 36 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 37 | 38 | dirhtml: 39 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 40 | @echo 41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 42 | 43 | pickle: 44 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 45 | @echo 46 | @echo "Build finished; now you can process the pickle files." 47 | 48 | json: 49 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 50 | @echo 51 | @echo "Build finished; now you can process the JSON files." 52 | 53 | htmlhelp: 54 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 55 | @echo 56 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 57 | ".hhp project file in $(BUILDDIR)/htmlhelp." 58 | 59 | qthelp: 60 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 61 | @echo 62 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 63 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 64 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/NCSdocumentation.qhcp" 65 | @echo "To view the help file:" 66 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/NCSdocumentation.qhc" 67 | 68 | latex: 69 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 70 | @echo 71 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 72 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 73 | "run these through (pdf)latex." 74 | 75 | changes: 76 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 77 | @echo 78 | @echo "The overview file is in $(BUILDDIR)/changes." 79 | 80 | linkcheck: 81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 82 | @echo 83 | @echo "Link check complete; look for any errors in the above output " \ 84 | "or in $(BUILDDIR)/linkcheck/output.txt." 85 | 86 | doctest: 87 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 88 | @echo "Testing of doctests in the sources finished, look at the " \ 89 | "results in $(BUILDDIR)/doctest/output.txt." 90 | -------------------------------------------------------------------------------- /src/pyNCS/api/ComAPI.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | 10 | #Path for recording experimental data 11 | from __future__ import absolute_import 12 | from .BaseComAPI import * 13 | 14 | class BatchCommunicatorBase(ResourceManagerBase,RecordableCommunicatorBase): 15 | def __init__(self): 16 | ''' 17 | The BatchCommunicator API defined by the NCS tools. 18 | 19 | Usage: 20 | >>> c = Communicator(host = 'localhost', devnum = 0) 21 | >>> c.run() 22 | ''' 23 | 24 | # Inputs: 25 | # *host:* the hostname of the computer where the hardware is attached (default: 26 | # localhost). 27 | ResourceManagerBase.__init__(self) 28 | RecordableCommunicatorBase.__init__(self) 29 | 30 | def run(self, stimulus=None, duration=None, context_manager=None): 31 | #IMPLEMENT 32 | ''' 33 | Stimulate the neuromorphic hardware with event stream *stimulus* and monitor it for *duration* ms 34 | Input: 35 | *stimulus*: a numpy array in (addr, time) format. Type should be uint32 (shape = (-1,2)). 36 | *duration*: monitor duration. 37 | *context_manager*: context manager used to wrap the stimulate function. Useful for syncing with external process. 38 | Output: a numpy array in addr, time format. Type is uint32 (shape = (-1,2)). 39 | 40 | Usage: 41 | >>> events = np.array([[0, 1],[100,200]], dtype='uint32') #addr, time format 42 | >>> run(events, 1500) 43 | ''' 44 | return EMPTY_RAW 45 | 46 | 47 | class ContinuousCommunicatorBase(BatchCommunicatorBase): 48 | 49 | def __init__(self, *args, **kwargs): 50 | ''' 51 | The Continuous Communicator API defined by the NCS tools. 52 | In addition to the Batch Communicator, this class has a mon() method which can be used to monitor data in real-time. 53 | 54 | Example Usage: 55 | >>> c = Communicator(host = 'localhost', devnum = 0) 56 | >>> c.run() 57 | >>> #Or 58 | >>> c = Communicator(host = 'localhost', devnum = 0) 59 | >>> c.open() 60 | >>> c.mon() 61 | >>> c.close() 62 | ''' 63 | 64 | # Inputs: 65 | # *host:* the hostname of the computer where the hardware is attached (default: 66 | # localhost). 67 | BatchCommunicatorBase.__init__(self) 68 | 69 | def mon(self, duration): 70 | #IMPLEMENT 71 | ''' 72 | Monitor the neuromorphic hardware for *duration* ms 73 | ''' 74 | pass 75 | 76 | def stim(self, stimulus, duration=None, context_manager=None, **stim_kwargs): 77 | #IMPLEMENT 78 | ''' 79 | Stimulate the neuromorphic hardware with event stream *stimulus* and monitor it for *duration* ms 80 | Input: 81 | *stimulus*: a numpy array in addr, time format. Type should be uint32 (shape = (-1,2)). 82 | *duration*: monitor duration. 83 | *context_manager*: context manager used to wrap the stimulate function. Useful for syncing with external process. 84 | ***stim_kwargs*: keyward arguments passed to the underlying stimulation modules 85 | 86 | Output: a numpy array in addr, time format. Type is uint32 (shape = (-1,2)). 87 | Usage: 88 | >>> events = np.array([0, 1],[100,200], dtype='uint32') #addr, time format 89 | >>> stim(events, 1500) 90 | ''' 91 | return EMPTY_RAW 92 | 93 | Communicator = BatchCommunicatorBase 94 | -------------------------------------------------------------------------------- /docs/general/hardware_setup.txt: -------------------------------------------------------------------------------- 1 | --------------------- 2 | How to set up a setup 3 | --------------------- 4 | 5 | Here we describe how to configure a new setup from scratch using existing 6 | hardware, i.e. existing VLSI chips and AER boards. 7 | 8 | Equipment 9 | ========= 10 | 11 | - The ExCol Mapper (Daniel_) 12 | - AEX boards for monitoring and sequencing spike trains to the chips (Daniel_) 13 | - Optional: tmpdiff128 retina on a parallel AER compatible board 14 | - at least 1 IFSLWTA chip (Giacomo chip) consisting of 128 I&F neurons with 32 synapses each (2 non-plastic exc., 2 inhibitory, 28 plastic synapses implementing the bistable learning synapse) and optional hard-wired "soft Winner-take-all connectivity 15 | - Optional: 1 2DIFWTA (Elisabetta chip) consisting of 64 x 32 I&F, 3 non-plastic synapses per neuron, 1 inhibitory synapse, 2 excitatory synapses 16 | 17 | - boards 18 | - mapper 19 | - chips 20 | - cables 21 | - software 22 | - drivers 23 | - other resources (acquisition board, ...) 24 | 25 | Installation 26 | ============ 27 | 28 | Program the mapper 29 | ~~~~~~~~~~~~~~~~~~ 30 | 31 | - how to program the mapper 32 | 33 | Program the AEX FPGA 34 | ~~~~~~~~~~~~~~~~~~~~ 35 | 36 | Tools you need 37 | ~~~~~~~~~~~~~~ 38 | 39 | As many AEX boards as you want (and 6V power suppliers for each...), Xilinx 40 | Platform Cable USB *or parallel*, Windows or Linux machine with drivers for 41 | Xilinx Platform Cable USB, AEX svn repository access rigths. This guide is for 42 | windows machines. 43 | 44 | #. Download the code for the AEXs from the svn repository. 45 | #. Plug-in Xilinx Platform Cable USB. 46 | #. After some dialog windows you will have corrected installed Xilinx drivers. 47 | #. Download ISE Webpack from http://www.xilinx.com/tools/webpack.htm 48 | 49 | Program can be installed on both Linux and Windows machines (see 50 | http://www.xilinx.com/ise/ossupport/index.htm) but driver for usb cable can be 51 | installed very easily on Windows [Note: there's a DVD with all the tools you 52 | need in the box of the Xilinx USB cable]. You'll need to use ISE Project 53 | workspace and Impact. The first compiles the code for the fpga, the other 54 | actually programs the fpga. 55 | 56 | The AEX project file for Xilinx ISE is: ``aex/aex.ise``. 57 | The top VHDL file is: ``aextop/z_top.vhd``. 58 | 59 | Once you downladed the fpga code you can open the file 'aex/aex.ise'. On the 60 | left panel, 'Sources', blablabla. 61 | 62 | Clean everything (i.e. right-click on the top file and remove it) then 63 | ``addsource``, choose your code (for example ``z_top_CH1.vhd``), 64 | make sure it is set as Top Module on the Source panel and be sure that all the 65 | sources for all the single parts are loaded. On the FPGA Design Summary 66 | double-click on Generate Programming file. Wait and get rid of the warnings... 67 | Open Impact and create a new project, open ``aex/z_top.bit``, than choose "create PROM 68 | file", select 4M model, click on left side on Generate file, go to the Boundary 69 | Scan, initialize the chain. assign you brand new .mcs file to the PROM (xcf04s) 70 | and the brand new z_top.bit in /aex to the FPGA (xc3s500e). Right click and 71 | Program both devices. After programming the xc3s500e you could see changes in 72 | leds state. You did it! In future you can use Verify insted of Program in 73 | order to compare what\'s on the FPGA and what\'s on your code. 74 | 75 | If you want to change the routing scheme, have a look at `Reprogramming AEX`_. 76 | 77 | .. _Reprogramming AEX: aex_reprogramming.html 78 | 79 | Power-cycle 80 | ~~~~~~~~~~~ 81 | 82 | There is a particular power cycle that one must respect: 83 | 84 | #. plug all the serial cables in the correct manner 85 | #. plug all USB cables, first the 0 channel board (it will be seen as 86 | `/dev/aerfx0`) 87 | #. Power up the AEX boards 88 | #. Turn on the AMDA boards (first main the daughter) 89 | #. Turn on the aex server 90 | 91 | The AMDA server starts automatically when plugging the first AMDA board. The 92 | AEX server have to be explicitly installed. 93 | Check that server are on:: 94 | 95 | $> ps aux | grep Serv 96 | fabios 24743 20.1 0.4 54800 8320 pts/1 Sl+ 11:44 0:02 python Server.py 97 | root 31477 0.0 0.3 166532 6768 ? S>> Addr=[range(20,30),0,0] 57 | >>> setup.seq.addrPhysicalConstruct({0:Addr}) 58 | array([5120, 5376, 5632, 5888, 6144, 6400, 6656, 6912, 7168, 7424], dtype=uint32) 59 | 60 | * Logical addresses, python floats, used by software such as SpikeLists. It has the advantage of convenientlyrepresenting complicated addresses in a single floating number. Example: 61 | 62 | .. code-block:: python 63 | 64 | #This creates the logical addresses: The addresses correspond to row 20 to 30, column 0, polarity 0 of the retina. 65 | 66 | >>> setup.seq[0].addrLogicalConstruct(Addr) 67 | 68 | array([ 20., 21., 22., 23., 24., 25., 26., 27., 28., 29.],dtype='float') 69 | 70 | or if you have several chips: 71 | 72 | .. code-block:: python 73 | 74 | #This creates the logical addresses: The addresses correspond to row 20 to 30, column 0, polarity 0 of the retina. 75 | 76 | >>> setup.seq.addrLogicalConstruct(Addr) 77 | 78 | {1:array([ 20., 21., 22., 23., 24., 25., 26., 27., 28., 29.], dtype=float)} 79 | 80 | * Human Readable addresses do not exist per se. It is only a method to conveniently define/decode physical or logical. In fact, it corresponds to the ``Addr`` variable in the examples above. 81 | 82 | *Remark:* There exists function for extracting and constructing physical and logical addresses. Construction and Extraction are both meant from the point of view of Human Readable addresses. 83 | 84 | *Remark:* Technically there exists functions for translating from physical to logical directly (without using extraction/construction functions). But these are intended for internal use only. 85 | 86 | 87 | .. Using pyST for creating mappings 88 | .. ________________________________ 89 | .. 90 | .. 91 | .. Using NeuroTools in combination with pyST 92 | .. _________________________________________ 93 | 94 | 95 | .. _NeuroTools: http://neuralensemble.org/trac/NeuroTools 96 | .. _pyNCS: pyncs.html 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/pyNCS/connection.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: Fabio Stefanini 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | from __future__ import absolute_import 10 | import numpy as np 11 | import pylab 12 | 13 | from .mapping import Mapping, PMapping 14 | 15 | 16 | class Connection(object): 17 | """ 18 | A class representing the connections between populations. 19 | """ 20 | def __init__(self, popsrc, popdst, synapse, 21 | fashion='one2one', 22 | fashion_kwargs={}, 23 | connection_kwargs={}, 24 | append=True, 25 | setup=None): 26 | """ 27 | - popsrc: source population 28 | - popdst: destination population 29 | - synapse: on which synapse to connect 30 | - fashion: type of connectivity 31 | - fashion_kwargs: arguments for fashion-type connectivity 32 | - append: whether to append this connection to the setup mapping table 33 | - setup: specify setup if different from popsrc.setup 34 | """ 35 | self.mapping = self._create_mapping(popsrc, popdst, synapse) 36 | self.mapping.connect( 37 | popsrc.soma, 38 | popdst.synapses[synapse], 39 | connection_kwargs = connection_kwargs, 40 | fashion=fashion, 41 | fashion_kwargs=fashion_kwargs) 42 | self.mapping.prepare() 43 | if setup is None: 44 | setup = popsrc.setup 45 | if append: 46 | setup.mapping.merge(self.mapping) 47 | 48 | self.synapse = synapse 49 | self.popsrc = popsrc 50 | self.popdst = popdst 51 | self.connection_kwargs = connection_kwargs 52 | 53 | def _create_mapping(self, popsrc, popdst, synapse): 54 | return Mapping(popsrc.name + '_to_' + popdst.name, 55 | 'Connects %s to %s on synapse \'%s\'.' % 56 | (popsrc.name, popdst.name, synapse)) 57 | 58 | def __len__(self): 59 | return len(self.mapping.mapping) 60 | 61 | def __repr__(self): 62 | return "Connection object: {0} -> {1} via {2}".format(self.popsrc.name, 63 | self.popdst.name, 64 | self.synapse) 65 | 66 | 67 | def plot(self): 68 | ''' 69 | plots the connectivity 70 | ''' 71 | srcindx = {j:i for i,j in enumerate(self.popsrc.soma.paddr)} 72 | dstindx = {j:i for i,j in enumerate(self.popdst.synapses[self.synapse].paddr)} 73 | conn_matrix = np.zeros((len(self.popdst.synapses[self.synapse]), 74 | len(self.popsrc.soma))) 75 | for src, dst in np.array(self.mapping.mapping)[:,:2]: 76 | conn_matrix[dstindx[dst], srcindx[src]] += 1 77 | pylab.colorbar(pylab.pcolor(conn_matrix)) 78 | pylab.xlabel(self.popsrc.name) 79 | pylab.ylabel(self.popdst.name) 80 | 81 | # def __connect_one2one__(self, popsrc, popdst, synapse, syn_ids=[0]): 82 | # """ 83 | # Connects in a one to one fashion. Every source neuron connects to one 84 | # synapse on the destination. 85 | # - syn_ids: array of synapses into which to connect 86 | # """ 87 | # nsrc = len(syn_ids) 88 | # ndst = len(popdst[0].synapses[synapse]) 89 | # [self.mapping.connect(popsrc.soma[i::nsrc], 90 | # popdst.synapses[synapse][i::ndst]) 91 | # for i in syn_ids] 92 | 93 | # def activate(self, setup=None): 94 | # """ 95 | # Shortcut function to apply connections over-writing the existing ones. 96 | # See also NeuroSetup.Mapping.import_from_connections(). 97 | # - setup: if None, self.setup will be used 98 | # """ 99 | # if setup is None: 100 | # self.mapping.write() 101 | # else: 102 | # setup.mapping.import_from_connections(self) 103 | # setup.mapping.write() 104 | 105 | 106 | class PConnection(Connection): 107 | def _create_mapping(self, popsrc, popdst, synapse): 108 | return PMapping(popsrc.name + '_to_' + popdst.name, 109 | 'Connects %s to %s on synapse \'%s\'.' % 110 | (popsrc.name, popdst.name, synapse)) 111 | -------------------------------------------------------------------------------- /docs/general/aex_reprogramming.txt: -------------------------------------------------------------------------------- 1 | Reprogram routing of AEX boards 2 | =============================== 3 | 4 | Those who want to create their own AEX version, have to first checkout the code 5 | from https://x.ethz.ch/svn/aer/fpga 6 | 7 | Therein, the AEX project file for Xilinx ISE is: ``aex/aex.ise``. 8 | The top VHDL file is: ``aextop/z_top.vhd``. 9 | 10 | Once you downladed the fpga code you can open the file 'aex/aex.ise'. On the 11 | left panel, 'Sources', blablabla. 12 | 13 | .. note:: If you encounter problems you can always go back to revision 1564 of 14 | the ``aex.ise`` file, rename it as you want, for example ``aex2.ise``, 15 | and go on with your modifications 16 | 17 | In the top file, at the beginning, just after the entity declaration, you find 18 | all the configuration settings. The configuration is with respect to paths 19 | between the three interfaces, denoted as P, S, U for Parallel, Serial and USB. 20 | There are 3^3 = 9 combinations so 9 possible path to configure. At first, each 21 | path can be enabled or disabled completely. These are the first nine constants, 22 | with the names ``confPathEnableXYxS``, with XY being PP, PS, PU, SP, and so on... 23 | 24 | If ``0`` is assigned to a path, it is disabled. 25 | Then there are four configuration values for each path, 26 | 27 | - confXYFilterRangeMinxDI with default x"00000000" 28 | - confXYFilterRangeMaxxDI with default x"FFFFFFFF" 29 | - confXYOutMaskAndxDI with default x"FFFFFFFF" 30 | - confXYOutMaskOrxDI with default x"00000000" 31 | 32 | with XY being the same as before. 33 | An address A coming to the path is checked to be in the range:: 34 | 35 | A >= confXYFilterRangeMinxDI and A >= confFilterRangeMaxxDI 36 | 37 | If not, the address is discarded. If the filter check is passed, A is used to 38 | calculate Anew in the following way:: 39 | 40 | Anew <= (A and confXYOutMaskAndxDI) or confXYOutMaskOrxDI 41 | 42 | This gives us the possibility to make the trick. Notice first that we have to 43 | distinguish if an event is input for a chip or output from a chip, because of 44 | monitoring purposes. This reduces the address space. The range filtering is 45 | used by an AEX for checking if an address has to be sent to its chip. The 'or' 46 | mask is used for adding the stamp. The 'and' mask is used for cleaning the bits 47 | before stamping. 48 | 49 | For example, if we had 8 bits, 5 for neurons addressing: 50 | 51 | #. 01011010 (0x5A) comes from the mapper 52 | #. it is for chip number 010 (0x40) 53 | #. this cause activity on chip 010 54 | #. chip 010 stamp its activity with 110 (add 0xC0 to the address) 55 | #. mapper finds 0xC0 + 0x14 and then knows who is the sender 56 | #. mapper maps this activity to someone else... 57 | 58 | Note that each event add an address in the communication loop. If nobody removed 59 | it, the chain would soon saturate. The idea is then to stamp a chip output 60 | address in a different way of a chip input address. * better explanation 61 | please...* 62 | 63 | Each AEX board will have its own configuration because the filter and stamp 64 | change. For example, for Chip1:: 65 | 66 | constant confSPFilterRangeMinxDI : std_logic_vector(31 downto 0) :=x"0000A000"; 67 | constant confSPFilterRangeMaxxDI : std_logic_vector(31 downto 0) :=x"0000AFFF"; 68 | constant confSPOutMaskAndxDI : std_logic_vector(31 downto 0) :=x"FFFF1FFF"; 69 | constant confSPOutMaskOrxDI : std_logic_vector(31 downto 0) :=x"00002000"; 70 | 71 | The path enabled are PS, PU, SP, SU, US for all the AEXs. 72 | 73 | The files created are in 'fpga/aextop' folder: 74 | 75 | - ``z_top_CH1.vhd`` 76 | - ``z_top_CH2.vhd`` 77 | - ``z_top_CH3.vhd`` 78 | - ``z_top_RS.vhd`` 79 | 80 | Notes and common problems in programming AEX 81 | -------------------------------------------- 82 | 83 | The ise project file is automagically saved in any moment... If you do 84 | something wrong like removing all the sources on the left panel, this change 85 | will persist even if you close the project without explicitly saving. - At the 86 | end of the process, be sure that only D2 led is on and the others are off. Once 87 | you connect the board to the USB you should se D1 and D3 on and D2 off. Please 88 | notice that this is a possible check but is *not* exhaustive. 89 | 90 | Going further 91 | ------------- 92 | 93 | The loop design we described before is the simplest one can think of. This 94 | setup will work with an input (retina or sequencer) and 3 chips, 2Difwta or 95 | ifslwta. An other possibility is to use the fact that ifslwta chips use a 96 | lower number of bits for neurons and synapses addressing. This means that in 97 | principal it is possible to use one retina and up to 6 ifslwta *is it true?*. 98 | 99 | Anyway we implemented this before in order to see if everything is going to 100 | work or not, then after we can think about something more general. 101 | -------------------------------------------------------------------------------- /docs/general/learning.txt: -------------------------------------------------------------------------------- 1 | Use plastic synapses of ``ifslwta`` chip 2 | ======================================== 3 | 4 | Learning algorithm 5 | ------------------ 6 | 7 | Read `Fusi et al. 2000, Brader et al. 2007`. 8 | 9 | Learning chip 10 | ------------- 11 | 12 | The algorithm above is implemented in the ``ifslwta`` chip. Input spikes 13 | trigger the update of the synaptic weight of that synapse. This operation is 14 | done by an analog circuit which changes the amount of charge stored in a 15 | capacitance which constitutes the weight of that synape. 16 | 17 | Each of the 128 neurons of the ifslwta chip has 32 synapses. Synapses 4 to 31 18 | are plastic, thus there are 32x128=3584 plastic synapses. One can use the 19 | multiplexer to use more synapses for each neuron, thus reducing the number of 20 | neurons (see hardware page of ifslwta for more details). For example, one can 21 | use a multiplexer of 1-0-1 to have 4 neurons with 28*32 learning synapses each. 22 | Notice that also non-plastic synapses will be multiplexed. 23 | 24 | Synaptic matrix class 25 | --------------------- 26 | 27 | We created a class that represent the matrix of synaptic weights on a chip 28 | (tested on ``ifslwta`` chip). Its structure is similar to a 29 | ``pyTune.Parameter`` structure. We explain here only the interesting parts of 30 | it. A ``Wij`` class is already written, ask Fabio_. 31 | 32 | By creating the matrix we mean creating all the populations and connections 33 | that we will need to probe the synaptic weights. 34 | 35 | .. note:: We first need to import the ``Wij`` class because it is not yet 36 | included in the base pyNCS package. We'll assume this class is 37 | implemented in the ``wij.py`` file somewhere. 38 | 39 | :: 40 | 41 | from wij import Wij 42 | 43 | wij = Wij('wij1', 'This is the matrix of synaptic weights on chip1.') 44 | wij.set_context(nsetup, 'ifslwta', 'excitatory', 45 | neurons=range(28), 46 | synapses=range(28)) 47 | 48 | As you may have noticed, the weights the class will look at the 28 synapses 49 | of the first 28 ``excitatory`` neurons in ``ifslwta`` chip of the ``nsetup`` 50 | setup. 51 | 52 | Read the synaptic weights 53 | ------------------------- 54 | 55 | In order to read the matrix of synaptic weights we have to do some... 56 | electrophysiology because there is no way of direct access to them. The way to 57 | do it is to set the parameters of the learning such that the synapses are kept 58 | frozen and then send a stimulus to each synapse. If the synapse state is high 59 | we expect an output from the neuron that is connected to it. If the state is 60 | low we expect no output. 61 | 62 | This procedure relys on -- a lot of -- parameters that has to be set before 63 | doing the actual measure. Explain here... 64 | 65 | Most basic thing, we want to ``get`` the synaptic matrix. There is a method 66 | that does this for us:: 67 | 68 | wij_status = wij.get() 69 | 70 | Notice you don't need to assign the value to a variable because the ``get`` 71 | function automatically updates the ``wij.state`` variable for you. During the 72 | probing, the system performs the following operations: 73 | 74 | - set multiplexer to [0,0,0] 75 | - prepare stimulus and write mapping on mapper 76 | - "turn off" learning (read below) 77 | - stimulate all the synapses of each neuron sequencially (1 spike per 78 | synapse) 79 | - translate output into binary matrix. 80 | 81 | .. note:: A specific set of biases should be applied in a specific sequence 82 | prior to the stimulation. Ask Fabio_ for these biases. 83 | 84 | The output of the get function is a 28x28 matrix, i.e. the dimensions we 85 | initilized the matrix with. The weights can be visualized by:: 86 | 87 | wij.show() 88 | 89 | Set the synaptic weights 90 | ------------------------ 91 | 92 | In order to set each synaptic weight to a specific value we must run an 93 | experiment that drives it to the value we want it to be. Even though the 94 | learning algorithm is not deterministic in general (i.e. it relies on the 95 | stochastic behaviour of pre- and post-synaptic activities), we can use it in a 96 | deterministic way by setting some parameter to specific values. For example, if 97 | we want to drive the weight to the high state, we will set the threshold of the 98 | membrane potential to 0 and send some high frequency input: the weight will 99 | receive only potentiation jumps and eventually cross the bi-stability 100 | threshold. 101 | 102 | There is a useful function that sets the weights to all-high or all-low by just 103 | applying a sequence of biases:: 104 | 105 | wij.reset(1) # set all to high 106 | wij.reset(0) # set all to zero 107 | 108 | Stop-learning 109 | ------------- 110 | 111 | The stop-learning features depends on the post-synaptic neuron's firing rate. 112 | In other words, it depends on something like a Calcium concentration variable. 113 | In the chip, there is a capacitor that integrates the post-synaptic spikes and 114 | 3 comparators modeling the 3 thresholds described on the learning algorithm. 115 | The weight of the plastic synapse is modified by the pre-synaptic spikes only 116 | when the Calcium variable lies within a certain range determined by those 117 | threshold. One can use these threshold to *turn off* the learning when it is 118 | not needed, e.g. we don't want to modify the synaptic weights when we send the 119 | ``get`` stimulus. Use:: 120 | 121 | wij.set_learning(0) 122 | 123 | to turn-off synaptic plasticity. 124 | 125 | .. note:: There is no ``set_learning(1)`` because the value of each threshold 126 | could depend on the specific experiment. 127 | 128 | .. _Fabio: fabio.stefanini@ini.phys.ethz.ch 129 | -------------------------------------------------------------------------------- /src/pyNCS/api/BaseComAPI.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | 10 | #Path for recording experimental data 11 | import numpy, getpass, warnings 12 | EMPTY_RAW = numpy.zeros([0,2], dtype='uint32') 13 | USER = getpass.getuser() 14 | 15 | class ResourceManagerBase(object): 16 | ''' 17 | The ResourceManagerBase class is a base class for opening, closing a resource. It is used as parent classes for the configuration, communication and mapping APIs. 18 | The init function takes no arguments by default 19 | ''' 20 | def __init__(self): 21 | self._neurosetup = None 22 | self._neurosetup_registered = False 23 | self._isopen = False 24 | 25 | def open(self): 26 | ''' 27 | Opens resource 28 | ''' 29 | self._isopen = True 30 | 31 | def close(self): 32 | ''' 33 | Closes resource 34 | ''' 35 | self._isopen = False 36 | 37 | @property 38 | def isopen(self): 39 | return self._isopen 40 | 41 | def __del__(self): 42 | if self.isopen: 43 | self.close() 44 | 45 | @property 46 | def neurosetup(self): 47 | if not self._neurosetup_registered: 48 | warnings.warn('NeuroSetup has not been registered') 49 | return None 50 | else: 51 | return self._neurosetup 52 | 53 | def register_neurosetup(self, neurosetup): 54 | ''' 55 | Provides a link to the Neurosetup. This is useful for complex parameter 56 | configuration protocols requiring the sequencing and monitoring of 57 | address-events 58 | ''' 59 | self._neurosetup_registered = True 60 | self._neurosetup = neurosetup 61 | 62 | class RecordableCommunicatorBase(object): 63 | REC_PATH = '/tmp/exp_rec_' + USER 64 | REC_FN_SEQ = 'seq' 65 | REC_FN_MON = 'mon' 66 | REC_HEADER_SEQ = '# File format raw address, ISI (us)' 67 | REC_HEADER_MON = '# File format raw address, timestamp (us)' 68 | 69 | def __init__(self): 70 | self._rec_fns = [] 71 | self._run_id = 0 72 | self.__reset() 73 | self.del_all() 74 | 75 | def get_exp_rec(self): 76 | ''' 77 | Returns the filename where the raw stimated and monitored events are saved. 78 | The filenames for all experiments are returned, and run_id is reset 79 | 80 | Output: list of filenames containing the experiment records (stimulated and monitored events). Additionally, the experiment number is reset. 81 | 82 | ''' 83 | #CONVIENIENCE FUNCTION, IMPLEMENTATION NOT REQURIED 84 | import copy 85 | rec_fns = copy.copy(self._rec_fns) 86 | self.__reset() 87 | return rec_fns 88 | 89 | def run_rec(self, stimulus = None, *args, **kwargs): 90 | #CONVIENIENCE FUNCTION, IMPLEMENTATION NOT REQURIED 91 | ''' 92 | Stimulate the neuromorphic hardware with event stream *stimulus* and monitor it for *duration* ms. 93 | In addition to the run() function, this function records the experimental data in /tmp/. 94 | The resulting files can be obtained with get_exp_record 95 | This function should be overridden to avoid redundant events file creation. 96 | 97 | Input: (see also run() for more information) 98 | *stimulus*: a numpy array in (addr, time) format. Type should be uint32 (shape = (-1,2)). 99 | *duration*: monitor duration. 100 | *context_manager*: context manager used to wrap the stimulate function. Useful for syncing with external process. 101 | Output: a numpy array in addr, time format. Type is uint32 (shape = (-1,2)). 102 | 103 | Usage: 104 | >>> events = np.array([[0, 1],[100,200]], dtype='uint32') #addr, time format 105 | >>> run_record(events, 1500) 106 | ''' 107 | #CONVIENIENCE FUNCTION, IMPLEMENTATION NOT REQUIRED 108 | stim_fn, mon_fn = self.__gen_rec_fns() 109 | #Save stim before in case something goes wrong 110 | self.__save_rec_file(stimulus, stim_fn) 111 | mon_evs = self.run(stimulus = stimulus, *args, **kwargs) 112 | self.__save_rec_file(mon_evs, mon_fn) 113 | 114 | return mon_evs 115 | 116 | def __save_rec_file(self, ev_array, filename): 117 | ''' 118 | Save data using np.save, and adds filename in self._record_fns 119 | ''' 120 | self._rec_fns.append(filename+'.npy') 121 | numpy.save(filename, ev_array) 122 | 123 | self._run_id += 1 124 | 125 | def __gen_rec_fns(self): 126 | ''' 127 | Generate filenames for recording 128 | ''' 129 | #Get username 130 | 131 | 132 | import time 133 | N = self._run_id 134 | current_time_str = time.strftime("__" + "%d-%m-%Y-%H:%M:%S", time.localtime()) 135 | filename = self.REC_PATH + '_{2}_{0}__run{1}' 136 | stim_fn = filename.format(current_time_str, N, self.REC_FN_SEQ) 137 | mon_fn = filename.format(current_time_str, N, self.REC_FN_MON ) 138 | return stim_fn, mon_fn 139 | 140 | def __reset(self): 141 | self._run_id = 0 142 | self._rec_fns = [] 143 | return None 144 | 145 | def reset(self): 146 | #CONVIENIENCE FUNCTION, IMPLEMENTATION NOT REQURIED 147 | pass 148 | 149 | def del_all(self): 150 | import glob, os 151 | fn_to_del = glob.glob(self.REC_PATH+'*') 152 | for f in fn_to_del: 153 | os.remove(f) 154 | 155 | def __del__(self): 156 | self.del_all() 157 | 158 | def run(self, *args, **kwargs): 159 | return EMPTY_RAW 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/pyNCS/api/IFSLWTA_brian_model.py: -------------------------------------------------------------------------------- 1 | import brian_no_units 2 | from brian.units import * 3 | from brian.group import * 4 | import time 5 | import scipy.signal as sg 6 | import scipy.stats as stats 7 | import numpy as np 8 | from brian.stdunits import * 9 | from brian.network import run, Network, network_operation 10 | from brian.connections.connection import Connection 11 | from brian.directcontrol import SpikeGeneratorGroup 12 | from brian.clock import defaultclock 13 | from brian.equations import Equations 14 | from brian.neurongroup import NeuronGroup 15 | from brian.monitor import SpikeMonitor, StateMonitor 16 | 17 | 18 | defaultclock.dt = 0.0001*second 19 | #Network Parameters: 20 | N_EP1=124; 21 | N_IP1=4; 22 | N = N_EP1+N_IP1 23 | #VLSI Neuron constants 24 | sigma_mismatch=0.25 25 | 26 | def create_netobjs(stim, params): 27 | C = params['Cap'] 28 | KappaN = params['Kappan'] 29 | KappaP = params['Kappap'] 30 | I0N = params['I0n'] 31 | I0P = params['I0p'] 32 | Ut = params['Ut'] 33 | Delta_t = (Ut/KappaP) 34 | 35 | #Feed-Forward parameters 36 | i_inj = params['i_inj' ] 37 | i_injinh1 = params['i_injinh1'] 38 | i_injinh2 = params['i_injinh2'] 39 | i_injinh3 = params['i_injinh3'] 40 | i_injinh4 = params['i_injinh4'] 41 | i_leak = params['i_leak' ] 42 | tau_syn_E = params['tau_syn_E'] 43 | tau_syn_I = params['tau_syn_I'] 44 | tau_synloc_E = params['tau_synloc_E'] 45 | tau_synloc_IE = params['tau_synloc_IE'] 46 | v_thresh = params['v_thresh' ] 47 | w_syn_E1 = params['w_syn_E1' ] 48 | w_syn_E2 = params['w_syn_E2' ] 49 | w_syn_I = params['w_syn_I' ] 50 | w_synloc_E = params['w_synloc_E'] 51 | w_synloc_EE = params['w_synloc_EE'] 52 | w_synloc_EI = params['w_synloc_EI'] 53 | w_synloc_IE = params['w_synloc_IE'] 54 | w_synloc_S = params['w_synloc_S'] 55 | ##Feed-Back parameters 56 | #w =dict() 57 | #w['e'] =1e-11 58 | #w['i'] =5e-11/N_IP1 59 | #w['ei'] =2e-11/N_EP1 60 | 61 | eqs =Equations(''' 62 | dV/dt=(-I_lk + I_fb + I_in + Ia + Iloce - Iloci - Ii)/C: volt 63 | 64 | 65 | I_fb = I0P*exp((V-v_thresh)/Delta_t) : amp 66 | I_in : amp 67 | I_lk = i_leak : amp 68 | 69 | dIa/dt=-Ia/tau_syn_E: amp 70 | dIloce/dt=-Iloce/tau_synloc_E: amp 71 | dIloci/dt=-Iloci/tau_synloc_IE: amp 72 | dIi/dt=-Ii/tau_syn_I: amp 73 | ''') 74 | 75 | EIP = NeuronGroup(N, model=eqs, reset = 0, threshold=1.5, refractory=.001) 76 | EP1 = EIP[:N_EP1] 77 | IP1 = EIP[N_EP1:] 78 | 79 | EP1.I_in = np.random.normal(1,sigma_mismatch,N_EP1)*i_inj 80 | IP1.I_in = np.random.normal(1,sigma_mismatch,N_IP1)*\ 81 | np.array([i_injinh1, 82 | i_injinh2, 83 | i_injinh3, 84 | i_injinh4]) 85 | 86 | #Create connections between population 87 | v_loclat = np.zeros([N_EP1]) 88 | v_loclat[N_EP1/2] = w_synloc_S 89 | v_loclat[[N_EP1/2-1,N_EP1/2+1]] = w_synloc_E 90 | v_loclat[[N_EP1/2-2,N_EP1/2+2]] = w_synloc_EE 91 | v_loclat[[N_EP1/2-3,N_EP1/2+3]] = w_synloc_EE/2 92 | v_loclat = np.roll(v_loclat,-N_EP1/2) 93 | W = np.array([ np.roll(v_loclat,i) for i in range(N_EP1)]) 94 | W *= np.random.normal(1,sigma_mismatch,W.shape) 95 | ConnE =Connection(EP1,EP1,'Iloce');ConnE.connect(EP1,EP1,W) 96 | ConnEI =Connection(EP1,IP1,'Iloce');ConnEI.connect(EP1,IP1, W = w_synloc_EI*np.random.normal(1,sigma_mismatch,[len(EP1),len(IP1)])) 97 | ConnIE =Connection(IP1,EP1,'Iloci');ConnIE.connect(IP1,EP1, W = w_synloc_IE*np.random.normal(1,sigma_mismatch,[len(IP1),len(EP1)])) 98 | 99 | M_EIP =SpikeMonitor(EIP) 100 | MV_EIP= StateMonitor(EIP,'V',record=range(0,N),timestep=int(1*ms/defaultclock.dt)) 101 | 102 | @network_operation 103 | def update_mpot(): 104 | EIP.V[EIP.V<0.]=0. 105 | # ME_EP1= StateMonitor(EP1,'Ie',record=range(0,N_EP1),timestep=int(1*ms/defaultclock.dt)) 106 | # MI_EP1= StateMonitor(EP1,'Ii',record=range(0,N_EP1),timestep=int(1*ms/defaultclock.dt)) 107 | # MW_EP1= StateMonitor(EP1,'Ia',record=range(0,N_EP1),timestep=int(1*ms/defaultclock.dt)) 108 | 109 | netobjs = {'EIP':EIP, 110 | 'update_mpot':update_mpot, 111 | 'ConnE': ConnE, 112 | 'ConnEI': ConnEI, 113 | 'ConnIE': ConnIE, 114 | #'M_In1': M_In1, 115 | 'M_EIP': M_EIP, 116 | 'MV_EIP': MV_EIP} 117 | 118 | return netobjs, M_EIP, MV_EIP 119 | 120 | 121 | 122 | if __name__ == '__main__': 123 | from pylab import * 124 | from brian.plotting import raster_plot 125 | ion() 126 | from paramTranslation import params, loadBiases 127 | from expSetup import * 128 | configurator = pyNCS.ConfAPI.Configurator() 129 | configurator._readCSV('chipfiles/ifslwta.csv') 130 | configurator.set_parameters(loadBiases('biases/defaultBiases_ifslwta')) 131 | p=params(configurator, 'chipfiles/ifslwta_paramtrans.xml') 132 | p.translate('pinj',2.8) 133 | p.translate('nsynloclat1',0.55) 134 | p.translate('nsynloclat2',0.53) 135 | p.translate('nsynexcinh',0.45) 136 | p.translate('psynlocinhw',2.75) 137 | p.translate('psynlocinhth',.3) 138 | stim = np.transpose([np.random.randint(0,128,32000), np.cumsum(np.random.random(32000)/16)]) 139 | netobjs, M_EIP, MV_EIP = create_netobjs(stim,p.cur) 140 | net = Network(netobjs.values()) 141 | net.run(1) 142 | raster_plot(*[M_EIP]) 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /src/pyNCS/api/paramTranslation.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # File Name : sympyParams.py 3 | # Purpose: 4 | # 5 | # Author: Emre Neftci 6 | # 7 | # Creation Date : 8 | # Last Modified : Tue 15 Mar 2011 06:11:41 PM CET 9 | # 10 | # Copyright : (c) 2011 11 | # Licence : GPLv4 12 | #----------------------------------------------------------------------------- 13 | 14 | #chip=pyNCS.Chip('/home/emre/Neuron/software/pyNCS/src/pyNCS/pads_ifslwta.csv') 15 | import numpy as np 16 | from xml.dom import minidom as md 17 | from urllib2 import urlopen 18 | #chip=pyNCS.Chip('/home/emre/Neuron/software/pyNCS/src/pyNCS/pads_ifslwta.csv') 19 | from numpy import log,exp 20 | 21 | def log(x): 22 | if x<0: 23 | return -1e32 24 | else: 25 | return np.log(x) 26 | 27 | class params(): 28 | 29 | xml_version=.1 30 | 31 | 32 | def __init__(self,configurator, xml_filename): 33 | from sympy import Symbol,exp,log 34 | self.conf=configurator 35 | self.cur=dict() 36 | 37 | for s in self.conf.get_param_names(): 38 | globals()[s]=Symbol(s) 39 | 40 | 41 | self.loadXML(xml_filename) 42 | 43 | #Some default parameters 44 | for i,k in self.initial_parameters.items(): 45 | self.cur.update({i:k}) 46 | 47 | self.cur.update(self.conf.get_parameters()) 48 | 49 | def loadXML(self,filename): 50 | if '://' in filename: 51 | doc= md.parse( urlopen(filename) ) 52 | else: 53 | doc = md.parse( filename ) 54 | 55 | nsetup= doc.childNodes[0] 56 | if nsetup.tagName!='paramtrans' or float(nsetup.getAttribute('version'))`_ 5 | 6 | 7 | Introduction 8 | ------------ 9 | 10 | This package provides the `Oscilloscope class `_ which actually is an abstraction wrapper 11 | that can be used to access any oscilloscope-like device for which exists a 'driver'. So far there is only a 12 | driver provided for the `Spectrum Card `_ -- Normally you wouldn't care too 13 | much about the actual drivers and only use the wrapper. Using a different oscilloscope then results in a simple 14 | change of one line of code: 15 | 16 | .. code-block:: python 17 | 18 | from pyOsc.spectrum import SpectrumCard as driver # already implemented 19 | # from pyOsc.agilent import AgilentEthernetController as driver # not yet implemented ! 20 | 21 | import pyOsc 22 | osc= pyOsc.Oscilloscope( driver() ) 23 | 24 | 25 | Tutorial 26 | -------- 27 | 28 | Initializing 29 | ~~~~~~~~~~~~ 30 | 31 | Let's assume we are connected via ``ssh`` to ``zaex`` where the ``SpectrumCard`` is currently installed and 32 | let's assume we have some single chip setup as described in the setup file 33 | `zaex.xml `_ 34 | 35 | .. code-block:: python 36 | 37 | import pyOsc,pyNCS 38 | from pyOsc.spectrum import SpectrumCard as driver # already implemented 39 | osc= pyOsc.Oscilloscope( driver(debug=True) ) 40 | basedir = '/home/federico/pyFED/' 41 | setup = pyNCS.NeuroSetup(basedir+'setups/mc_setuptype.xml',basedir+'setups/mc.xml'); 42 | 43 | The spectrum card has 8 channels. As of the time of writing this tutorial, we have them connected to the 44 | ``ifslwta`` chip in a particular way. In order to avoid confusing the lines and signals, we can label 45 | the channels like this 46 | 47 | .. code-block:: python 48 | 49 | osc.names( { 50 | 0 : 'Vmem127', 51 | 1 : 'Vsyn ("Vpls")', 52 | 2 : 'Vpls ("Vsyn")', 53 | 3 : 'VsynAER', 54 | 4 : 'VplsAER', 55 | 5 : 'Vk', 56 | 6 : 'Vwstd', 57 | 7 : 'Vmem (scanner)' }) 58 | 59 | 60 | Getting some data 61 | ~~~~~~~~~~~~~~~~~ 62 | 63 | In the simplest scenario, we inject some current, set the scanner to any neuron, setup the channels and 64 | just start recording 65 | 66 | .. code-block:: python 67 | 68 | osc.channels( [7] ) # activate only 1 channel 69 | osc.ranges( {7:1000} ) # set the range to (-1000mV) to (1000mV) 70 | osc.sr( 1024 ) # sample rate in Hertz 71 | setup.find('ifslwta').bias.pinj.v= 2.87 # inject some current into all neurons 72 | 73 | 74 | We know that all the neurons are firing more or less continuously due to the injection current. We would 75 | like to acquire 5 seconds of data. The whole process of data acquiring is completely asynchronous, so we 76 | have to tell the oscilloscope how much data we would like and then we need to wait until the oscilloscope 77 | is ready: 78 | 79 | .. code-block:: python 80 | 81 | samples= 5* osc.sr() 82 | osc.start( samples ) 83 | import time 84 | while not osc.done(): time.sleep(1) 85 | 86 | 87 | When we got so far, the whole data is acquired and can be found on the oscilloscope. In order to process 88 | it in python scripts, we need first to transfer it to the computer memory. This is done by 89 | 90 | .. code-block:: python 91 | 92 | data= osc.data() 93 | 94 | The data is now contained in raw format in the dictionary ``data``. The keys to the dictionary are the 95 | channel numbers and the samples are of type ``numpy.int16`` (for the spectrumcard, other drivers may 96 | specify different sample types). 97 | 98 | 99 | Visualizing the data 100 | ~~~~~~~~~~~~~~~~~~~~ 101 | 102 | Simply type 103 | 104 | .. code-block:: python 105 | 106 | osc.plot( data ) 107 | from matplotlib import pyplot as plt 108 | plt.show() #pop up plot 109 | 110 | This should result in a plot similar to the following 111 | 112 | .. figure:: ../images/raw_data.png 113 | :align: center 114 | :width: 627px 115 | :alt: raw data from oscilloscope 116 | 117 | If you want to display the data in millivolt and milliseconds instead of samples, simply type 118 | 119 | .. code-block:: python 120 | 121 | osc.plot( osc.normalize(data) ) 122 | 123 | 124 | Setting a trigger 125 | ~~~~~~~~~~~~~~~~~ 126 | 127 | Let's suppose we want to have a nice picture of the spiking neuron. You can easily see in the figure 128 | above that the different spikes are not exactly the same, so let's take the average over several cycles 129 | to get a smoother and more representative image. 130 | 131 | In order to do this we will set a trigger on the sharp falling edge of the membrane potential and center 132 | the data around that trigger. Let's first precisely determine the point we want to trigger at. For this 133 | purpose I use the normalized data plot from above, zoom a little bit closer and move my mouse cursor to 134 | the point I want to trigger at: 135 | 136 | .. figure:: ../images/normalized_data_zoomed.png 137 | :align: center 138 | :width: 649px 139 | :alt: raw data from oscilloscope 140 | 141 | Ok. What we want is the following 142 | 143 | - Trigger on the falling edge at 138 mV (on channel 7). 144 | - Record 200ms on every trigger. 145 | - Center the falling edge at 20% of these 200ms. 146 | - Collect 10 'rounds' of data. 147 | 148 | This translates into the following code 149 | 150 | .. code-block:: python 151 | 152 | osc.trigger( 7,'\\',138,offset=.2 ) 153 | samples= osc.sr() * .2 154 | osc.rounds( 10 ) 155 | 156 | As above, we start the data acquisition, wait for the oscilloscope to be ready and transfer the data: 157 | 158 | .. code-block:: python 159 | 160 | osc.start( samples ) 161 | import time 162 | while not osc.done(): time.sleep(1) 163 | data= osc.data() 164 | 165 | 166 | The raw plott looks pretty confusing, because we the different rounds are just concatenated one after 167 | the other in the sample data. That's why we let the oscilloscope wrapper plot markings between the rounds 168 | and indicate the trigger level with a red line 169 | 170 | .. code-block:: python 171 | 172 | osc.plot( data,decorate=True ) 173 | 174 | .. figure:: ../images/decorated_data.png 175 | :align: center 176 | :width: 649px 177 | :alt: raw data from oscilloscope 178 | 179 | 180 | We can now calculate our smooth plot by averaging the rounds. There's a convinience method in ``Oscilloscope`` 181 | to do this 182 | 183 | .. code-block:: python 184 | 185 | average= osc.average(data) 186 | osc.plot(osc.normalize( average )) 187 | 188 | 189 | Feedback 190 | ~~~~~~~~ 191 | 192 | If you found this tutorial useful or if you have any questions or if things did not work out 193 | the way they are supposed to, you can always `send me an email `_ 194 | 195 | -------------------------------------------------------------------------------- /docs/general/pytune_python_file_template.txt: -------------------------------------------------------------------------------- 1 | :: 2 | 3 | # -*- coding: utf-8 -*- 4 | 5 | # HELLO, 6 | # THIS IS A TEMPLATE FOR THE CREATION OF PARAMETERS IN THE NCS PLUGIN OF 7 | # pyTune. PLEASE READ ALL THE STRINGS WRITTEN IN CAPITAL LETTERS AND FOLLOW THE 8 | # DESCRIBED CONVENTIONS AS MUCH AS POSSIBLE. 9 | 10 | from __future__ import with_statement 11 | from os import path 12 | from pyTune.base import Parameter 13 | from pyAex import netClient 14 | #from pyOsc import pyOsc 15 | 16 | import numpy as np 17 | 18 | # DEFINE SCOPE CHANNELS HERE # 19 | #global scope 20 | #scope = pyOsc.Oscilloscope( driver(debug=True) ) 21 | #scope.names( { 22 | #0 : 'Vmem127', 23 | #1 : 'Vsyn ("Vpls")', 24 | #2 : 'Vpls ("Vsyn")', 25 | #3 : 'VsynAER', 26 | #4 : 'VplsAER', 27 | #5 : 'Vk', 28 | #6 : 'Vwstd', 29 | #7 : 'Vmem (scanner)' }) 30 | 31 | class Template(Parameter): # REPLACE WITH NameOfYourParameter 32 | ''' 33 | DESCRIBE PARAMETER HERE. 34 | Units: "UNITS HERE" 35 | ''' 36 | def __init__(self, paramid='Template', # if your parameter has a long name: 37 | # PlesaUseThisFormat 38 | xmlfilename='template.xml', # now instead, use_this_format 39 | history_filename='template.history'): # and_also_here 40 | ''' 41 | ''' 42 | # DON'T FORGET TO CREATE your_parameter.xml! 43 | # PLEASE DON'T MODIFY THIS 44 | resources = path.join(path.dirname(__file__), xmlfilename) 45 | history_filename = path.join(path.dirname(__file__), history_filename) 46 | Parameter.__init__(self, paramid, xml=resources, history_filename=history_filename) 47 | 48 | def setContext(self, population, synapses_id): 49 | """ 50 | THIS SETS THE context OF A PARAMETER, I.E. POPULATION(S) ON WHICH IT 51 | ACTS. PLEASE DESCRIBE ARGUMENTS HERE, AS SHOWN IN THE FOLLOWING 52 | EXAMPLE. 53 | Sets the context for the parameter. Arguments are: 54 | - population = pyNCS.Population 55 | - synapses_id = The string of the synapses (e.g. 'excitatory0') 56 | """ 57 | # DEFINE YOUR context HERE, FOR EXAMPLE: 58 | self.neurons = population.soma 59 | self.synapses = population.synapses[synapses_id] 60 | 61 | # DON'T FORGET YOU CAN USE Population.neuronblock, IN WHICH YOU FIND 62 | # ALL THE BIASES THAT YOU NEED. SEE EXAMPLE: 63 | self.bias = population.neuronblock.synapses[synapses_id].biases['tau'] 64 | 65 | # THE SET OF FUNCTIONS STARTING WITH DOUBLE UNDERSCORE REPLACE THE ONES 66 | # INHERITED FROM pyTune.Parameter 67 | 68 | def __getValue__(self): 69 | """ 70 | DESCRIBE HOW THE FUNCTION WORKS. 71 | """ 72 | # YOU ALWAYS HAVE TO IMPLEMENT A GET FUNCTION. 73 | # DON'T FORGET YOU CAN DEFINE __getvalue_startup__ IF YOU NEED TO DO 74 | # SOME OPERATION BEFORE THE ACUTAL MEASURE (IT IS AUTOMATICALLY CALLED, 75 | # PLEASE *DON'T* CALL IT HERE. 76 | # IF THE VALUE IS A FUNCTION OF THE VALUE OF THE SUB-PARAMETERS, YOU 77 | # CAN CALL THEM EXPLICITLY HERE VIA: 78 | # Parameter.parameters['name_of_subparameter'].getValue() 79 | return value 80 | 81 | def __setValue__(self, value, searchparams): 82 | """ 83 | DESCRIBE HOW THE FUNCTION WORKS. 84 | """ 85 | # YOU DON'T NECESSARILY NEED TO SPECIFY A SET FUNCTION. IF YOU DON'T 86 | # SPECIFY HERE, A RECURSIVE FUNCTION WILL BE USED [TODO: is this true?] 87 | # searchparams IS A DICTIONARY CONTAINING ALL THE ADDITIONAL 88 | # INFORMATIONS YOUR ALGORITHM NEEDS, SUCH AS TOLERANCE, INCREMENT STEP 89 | # SIZE, ETC. AN EXAMPLE IS THE FOLLOWING: 90 | # searchparams = { 91 | # 'tolerance_style' : '%', 92 | # 'template' : {'tolerance' : 20, 93 | # 'max' : 10, 94 | # 'min' : 0, 95 | # 'step' : 1, 96 | # 'step_type' : 'linear', 97 | # } 98 | # 'subparam1' : {'tolerance' : 10, 99 | # 'max' : 4, 100 | # 'min' : 3, 101 | # 'step' : 0.1, 102 | # 'step_type' : 'exponential', 103 | # } 104 | # 'subparam2' : {'tolerance' : 10, 105 | # } 106 | # } 107 | # PLEASE NOTICE: DON'T FORGET TO DEFINE A FUNCTION THAT LOOKS WHEITHER 108 | # THE SEARCHPARAMS HAVE BEEN DEFINED AND PUTS DEFAULT VALUES 109 | # INSTEAD. 110 | return value 111 | 112 | def __get_method__(self): # PLEASE REPLACE method WITH THE 113 | # name_of_the_method 114 | ''' 115 | DESCRIBE HOW THE METHOD WORKS. 116 | ''' 117 | # IMPLEMENT YOUR OWN METHOD HERE. FOR EXAMPLE, YOU MAY HAVE TWO 118 | # DIFFERENT WAYS TO MEASURE YOUR PARAMETER, ONE USING THE SCOPE ONE 119 | # USING SPIKING DATA. YOU CAN THEN DEFINE __get_scope__ AND 120 | # __get_spiking__. YOU CAN DEFINE AS MANY METHOD AS YOU WANT AND THEN 121 | # CALL THEM IN YOUR SCRIPT BY: 122 | # getValue(method='your_method_here') 123 | return value 124 | 125 | def __set_method__(self, value, searchparams): # PLEASE REPLACE method WITH THE 126 | # name_of_the_method 127 | ''' 128 | DESCRIBE HOW THE METHOD WORKS. 129 | ''' 130 | # IMPLEMENT YOUR METHOD HERE. READ __get_method__ COMMENTS TO KNOW MORE 131 | # ABOUT METHODS. 132 | return value 133 | 134 | def __get_startup__(self): 135 | """ 136 | """ 137 | # THIS FUNCTION IS CALLED AT EVERY getValue CALL AND IT IS USED TO 138 | # APPLY PRELIMINARY SETTING IF NEEDED, E.G. SET ALL LEARNING SYNAPSES 139 | # TO HIGH IF YOU WANT TO MEASURE THEIR EFFICACY. 140 | return 141 | 142 | def __set_startup__(self): 143 | """ 144 | """ 145 | # THIS FUNCTION IS CALLED AT EVERY setValue CALL AND IT IS USED TO 146 | # APPLY PRELIMINARY SETTING IF NEEDED 147 | return 148 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Python Spike Toolbox documentation build configuration file, created by 4 | # sphinx-quickstart on Mon Nov 23 16:07:25 2009. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.append(os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # Add any Sphinx extension module names here, as strings. They can be extensions 24 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 25 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath'] 26 | 27 | # Add any paths that contain templates here, relative to this directory. 28 | templates_path = ['_templates'] 29 | 30 | # The suffix of source filenames. 31 | source_suffix = '.txt' 32 | 33 | # The encoding of source files. 34 | #source_encoding = 'utf-8' 35 | 36 | # The master toctree document. 37 | master_doc = 'index' 38 | 39 | # General information about the project. 40 | project = u'Python NCS tools' 41 | copyright = u'2012, University of Zurich, Emre Neftci, Sadique Sheik, Fabio Stefanini, Giacomo Indiveri' 42 | 43 | # The version info for the project you're documenting, acts as replacement for 44 | # |version| and |release|, also used in various other places throughout the 45 | # built documents. 46 | # 47 | # The short X.Y version. 48 | version = '0.2' 49 | # The full version, including alpha/beta/rc tags. 50 | release = '0.2' 51 | 52 | # The language for content autogenerated by Sphinx. Refer to documentation 53 | # for a list of supported languages. 54 | #language = None 55 | 56 | # There are two options for replacing |today|: either, you set today to some 57 | # non-false value, then it is used: 58 | #today = '' 59 | # Else, today_fmt is used as the format for a strftime call. 60 | #today_fmt = '%B %d, %Y' 61 | 62 | # List of documents that shouldn't be included in the build. 63 | #unused_docs = [] 64 | 65 | # List of directories, relative to source directory, that shouldn't be searched 66 | # for source files. 67 | exclude_trees = ['_build'] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. Major themes that come with 93 | # Sphinx are currently 'default' and 'sphinxdoc'. 94 | html_theme = 'default' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | #html_theme_options = {} 100 | 101 | # Add any paths that contain custom themes here, relative to this directory. 102 | #html_theme_path = [] 103 | 104 | # The name for this set of Sphinx documents. If None, it defaults to 105 | # " v documentation". 106 | #html_title = None 107 | 108 | # A shorter title for the navigation bar. Default is the same as html_title. 109 | #html_short_title = None 110 | 111 | # The name of an image file (relative to this directory) to place at the top 112 | # of the sidebar. 113 | #html_logo = None 114 | 115 | # The name of an image file (within the static path) to use as favicon of the 116 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 117 | # pixels large. 118 | #html_favicon = None 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ['_static'] 124 | 125 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 126 | # using the given strftime format. 127 | #html_last_updated_fmt = '%b %d, %Y' 128 | 129 | # If true, SmartyPants will be used to convert quotes and dashes to 130 | # typographically correct entities. 131 | #html_use_smartypants = True 132 | 133 | # Custom sidebar templates, maps document names to template names. 134 | #html_sidebars = {} 135 | 136 | # Additional templates that should be rendered to pages, maps page names to 137 | # template names. 138 | #html_additional_pages = {} 139 | 140 | # If false, no module index is generated. 141 | #html_use_modindex = True 142 | 143 | # If false, no index is generated. 144 | #html_use_index = True 145 | 146 | # If true, the index is split into individual pages for each letter. 147 | #html_split_index = False 148 | 149 | # If true, links to the reST sources are added to the pages. 150 | #html_show_sourcelink = True 151 | 152 | # If true, an OpenSearch description file will be output, and all pages will 153 | # contain a tag referring to it. The value of this option must be the 154 | # base URL from which the finished HTML is served. 155 | #html_use_opensearch = '' 156 | 157 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 158 | #html_file_suffix = '' 159 | 160 | # Output file base name for HTML help builder. 161 | htmlhelp_basename = 'PythonSpikeToolboxdoc' 162 | 163 | 164 | # -- Options for LaTeX output -------------------------------------------------- 165 | 166 | # The paper size ('letter' or 'a4'). 167 | #latex_paper_size = 'letter' 168 | 169 | # The font size ('10pt', '11pt' or '12pt'). 170 | #latex_font_size = '10pt' 171 | 172 | # Grouping the document tree into LaTeX files. List of tuples 173 | # (source start file, target name, title, author, documentclass [howto/manual]). 174 | latex_documents = [ 175 | ('index', 'PythonSpikeToolbox.tex', u'Python Spike Toolbox Documentation', 176 | u'Emre Neftci', 'manual'), 177 | ] 178 | 179 | # The name of an image file (relative to this directory) to place at the top of 180 | # the title page. 181 | #latex_logo = None 182 | 183 | # For "manual" documents, if this is true, then toplevel headings are parts, 184 | # not chapters. 185 | #latex_use_parts = False 186 | 187 | # Additional stuff for the LaTeX preamble. 188 | #latex_preamble = '' 189 | 190 | # Documents to append as an appendix to all manuals. 191 | #latex_appendices = [] 192 | 193 | # If false, no module index is generated. 194 | #latex_use_modindex = True 195 | 196 | 197 | # Example configuration for intersphinx: refer to the Python standard library. 198 | intersphinx_mapping = {'http://docs.python.org/': None} 199 | -------------------------------------------------------------------------------- /docs/general/introduction.txt: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | A general introduction. 5 | 6 | Neuromorphic hardware 7 | --------------------- 8 | 9 | - multineuron chips 10 | - AER communication 11 | 12 | Description of the Chips Developed at INI 13 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | Our VLSI chips can be interfaced to computers via custom "AEX" boards, and 16 | among each other via a custom "mapper" board. The AEX boards are controlled by 17 | an FPGA (Filed Programmable Gate Array) which routes the communications between 18 | serial (i.e. other chips and mapper), parallel (i.e. the chip) and usb ports 19 | (i.e. the user's computer). Here is a brief tutorial on how to use these 20 | boards, how they are configured in a multi-chip setup, and how to re-program 21 | the FPGAs on the AEX boards to suit your needs. 22 | 23 | :IFSLWTA: 24 | 25 | This chip contains a 1D sheet consisting of 128 IAF neurons, 4 of them receive 26 | excitation from the other 124 and inhibit them back. Each row has 32 synapses, 27 | 2 excitatory, 2 inhibitory, 28 excitatory plastic synapses. Neurons have local 28 | connections to first and second neighbour. Plasticity acts as a 2 state switch: 29 | each synapse (28*128) can be turned on or off by learning. If it happens that 30 | one synapse has a value between the on and off values, it will be pushed to the 31 | nearest one according to a set of thresholds. 32 | 33 | This chip shows the Stop-Learning algorithm (Brader et al., 2007; Mitra et al., 34 | 2009). 35 | 36 | Uses 12/16bits for neuron addressing. 37 | 38 | :2DIFWTA: 39 | 40 | This chip is a 2D matrix of 32*64 IAF neurons similar to the ifslwta ones. Each 41 | neuron has 2 excitatory connections (synapses 1-2) and 1 inhibitory (synapse 0). Local connections are 42 | with the nearest neighbour (can be limited to 1/2 vertical neighbours +/- 1 lateral/diagonal neighbours). 43 | Uses 13/16bits for neuron addressing. 44 | There is a *bug* in this chip that generates illegal events on the AER bus : 45 | Every time an inhibitory synapse of a neuron with a Y coordinate of (4n+2) or 46 | (4n+3) is addressed, the system gets into a hung-up state and all AEX boards 47 | have to be restarted in order to make it work again ! 48 | 49 | :CPG: 50 | 51 | :DVS Silicon Retina: 52 | 53 | :Silicon cochlea: 54 | 55 | The AER interface board 56 | ~~~~~~~~~~~~~~~~~~~~~~~ 57 | 58 | AER chips need to be interfaced to the outer world. We developed a custom board 59 | to route signals from/to the chip to/from a usb connected computer and a serial 60 | bus for multi-chip and mapping capabilities. 61 | 62 | An AEX board has three I/O channels: 63 | USB, Parallel, Serial. USB protocol is used for communication with an external 64 | PC for monitoring, bias settings and stimulation. Parallel port gives access to 65 | the chip through the AMDA and daughter board. Serial communication is used by 66 | the mapper via the AER protocol. The board is controlled by a Xilinx ***model*** 67 | 32bits FPGA chip. Refer to D. Fasnacht Master thesis for more infos. 68 | The mapper receives spike events from the chip with a stamp which identifies the 69 | neuron that emitted that spike. A mapping table is compiled on the mapper so 70 | every incoming event can be sent to other neurons as they were 71 | connected by a synapse. Mapper has a I/O serial interface (16bit). Refer to D. 72 | Fasnacht documentation. 73 | 74 | The mapper 75 | ~~~~~~~~~~ 76 | 77 | Suppose you have N chips (so N AEX boards, AMDAs and daughter boards). Using one 78 | mapper you can arbitrarily connect neurons of these chips, building complex networks. 79 | 80 | We have two setups currently available: 81 | 82 | * the `Zenzero setup `_ 83 | * the `Zaex setup `_ 84 | 85 | Refer to those pages for details on how to use these existing setups. If you 86 | want to arrange a chip in a new multichip setup, you have to reprogram the AEX 87 | board's FPGA, where informations are routed and filtered properly. 88 | 89 | Please notice that what you are going to reprogram is only valid for a specific 90 | setup, so before going into any modification prepare the setup you want to 91 | arrange. For example: 1 2Difwta and 1 ifslwta. The serial connections are 92 | arranged in a loop chain as 93 | 94 | ========== === =========== 95 | Source Destination 96 | ========== === =========== 97 | Mapper OUT --> Chip1 IN 98 | ---------- --- ----------- 99 | Chip1 OUT --> Chip2 IN 100 | ---------- --- ----------- 101 | ... 102 | ---------- --- ----------- 103 | ChipN OUT --> Mapper IN 104 | ========== === =========== 105 | 106 | ChipN is connected to the user's PC via USB. An address coming from the mapper 107 | is checked by each AEX board and sent to the next chip. If it is an address for 108 | ChipM, AEX board number M will also send the message to its chip via Parallel 109 | port. This message will pass through each AEX until the mapper rejects it (see 110 | next section for details). An address coming from ChipL will be stamped by its 111 | AEX board. Chip addressing use the bits that are not used for neurons 112 | addressing. Of course there are some limitations. The first one can think of 113 | is a bandwith limitation, the amount of information per time unit the chain can 114 | process. 115 | 116 | In this design we will suppose that mapper capabilities are enough to route all 117 | the incoming events without sensible deviations from the ideal case. This can 118 | be false in particular cases. The second is in the address space. Each chip 119 | needs a certain amount of bits for the addressing of neurons. The bigger the 120 | chip (N neurons), the higher the number (~logN). While the AEX boards can 121 | manage 32bits data, the mapper serial communication is 16bits so 16 bits are 122 | the maximum number of bits one can use for chip and neurons addressing. The 123 | design must consider the maximum amount of bits for neurons addressing and what 124 | remains for chip addressing. The design presented here refers to the use of 1 125 | Retina and 3 2Difwta chip. One can even choose not to use the retina and use 126 | the sequencer instead. They cannot be used together at the same time. You can 127 | use either 2Difwta and/or ifslwta chips. Once you program the AEX you cannot 128 | change the position of an AEX in the chain * is it true? *. 2Difwta uses 13/16 129 | bits, so we have 3 bits left for chips addressing. Retina chip uses 15/16 bits 130 | but here we can use only 13 of them restricting the size of the retina. The 8 131 | resulting addresses are as follows. 132 | 133 | .. Make a table here 134 | 135 | ============== ======= 136 | Chip IN 137 | ============== ======= 138 | Retina/Seq 000 139 | -------------- ------- 140 | Chip 1 IN: 001 141 | -------------- ------- 142 | Chip 2 IN: 010 143 | -------------- ------- 144 | Chip 3 IN: 011 145 | ============== ======= 146 | 147 | ============== ======= 148 | Chip OUT 149 | ============== ======= 150 | Retina/Seq 100 151 | -------------- ------- 152 | Chip 1 101 153 | -------------- ------- 154 | Chip 2 110 155 | -------------- ------- 156 | Chip 3 111 157 | ============== ======= 158 | 159 | Each setup needs one (and only one) special channel 0 board. This board doesn't 160 | transmit mapped events (i.e. inputs for the chips) through the serial-to-serial 161 | path. This means it has to be the last one on the chain and the one that is 162 | used to send events from usb to the chain. This serial-to-serial filtering has 163 | been introduced after realizing that the mapper cannot receive mapped events, 164 | otherwise the chain is blocked. Please notice that because of this you cannot 165 | use channel 4 (retina input) for the sequencer: your events would be trashed by 166 | the special aex. 167 | 168 | Software 169 | -------- 170 | 171 | .. figure:: ../images/software.jpg 172 | 173 | Software for real-time interaction, control, configuration of a neuromorphic 174 | system. General stuff about: 175 | 176 | - what can be done 177 | - how it is implemented 178 | - what's needed to control new hardware (csv, xml, ...) 179 | - server-client architecture 180 | -------------------------------------------------------------------------------- /docs/general/spcm.txt: -------------------------------------------------------------------------------- 1 | Spectrum Board installation 2 | =========================== 3 | 4 | A digital acquisition board is installed on one of the NCS machines. This 5 | board, named Spectrum after the producers name, can be used for the acquisition 6 | of analog signals directly from the chips, giving the user the possibility to 7 | integrate his experiments with a tool for the reading of non-AER signals. NCS 8 | group has written an interface in Python and standard basic operation can now 9 | be done from inside a python script just calling an executable. 10 | 11 | Introduction 12 | ------------ 13 | 14 | The board is a Spectrum M2i.3132. It has 8 channels, 12bits. They can acquire simultaneously at 25MHZ max [#]_. 15 | 16 | Drivers and software are provided for 17 | Windows and a bunch of linux distributions and architectures. For zaex machine, we need the driver sources and compile the driver. The source code is *not* 18 | distributed so we need a special permission in order to use (and eventually modify) their driver. Every programmer using the board has to sign an agreement saying 19 | the usual things like "I will not re-ditribute the code... I will not use the code for making money...". Something like this will work:: 20 | 21 | Dear Bernd, 22 | I'm a PhD working at the Institute of Neuroinfomatics in Zurich with 23 | Giacomo Indiveri. We have an M2i.3132 installed and I need the driver 24 | source code because there is no build for our distribution and architecture 25 | (Ubuntu , multicore SMP, ). I know I can sign a non-disclosure agreement, 26 | can you send it please? 27 | Thank you and best regards, 28 | Fabio Stefanini 29 | 30 | Easily speaking, the board itself is a minimal oscilloscope. It is much similar (in concept) to the hardware installed on other more expensive oscilloscopes 31 | with nice LCD panels, buttons, controls, ... This one has a lot of advantages, over the obvious disadvantage represented by the performances: it is provided as 32 | a PCI card to be installed on a computer. This means it can be used by scripts which eventually need to read analog signal and then perform some operation. 33 | First example coming to your mind: auto-adjusting biases on a chip! 34 | 35 | Since the company only gave us the driver, we needed to write our own interface, even because our very peculiar NCS-style purposes (interface with the chips). 36 | A first attempt of having a complete interface to be integrated in a complex optimization algorithm was done by the writer and it is here documented. 37 | At this Alpha stage, the C program is able to set board's parameters (how many channels you want to use? Which range in voltages? Which signal should trigger 38 | the acquisition? etc.) and perform an acquisition writing the output directly into a file. 39 | 40 | .. [q] The main contact is ''Bernd.Toerner AT spec DOT de'', ''Claudia.Boras AT spec DOT de'' was the girl 41 | replying to my email, ''Matthias.Wilma AT spec DOT de'' is the contact for technical support. 42 | 43 | .. [#] This is enough for acquiring signals from our chips. For example, with a samplerate of 25MHz you can clearly catch req/ack signals and trigger acquisition with them. 44 | 45 | Installing/Updating the board 46 | ----------------------------- 47 | 48 | You can checkout all the code you need from svn_. Here's a short description of the important content you just downloaded: 49 | 50 | - examples: a set of examples programs in C provided by the company. They should easily work and I started from them writing the actual interface. 51 | - spcm_linuxkernel_source: the driver source! 52 | - ncspectrum: the programs for acquiring signals 53 | - m2i31_manual_english.pdf: the manual... 54 | 55 | .. _svn: https://svn.ini.uzh.ch/repos/avlsi/NCS/SW/spectrum/. 56 | 57 | Now have the source code. It is good to update it from time to time. Go to the `Spectrum's website`_ for new software. For the latest new driver 58 | you always have to ask them the source by email, though. Let's see how to update the driver. 59 | 60 | .. _Spectrum's website: http://www.spec.de/driver_download.html 61 | 62 | You need to be root sometimes to complete the operations(Actually you should be a member of SPCM group on ZAEX to have the right access!!). Ask zaex's admins for that. To compile the drivers type:: 63 | 64 | $ sudo su 65 | # cd spcm_linuxkernel_source/m2i_krnl_linux 66 | # make -f Makefile.kernel26 67 | 68 | The kernel module should be copied in the /lib/modules/`uname -r`/extras. Run a:: 69 | 70 | # sudo depmod 71 | 72 | to make sure the module list is updated. To load the module run:: 73 | 74 | # sudo modprobe spcm 75 | 76 | If modprobe does not work, try:: 77 | 78 | # sudo insmod /lib/modules/`uname -r`/extras/spcm.ko 79 | 80 | Check that the /dev/spcm0 node is created and check its permissions. If it has root permissions, it means udev rules didn't work so always remember to run the programs that use the device as root. Trying to solve the udev problem is also a good idea. 81 | 82 | *TODO: fix udev problem (udev rule apply correct permissions to /dev/spcm0 but segfault is raised if you are not root!)* 83 | 84 | Spectrum software 85 | ----------------- 86 | 87 | From the company's website you can download the latest software. The first one is the Spcm Control Center (spcm_control_center_v127b3459.tgz). It visualizes some 88 | infos about the spcm card so you can use it in order to check that the board is really running. You can do also other unimportant stuff with it if you want. 89 | 90 | An other cool and useful one is SBench6 (sbench6-6.0.06b3529-1.64bit_stdc++6.rpm). Install it by typing:: 91 | 92 | $> sudo rpm -Uvh sbench6-6.0.06b3529-1.64bit_stdc++6.rpm 93 | 94 | Once you do that you end up with a cool GUI which visualize signals in realtime. You can practice with it a bit. Just run it:: 95 | 96 | $> SBench6 97 | 98 | Normally, you first visualize the signals you are going to acquire and sets the parameters (ranges, offsets, ...), try some acquisition and test different 99 | buffer lenghts and triggering and finally put everything in a python script and automatize the acquisition. The latter operation is a bit time consuming because 100 | it require to write a lot of stuff. Since you can save the configuration file directly from the GUI, it would be nice to be able to read this signal from inside the 101 | python script. Do you want to be the really first guy implementing this amazing feature? Be my guest then! 102 | 103 | For saving the configuration just go to File > Save config. It will save a txt file with a lot of stuff in it. 104 | 105 | Please notice that the free version of SBench6 doesn't allow ASCII save of data file. If you want an ASCII file with your data you can only use the C program ``rec_single_asciifile``. 106 | 107 | Common problems 108 | --------------- 109 | 110 | Debugging 111 | ~~~~~~~~~ 112 | 113 | Whenever something weird happens, is cool to have a trace of all the operations that have been done with the board. 114 | Open the Spectrum Control Center and set the log level on the support tab to "log all, including library calls". 115 | Then close the Control Center and start your program. 116 | Now all driver calls and further informations are stored in the file "spcmdrv_debug.txt". If you want to contact the company, always send them this file. 117 | It is also useful for debugging you program, obviously. 118 | 119 | The system doesn't find the board 120 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 121 | 122 | It can be a problem of permission. Try running you command with ``sudo``, for example:: 123 | 124 | $> sudo Sbench6 125 | 126 | If this works, it means the udev rule is not working properly setting the right permissions for ``/dev/spcm0``. If it still doesn't work 127 | the problem is maybe hard to solve. First, check that ``/dev/spcm0`` is actually there, then try to remove the module and load it again:: 128 | 129 | $> sudo rmmod spcm 130 | $> ls /dev/spcm0 131 | ls: cannot access /dev/spcm0: No such file or directory 132 | $> sudo modprobe spcm 133 | $> ls /dev/spcm0 134 | /dev/spcm0 135 | 136 | SBench6 keeps crashing 137 | ~~~~~~~~~~~~~~~~~~~~~~ 138 | 139 | Well... That's why it is so useful to save a config file... If it crashes, just close it and open it again. Perhaps this is related to the "acquiring 140 | zeros" problem. Who knows... You may want to contact the company. 141 | 142 | 143 | Acquired signals are all 0s 144 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 145 | 146 | This is a bug somewhere in the driver, most probably. Nobody really figured out how to solve it. A work-around is to set a smaller buffersize (under 2MB) 147 | and/or decreasing the framerate and acquire again. Do you want to fix this problem? Be my guest! 148 | -------------------------------------------------------------------------------- /test/chipfiles/ifslwta.csv: -------------------------------------------------------------------------------- 1 | "chipclass" "IFSLWTA" 2 | 3 | "aerIn" 4 | "id" "x" "range" "range(128)" "type" "1" "f" "X" 5 | "id" "s" "range" "range(32)" "type" "-1" "f" "Y" 6 | "pinid" "X" "f" "x" 7 | "pinid" "Y" "f" "s" 8 | "pinlayout" "X0 X1 X2 X3 X4 X5 X6 Y4 Y3 Y2 Y1 Y0" 9 | 10 | "aerOut" 11 | "id" "x" "range" "range(128)" "type" "1" "f" "X" 12 | "pinid" "X" "f" "x" 13 | "pinlayout" "X6 X5 X4 X3 X2 X1 X0" 14 | 15 | Count PIN PKG CircuitBlock SignalName FET BiasType PadType Range SimulationValue Description Channel Shared with 16 | 1 4 4 Arbiter TX0 (scx) LATCH Transmitter Data 17 | 2 5 5 TX1 (scx) LATCH Transmitter Data 18 | 3 6 6 TX2 (scx) LATCH Transmitter Data 19 | 4 7 7 TX3(scx) LATCH Transmitter Data 20 | 5 8 8 TX4 (scx) LATCH Transmitter Data 21 | 6 9 9 TX5 (scx) LATCH Transmitter Data 22 | 7 10 10 TX6 (scx) LATCH Transmitter Data 23 | 8 11 11 nTREQ digiOUT Transmitter Chip Request (active low) 24 | 9 3 3 nTACK digiIN Transmitter Chip Acknowledge (active low) 25 | 10 12 12 Aepd n dac IN [0.4:1.2] AER Pull-down bias 1 26 | 11 17 17 Decoder RX0(0/1) digiIN Receiver X Data 27 | 12 16 16 RX1(0/1) digiIN Receiver X Data 28 | 13 15 15 RX2(0/1) digiIN Receiver X Data 29 | 14 14 14 RX3(0/1) digiIN Receiver X Data 30 | 15 13 13 RX4(0/1) digiIN Receiver X Data 31 | 16 30 30 RY0(0/1) digiIN Receiver Y Data 32 | 17 29 29 RY1(0/1) digiIN Receiver Y Data 33 | 18 28 28 RY2(0/1) digiIN Receiver Y Data 34 | 19 27 27 RY3(0/1) digiIN Receiver Y Data 35 | 20 26 26 RY4(0/1) digiIN Receiver Y Data 36 | 21 25 25 RY5(0/1) digiIN Receiver Y Data 37 | 22 24 24 RY6(0/1) digiIN Receiver Y Data 38 | 23 19 19 RREQ digiIN Receiver Chip Request 39 | 24 21 21 RACK digiOUT Receiver Chip Acknowledge 40 | 25 32 32 PixAck WIDE Global Pixel Acknowledge signal 41 | 26 31 31 SynPU p dac IN [2.7:2.9] Pull-up bias of AER synaptic circuits 5 42 | 27 115 119 Scanner CK IN Scanner input clock (e.g. 3KHz) 43 | 28 116 120 OR digiOUT Scanner sync signal 44 | 29 1 1 ScanPD n dac IN [0.3:0.9] Scanner pull-down bias 0 45 | 30 111 113 ScanPBias p IN [2.4:3.0] Scanner p-type Op-amp bias 46 | 31 109 111 UP WIDE Scanned global UP learning signal 47 | 32 110 112 DN WIDE Scanned global DN learning signal 48 | 33 112 114 mem WIDE Scanned membrane potential 49 | 34 18 18 MUX mux0 dac digiIN Synapse multiplexer select line 2 50 | 35 20 20 mux1 dac digiIN Synapse multiplexer select line 3 51 | 36 22 22 mux2 dac digiIN Synapse multiplexer select line 4 52 | 37 103 105 RING ring1 n dac IN Select array boundary conditions (closed/opened) 57 53 | 38 83 85 Soma nadap n dac IN [2.2:3.3] Spike-frequency adaptation rate 39 54 | 39 81 83 nlk n dac IN [0:0.7] Leak current on all neurons 37 55 | 40 82 84 nlkadap n dac IN [0:0.7] Spike-frequency adaptation recovery rate 38 56 | 41 85 87 nrf n dac IN [0.1:0.7] Refractory period setting (of all neurons) 41 57 | 42 84 86 nsf n dac IN [0.4:0.9] Spike emission threshold (of all neurons) 40 58 | 43 86 88 pinj p dac IN Excitatory neuron injection current 42 59 | 44 87 89 pinj1 p dac IN Inhibitory neuron injection current 43 60 | 45 88 90 pinj2 p dac IN Inhibitory neuron injection current 44 61 | 46 89 91 pinj3 p dac IN Inhibitory neuron injection current 45 62 | 46 90 92 pinj4 p dac IN Inhibitory neuron injection current 46 63 | 47 107 109 Vmem127 WIDE Membrane potential of neuron 127 64 | 48 108 110 LPF nlpfth n dac IN [2.4:3.0] Stop learning Ca integrator threshold 58 65 | 49 92 94 nlpfw n dac IN [0.1:0.7] Stop learning Ca integrator weight 47 66 | 50 93 95 plpftau p dac IN [2.7:3.3] Stop learning Ca integrator time constant 48 67 | 51 106 108 Vk WIDE Stop learning Ca integrator output 68 | 52 96 98 CMPV pcmp p dac IN [2.4:3.0] Stop learning mem comparator bias 51 69 | 53 95 97 thmem p dac IN [0.2:0.8] Stop learning mem comparator threshold 50 70 | 54 97 99 CMPI nwta n dac IN [0.2:0.6] Stop learning Ca comparator bias (jump-height) 52 71 | 55 98 100 thk1 p dac IN [2.4:3.3] Stop learning enable threshold 53 72 | 56 99 101 thk2 p dac IN [2.3:3.3] Stop learning disable LTD threshold 54 73 | 57 100 102 thk3 p dac IN [2.2:3.3] Stop learning disable LTP threshold 55 74 | 58 110 112 CCONV pbuf p dac IN [2.4:3.0] Stop learning UP current-conveyor bias 59 ScanPBias 75 | 59 101 103 nbuf n dac IN [0.1:0.7] Stop learning DN current-conveyor bias 56 76 | 60 78 80 LOCPLS(I) nplsloc n dac IN [0.1:0.7] Local excitatory synapses pulse extender bias 35 77 | 61 79 81 nplslocinh n dac IN [0.1:0.6] Local inhibitory synapses pulse extender bias 36 78 | 62 105 107 Vpls WIDE Inhibitory neuron pulse extender output 79 | 63 75 77 LOCINH nsynlocinhtau n dac IN [0.2:0.5] Local inhibitory synapses time constant 32 80 | 64 74 76 psynlocinhw p dac IN [2.4:3.3] Local inhibitory synapses weight 31 81 | 65 49 51 psynlocinhth p dac IN [2.4:3.0] Local inhibitory synapses threshold 10 82 | 66 46 48 nsynlocginh n dac IN [0.2:0.5] Local inhibitory synapses g-threshold 7 83 | 67 104 106 Vsyn WIDE Local inhibitory synapses output 84 | 68 76 78 SYNLOC nsynlocth n dac IN [2.4:3.0] Local excitatory synapses threshold 33 85 | 69 73 75 psynloctau p dac IN [2.7:3.3] Local excitatory synapses time constant 30 86 | 70 77 79 nsynlocself n dac IN [0.1:0.6] Self-excitatory synapse weight 34 87 | 71 72 74 nsynexcinh n dac IN [0.1:0.6] Excitatory synapse to inhibitory neuron weight 29 88 | 72 71 73 nsynloclat1 n dac IN [0.1:0.6] First nearest neighbor synapse weight 28 89 | 73 70 72 nsynloclat2 n dac IN [0.1:0.6] Second and third nearest neighbor synapse weight 27 90 | 74 69 71 SYNAERLEARN nsynaerpls n dac IN [0.1:0.7] AER plastic synapses pulse extender bias 26 91 | 75 68 70 nsynaerth n dac IN [2.4:3.0] AER plastic synapses threshold 25 92 | 76 67 69 psynaerlk p dac IN [2.4:3.3] Bistability comparator bias 24 93 | 77 66 68 psynaernmda p dac IN [0.2:0.5] AER plastic synapses NMDA threshold 23 94 | 78 65 67 psynaertau p dac IN [2.7:3.3] AER plastic synapses time constant 22 95 | 79 63 65 synaerhi p dac IN [0.4:1.6] Bistability comparator top power supply rail 20 96 | 80 64 66 synaerlo n dac IN [0.0:0.4] Bistability comparator bottom power supply rail 21 97 | 81 62 64 synaerth p dac IN [0.2:1.4] Bistability comparator threshold 19 98 | 82 102 104 Vw31 WIDE AER plastic synapse weight (syn 31, neur 127) 99 | 83 61 63 SYNAERSTD nsynstdth n dac IN [2.4:3.0] AER STD synapses threshold 18 100 | 84 57 59 nsynstdw0 n dac IN [0.1:0.7] AER STD synapse 0 weight 14 101 | 85 58 60 nsynstdw1 n dac IN [0.1:0.7] AER STD synapse 1 weight 15 102 | 86 56 58 nsynstdwd0 n dac IN [0.0:0.4] AER STD synapse 0 weight depression rate 13 103 | 87 59 61 nsynstdwd1 n dac IN [0.0:0.4] AER STD synapse 1 weight depression rate 16 104 | 88 60 62 psynstdtau p dac IN [2.7:3.3] AER STD synapses time constant 17 105 | 89 54 56 Vwstd WIDE AER STD synapse 0 weight output 106 | 90 46 48 SYNAERINH nsynaerginh n IN [0.2:0.5] AER inhibitory synapses g-threshold nsynlocginh 107 | 91 47 49 nsynaerinhtau n dac IN [0.2:0.5] AER inhibitory synapses time constant 8 108 | 92 49 51 psynaerinhth p IN [2.4:3.0] AER inhibitory synapses threshold psynlocinhth 109 | 93 50 52 nsynaerinhpls n dac IN [0.1:0.6] AER inhibitory synapses pulse extender bias 11 110 | 94 48 50 psynaerinhw p dac IN [2.4:3.3] AER inhibitory synapses weight 9 111 | 95 51 53 Vplsaer WIDE AER inhibitory synapses pulse extender output 112 | 96 52 54 Vsynaer WIDE AER inhibitory synapses output 113 | 97 35 37 Test Array vLPF WIDE Voltage output of new LPF 114 | 98 36 38 Tw WIDE Output of +FB amplifier 115 | 99 37 39 ~Tw WIDE Output of +FB amplifier, inv 116 | 100 38 40 TwBuf WIDE Output of +FB amplifier, buf 117 | 101 42 44 mem1 WIDE membrane 118 | 102 43 45 DN1 WIDE DN 119 | 103 44 46 UP1 WIDE UP 120 | 104 45 47 mem2 WIDE membrane 121 | 105 40 42 QyT1 digiIN Y Select test array 122 | 106 41 43 QyT2 digiIN Y Select test array 123 | 107 39 41 nLearnW n dac IN [0.1:0.7] weight for bistable synapse 6 124 | 108 53 55 Power llGnd dac BARE [0.0:0.2] Low-leakage Ground rail 12 125 | 109 94 96 llVdd dac INOR [3.0:3.3] Low-leakage Vdd rail 49 126 | 110 55 57 Gnd Corner Gnd Analog Vdd 127 | 111 91 93 Vdd Corner aVdd Analog Vdd 128 | 112 34 36 dGnd PaddGnd Digital core and Digital Pad Ground 129 | 113 2 2 dGnd PaddGnd Digital core and Digital Pad Ground 130 | 114 80 82 dVdd PaddVdd Digital core Vdd 131 | 115 23 23 dVdd PaddVdd Digital core Vdd 132 | 116 114 118 PadVdd PadVDD Digital Pad Vdd 133 | 117 33 35 PadGnd Corner PadGND Digital core and Digital Pad Ground 134 | 118 113 115 FollBias dac Corner FollBias [0.3:0.6] Wide-pad follower bias 60 135 | 136 | TOTAL PINS: 116 137 | -------------------------------------------------------------------------------- /src/pyNCS/experimentTools.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: Emre Neftci 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | # -*- coding: utf-8 -*- 10 | 11 | #For jaer monitoring 12 | import tarfile 13 | import glob 14 | import time 15 | import os 16 | import fnmatch 17 | import warnings 18 | try: 19 | import dill as pickle 20 | except ImportError: 21 | warnings.warn('Cannot import dill, falling back to pickle. Several pyNCS objects cannot be pickled') 22 | import pickle 23 | 24 | import pylab 25 | import numpy as np 26 | from shutil import rmtree 27 | 28 | ### The globals class 29 | class datacontainer: 30 | def __init__(self): 31 | self.directory = './' 32 | 33 | global globaldata 34 | globaldata = datacontainer() 35 | 36 | REC_FN_SEQ = 'seq_address_specification' 37 | REC_FN_MON = 'mon_address_specification' 38 | 39 | def get_figsize(fig_width_pt, ratio='g'): 40 | """ 41 | Method to generate figure size. 42 | """ 43 | inches_per_pt = 1.0 / 72.0 # Convert pt to inch 44 | golden_mean = (np.sqrt(5) - 1.0) / 2.0 # Aesthetic ratio 45 | fig_width = fig_width_pt * inches_per_pt # width in inches 46 | if ratio is 'g': 47 | fig_height = fig_width * golden_mean # height in inches 48 | elif ratio is 's': 49 | fig_height = fig_width # square figure 50 | else: 51 | fig_height = 1. * fig_width / ratio 52 | fig_size = [fig_width, fig_height] # exact figsize 53 | return fig_size 54 | 55 | 56 | def loadPlotParameters(size=0.5, fontsize=18.0): 57 | """ 58 | Load default matplotlib parameters for pretty plotting 59 | size: 0.5 -- two column page. 60 | 0.33 -- three column page. 61 | 0.25 -- two column double figure. 62 | fontsize: universal font size 63 | """ 64 | if size <= 0.25: 65 | border = 0.22 66 | elif size <= 0.33: 67 | border = 0.20 68 | else: 69 | border = 0.15 70 | params0 = {'backend': 'pdf', 71 | 'savefig.dpi': 300., 72 | 'axes.labelsize': fontsize, 73 | 'figure.subplot.bottom': border, 74 | 'figure.subplot.left': border, 75 | 'text.fontsize': fontsize, 76 | 'xtick.labelsize': fontsize, 77 | 'ytick.labelsize': fontsize, 78 | #'legend.pad': 0.1, # empty space around the legend box 79 | 'legend.fontsize': fontsize, 80 | 'lines.markersize': 5, 81 | 'lines.linewidth': 1, 82 | 'font.size': fontsize, 83 | 'text.usetex': True, 84 | 'figure.figsize': get_figsize(1000 * size, ratio=1.3)} # size in inches 85 | pylab.rcParams.update(params0) 86 | 87 | def load_compatibility(filename): 88 | """ 89 | Same as experimentTools.load(), but works around recent module renaming problems 90 | Code from http://wiki.python.org/moin/UsingPickle/RenamingModules 91 | """ 92 | import pickle as pickle #Does not work with dill 93 | renametable = { 94 | 'pyST': 'pyNCS.pyST', 95 | 'pyST.spikes': 'pyNCS.pyST.spikes', 96 | 'pyST.STas': 'pyNCS.pyST.STas', 97 | 'pyST.STsl': 'pyNCS.pyST.STsl', 98 | 'pyST.stgen': 'pyNCS.pyST.stgen', 99 | } 100 | 101 | def mapname(name): 102 | if name in renametable: 103 | return renametable[name] 104 | return name 105 | 106 | def mapped_load_global(self): 107 | module = mapname(self.readline()[:-1]) 108 | name = mapname(self.readline()[:-1]) 109 | klass = self.find_class(module, name) 110 | self.append(klass) 111 | 112 | def loads(filename_): 113 | fh = file(filename_,'rb') 114 | unpickler = pickle.Unpickler(fh) 115 | unpickler.dispatch[pickle.GLOBAL] = mapped_load_global 116 | return unpickler.load() 117 | 118 | return loads(filename) 119 | 120 | def load(filename=None, compatibility=False): 121 | """ 122 | Unpickles file named 'filename' from the results directory. If no 'filename' is given, then 'globaldata.pickle' is loaded 123 | """ 124 | if filename == None: 125 | filename = globaldata.directory + 'globaldata.pickle' 126 | else: 127 | filename = globaldata.directory + filename 128 | if compatibility: 129 | return load_compatibility(filename) 130 | else: 131 | return pickle.load(file(filename, 'rb')) 132 | 133 | 134 | def save_py_scripts(): 135 | """ 136 | Save all the python scripts from the current directory into the results directory 137 | """ 138 | h = tarfile.open(globaldata.directory + 'exp_scripts.tar.bz2', 'w:bz2') 139 | all_py = glob.glob('*.py') 140 | for i in all_py: 141 | h.add(i) 142 | h.close() 143 | 144 | def save_file(filename): 145 | """ 146 | Save all the python scripts from the current directory into the results directory 147 | """ 148 | import shutil 149 | shutil.copy(filename, globaldata.directory+filename) 150 | 151 | 152 | def save(obj=None, filename=None): 153 | if obj == None and filename == None: 154 | f = file(globaldata.directory + 'globaldata.pickle', 'w') 155 | pickle.dump(globaldata, f) 156 | f.close() 157 | save_py_scripts() 158 | elif obj == None and filename != None: 159 | f = file(globaldata.directory + filename, 'w') 160 | pickle.dump(globaldata, f) 161 | f.close() 162 | else: 163 | f = file(globaldata.directory + filename, 'w') 164 | pickle.dump(obj, f) 165 | f.close() 166 | return None 167 | 168 | 169 | def savetxt(obj, filename): 170 | np.savetxt(globaldata.directory + filename, obj) 171 | 172 | 173 | def mksavedir(pre='Results/', exp_dir=None): 174 | """ 175 | Creates a results directory in the subdirectory 'pre'. The directory name is given by ###__dd_mm_yy, where ### is the next unused 3 digit number 176 | """ 177 | 178 | if pre[-1] != '/': 179 | pre + '/' 180 | 181 | if not os.path.exists(pre): 182 | os.makedirs(pre) 183 | prelist = np.sort(fnmatch.filter(os.listdir(pre), '[0-9][0-9][0-9]__*')) 184 | 185 | if exp_dir == None: 186 | if len(prelist) == 0: 187 | expDirN = "001" 188 | else: 189 | expDirN = "%03d" % ( 190 | int((prelist[len(prelist) - 1].split("__"))[0]) + 1) 191 | 192 | direct = time.strftime( 193 | pre + "/" + expDirN + "__" + "%d-%m-%Y", time.localtime()) 194 | assert not os.path.exists(direct) 195 | 196 | elif isinstance(exp_dir, str): 197 | direct = pre + exp_dir 198 | if os.path.exists(direct): 199 | print("Warning: overwriting directory {0}".format(direct)) 200 | rmtree(direct) 201 | 202 | else: 203 | raise TypeError('exp_dir should be a string') 204 | 205 | os.mkdir(direct) 206 | 207 | globaldata.directory = direct + str('/') 208 | 209 | fh = file( 210 | globaldata.directory + time.strftime("%H:%M:%S", time.localtime()), 'w') 211 | fh.close() 212 | 213 | print("Created experiment directory {0}".format(globaldata.directory)) 214 | return globaldata.directory 215 | 216 | 217 | def savefig(filename, *args, **kwargs): 218 | """ 219 | Like pylab.savefig but appends the Results directory 220 | """ 221 | pylab.savefig(globaldata.directory + filename, *args, **kwargs) 222 | 223 | 224 | def annotate(filename='', text=''): 225 | "Create a file in the Results directory, with contents text" 226 | f = file(globaldata.directory + filename, 'w') 227 | f.write(text) 228 | f.close() 229 | 230 | def save_rec_files(nsetup): 231 | ''' 232 | Saves files recorded by the communicator and prepends address specification 233 | ''' 234 | fh_addr_spec_mon = file(globaldata.directory + REC_FN_SEQ, 'w') 235 | fh_addr_spec_seq = file(globaldata.directory + REC_FN_MON, 'w') 236 | seq_addr_spec_str = nsetup.seq.reprAddressSpecification() 237 | mon_addr_spec_str = nsetup.mon.reprAddressSpecification() 238 | fh_addr_spec_mon.write(mon_addr_spec_str) 239 | fh_addr_spec_seq.write(seq_addr_spec_str) 240 | fh_addr_spec_mon.close() 241 | fh_addr_spec_seq.close() 242 | exp_fns = nsetup.communicator.get_exp_rec() 243 | import shutil, os 244 | for f in exp_fns: 245 | shutil.copyfile(f, globaldata.directory+f.split('/')[-1]) 246 | 247 | def savefigs(filename='fig', extension = 'png', close=True, *args, **kwargs): 248 | """ 249 | Saves all figures with filename *filename#* where # is the figure number. 250 | The order is: last opened last saved. 251 | Inputs: 252 | *filename*: figure name prefix 253 | *extension*: figure extension. savefig should resolve the format from the extension 254 | *close*: whether to close the figure after it is saved 255 | *args, **kwargs are passed to savefig 256 | """ 257 | import matplotlib,pylab 258 | figures = [manager.canvas.figure 259 | for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()] 260 | print('Saving {0} figures'.format(len(figures))) 261 | for i, f in enumerate(figures): 262 | savefig('fig'+str(i)+'.'+extension, *args, **kwargs) 263 | if close: pylab.close() 264 | -------------------------------------------------------------------------------- /src/pyNCS/api/BrianAPI.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | #----------------------------------------------------------------------------- 3 | # File Name : testComAPI.py 4 | # Purpose: Brian Simulator API for testing pyNCS. Can only be used as one 5 | # instance because mappings are global 6 | # 7 | # Author: Emre Neftci 8 | # 9 | # Creation Date : 05-06-2013 10 | # Last Modified : Thu 26 Mar 2015 12:21:07 PM PDT 11 | # 12 | # Copyright : (c) 13 | # Licence : GPLv2 14 | #----------------------------------------------------------------------------- 15 | from pyNCS.neurosetup import get_data 16 | from pyNCS.api.ComAPI import * 17 | from pyNCS.api.ConfAPI import * 18 | import pyNCS.pyST as pyST 19 | import IFSLWTA_brian_model as ibm 20 | import numpy as np 21 | from brian.directcontrol import PoissonGroup 22 | import os 23 | 24 | #TODO: multichip mappings 25 | #TODO: generalize _decode_mappings_list 26 | 27 | chipname = 'ifslwta' 28 | channel_seq = 0 29 | channel_ifslwtain = 6 30 | global_mappings_list = [] 31 | global_neurosetup = None 32 | global_sympy_params = None 33 | 34 | synapse_trans_dict = {0 : ['Ii', 'w_syn_I'], 35 | 1 : ['Ii', 'w_syn_I'], 36 | 2 : ['Ia', 'w_syn_E1'], 37 | 3 : ['Ia', 'w_syn_E2']} 38 | 39 | def _decode_mappings_list(mappings_list, synapse_id): 40 | ml = np.array(mappings_list) 41 | fr = decode_addr(ml[:,0])[channel_seq] #0 for field 0 42 | to = decode_addr(ml[:,1])[channel_ifslwtain] 43 | to_syn = to[0,to[1,:]==synapse_id] 44 | fr_syn = fr[0,to[1,:]==synapse_id] 45 | if len(to_syn)==0: 46 | return [] 47 | else: 48 | if np.shape(ml)[1]==3: 49 | prob = ml[:,2].astype('float')/128 50 | prob_syn = prob[to[1,:]==synapse_id] 51 | else: 52 | prob = np.ones(ml.shape[0]) 53 | return zip(fr_syn,to_syn,prob_syn) 54 | 55 | def _dlist_to_mappingdict(mapping): 56 | from collections import defaultdict 57 | #sort list 58 | if len(mapping)>0: 59 | mapping_dict = defaultdict(list) 60 | mapping_dict_probs = defaultdict(list) 61 | def func(srctgt): 62 | mapping_dict[srctgt[0]].append(srctgt[1]) 63 | mapping_dict_probs[srctgt[0]].append(srctgt[2]) 64 | map(func, mapping) 65 | return mapping_dict, mapping_dict_probs 66 | else: 67 | return {},{} 68 | 69 | def _mappingdict_to_matrix(mapping_dict, mapping_dict_probs): 70 | N_fr = len(mapping_dict) 71 | N_to = max(max(mapping_dict.values()))+1 72 | M = np.zeros([N_fr, N_to]) 73 | P = np.zeros([N_fr, N_to]) 74 | for k in mapping_dict.keys(): 75 | M[k,mapping_dict[k]] = 1 76 | P[k,mapping_dict[k]] = mapping_dict_probs[k] 77 | return M, P 78 | 79 | def translate_mappings(mapping_list, synapse_id): 80 | m = _decode_mappings_list(mapping_list, synapse_id) 81 | if m ==None: 82 | return None 83 | else: 84 | return _mappingdict_to_matrix(*_dlist_to_mappingdict(m)) 85 | 86 | def decode_addr(addr): 87 | #decode physical addresses to neuron - synapse 88 | global global_neurosetup 89 | return global_neurosetup.seq.addrPhysicalExtract(addr) 90 | 91 | class Communicator(BatchCommunicatorBase): 92 | def run(self, stimulus=None, duration=None, context_manager=None): 93 | stimulus_abs = pyST.events(stimulus, atype='p', isISI=True) 94 | stimulus_abs.set_abs_tm() 95 | self.evn_sin = evs_in = stimulus_abs.get_adtmev().astype('float') 96 | evs_in[:,1]*=1e-6 #brian takes seconds 97 | if duration == None and len(stimulus_abs)>0: 98 | duration = np.max(evs_in[:,1]) 99 | print(duration) 100 | elif duration == None: 101 | duration = 1. 102 | else: 103 | duration = float(duration)/1e3 104 | net, M_EIP, MV_EIP = self._prepare_brian_net(evs_in) 105 | self.outs = [net, M_EIP, MV_EIP] 106 | net.reinit(states=False) 107 | print('running virtual IFLSWTA for {0}s'.format(duration)) 108 | net.run(duration) 109 | sp = np.array(M_EIP.spikes).reshape(-1,2) 110 | sp[:,0]+=(2**16) #slot 2 in text.xml. THIS IS A POSSIBLE SOURCE OF TEST ERROR 111 | sp[:,1]*=1e6 112 | return sp 113 | 114 | 115 | def _prepare_brian_net(self, stimulus): 116 | from brian.directcontrol import SpikeGeneratorGroup 117 | from brian.synapses.synapses import Synapses 118 | from brian.network import Network 119 | self.S = [] 120 | netobjs, M_EIP, MV_EIP = ibm.create_netobjs(stimulus, global_sympy_params.cur) 121 | 122 | if len(stimulus)>0: 123 | N = max(stimulus[:,0])+1 124 | In1=SpikeGeneratorGroup(N,stimulus[stimulus[:,0] 0: 128 | gml = np.array(global_mappings_list).reshape(-1,3) 129 | for syn_idx in range(4): 130 | 131 | gml_dict, pgml_dict = _dlist_to_mappingdict(_decode_mappings_list(gml,syn_idx)) 132 | if len(gml_dict)>0: 133 | if len(stimulus)==0: 134 | input_pop = PoissonGroup(max(gml_dict.keys())+1, 0) 135 | else: 136 | input_pop = In1 137 | iname, wname = synapse_trans_dict[syn_idx] 138 | EIP = netobjs['EIP'] 139 | S=Synapses(input_pop,EIP,model="""w : 1 140 | p : 1""", 141 | pre=iname+"+=w*(rand() element 199 | ''' 200 | if isinstance(param, dict): 201 | self.parameters[param['SignalName']] = 0 202 | elif isinstance(param, etree._Element): 203 | self.parameters[param.SignalName] = 0 204 | 205 | def reset(self): 206 | #IMPLEMENT 207 | ''' 208 | Resets all the parameters to default values 209 | ''' 210 | return None 211 | 212 | def __parseNHML__(self, doc): 213 | ''' 214 | Parse xml file or element tree to generate the object 215 | ''' 216 | super(Configurator,self).__parseNHML__(doc) 217 | global global_sympy_params 218 | from paramTranslation import params 219 | filename = get_data('chipfiles/ifslwta_paramtrans.xml') 220 | global_sympy_params = self.sympy_params = params(self, filename) 221 | 222 | def _readCSV(self, CSVfile): 223 | super(Configurator,self)._readCSV(CSVfile) 224 | global global_sympy_params 225 | from paramTranslation import params 226 | filename = get_data('chipfiles/ifslwta_paramtrans.xml') 227 | global_sympy_params = self.sympy_params = params(self, filename) 228 | 229 | class Mappings(MappingsBase): 230 | def add_mappings(self, mappings): 231 | #IMPLEMENT (REQUIRED) 232 | ''' 233 | Adds *mappings* to the mappings table. 234 | 235 | Inputs: 236 | *mappings*: a two-dimenstional iterable 237 | ''' 238 | global global_mappings_list 239 | global_mappings_list += mappings 240 | 241 | def get_mappings(self): 242 | #IMPLEMENT (REQUIRED) 243 | ''' 244 | Returns an array representing the mappings 245 | ''' 246 | global global_mappings_list 247 | return global_mappings_list 248 | 249 | def clear_mappings(self): 250 | #IMPLEMENT (REQUIRED) 251 | ''' 252 | Clears the mapping table. No inputs 253 | ''' 254 | global global_mappings_list 255 | while True: 256 | try: 257 | global_mappings_list.pop() 258 | except IndexError: 259 | break 260 | 261 | return None 262 | 263 | -------------------------------------------------------------------------------- /src/pyNCS/pyST/STsl.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: Emre Neftci 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | from __future__ import absolute_import 10 | import os 11 | import numpy as np 12 | import pylab 13 | import matplotlib 14 | from . import pyST_globals 15 | from . import stgen 16 | from .spikes import SpikeList, SpikeTrain, load, merge, merge_spikelists 17 | 18 | #Globals 19 | addrIndex = 0 20 | timeIndex = 1 21 | STCreate = stgen.StGen() 22 | 23 | 24 | def plot_raster(SL, id_list=None, t_start=None, t_stop=None, display=True, id_color=None, kwargs={}): 25 | ''' Same as spikelist.raster_plot() but with pretty plot options 26 | 27 | id_color is used to customize colors according to neuron address (for example inhibitory vs. excitatory) 28 | 29 | Example: 30 | >>> id_color = [{'ids':range(124),'color':'blue'},{'ids':range(124,128),'color':'red'}] 31 | >>> plot_raster(chipout[158],id_color=id_color) 32 | ''' 33 | #SL._SpikeList__calc_startstop() 34 | kwargs_default = {'marker': '|', 'markersize': 2, 'color': 'black'} 35 | kwargs_default.update(kwargs) 36 | 37 | if id_color == None: 38 | SL.raster_plot(id_list, t_start, t_stop, display, kwargs) 39 | else: 40 | h = pylab.axes() 41 | for i in range(len(id_color)): 42 | kwargs['color'] = id_color[i]['color'] 43 | SL.id_slice(id_color[i]['ids']).raster_plot( 44 | t_start=t_start, t_stop=t_stop, display=h, kwargs=kwargs) 45 | pylab.ylim([SL.id_list().min() - 1, SL.id_list().max() + 1]) 46 | 47 | 48 | STPlotRaster = plot_raster 49 | 50 | 51 | def composite_plot_superimposed(st_pre, st_post, kwargs={}, colors=['blue', 'k'], id_list=None, t_start=None, t_stop=None, t_start_rate=None, t_stop_rate=None, pre_rate_mult=1.): 52 | """ 53 | Make a nice Composite plot superimposing two spike trains, a raster plot combined with a vertical rate plot. 54 | *st_pre* and *st_post* are two SpikeLists. st_post will be plotted above st_pre 55 | *colors* is a list specifying the respective colors for the bars and spikes for st_pre and st_post 56 | *kwargs* are the keyword arguments for common plot arguments in the raster plots. Default is {'alpha':0.7,'marker':','} for st_pre and plot_raster defaults for st_post 57 | *pre_rate_mult* is a float used for plotting the rates of st_pre on a different scale 58 | other arguments are the same as in composite_plot 59 | """ 60 | kwargs_pre = dict() 61 | kwargs_pre.update({'alpha': 0.8, 'marker': ',', 'color': colors[0]}) 62 | kwargs_pre.update(kwargs) 63 | kwargs_post = dict() 64 | kwargs_post.update(kwargs) 65 | kwargs_post.update({'color': colors[1]}) 66 | 67 | h1, h2 = composite_plot( 68 | st_pre, 69 | kwargs=kwargs_pre, 70 | kwargs_bar={'alpha': 0.8, 'color': colors[0]}, 71 | id_list=id_list, 72 | t_start=t_start, 73 | t_stop=t_stop, 74 | t_start_rate=t_start_rate, 75 | t_stop_rate=t_stop_rate, 76 | ) 77 | 78 | twin = False 79 | if pre_rate_mult != 1.: 80 | h2t = h2.twiny() 81 | twin = True 82 | else: 83 | h2t = h2 84 | 85 | super_plot = composite_plot( 86 | st_post, 87 | kwargs=kwargs_post, 88 | kwargs_bar={'color': colors[1]}, 89 | display=[h1, h2t], 90 | id_list=id_list, 91 | t_start=t_start, 92 | t_stop=t_stop, 93 | t_start_rate=t_start_rate, 94 | t_stop_rate=t_stop_rate) 95 | 96 | if twin: 97 | pre_lims = h2.get_xlim() 98 | #h2.set_xlim(pre_lims[0],pre_lims[1]*pre_rate_mult) 99 | color = colors[0] 100 | for tl in h2.get_xticklabels(): 101 | tl.set_color(color) 102 | h2.set_xlabel('Frequency (Hz)', color=color) 103 | 104 | return super_plot 105 | 106 | 107 | def composite_plot(SL, id_list=None, t_start=None, t_stop=None, t_start_rate=None, t_stop_rate=None, display=True, kwargs={}, kwargs_bar={}): 108 | """ 109 | Make a nice Composite plot, *i.e.* a raster plot combined with a vertical rate plot. 110 | 111 | The arguments are identical to STPlotRaster, except for display. 112 | *display* If True is given a new figure is created. If [axS,axR] is given, where axS and axR are pylab.axes objects, then the spike rater and the rate plot are plotted there. 113 | """ 114 | SL._SpikeList__calc_startstop() 115 | 116 | if id_list == None: 117 | id_list = SL.id_list() 118 | if t_start is None: 119 | t_start = SL.t_start 120 | if t_stop is None: 121 | t_stop = SL.t_stop 122 | if t_start_rate is None: 123 | t_start_rate = t_start 124 | if t_stop_rate is None: 125 | t_stop_rate = t_stop 126 | 127 | if display == True: 128 | h = pylab.figure() 129 | axS = pylab.axes([0.12, 0.12, 0.57, 0.8]) 130 | axR = pylab.axes([0.75, 0.12, 0.20, 0.8]) 131 | elif isinstance(display, list): 132 | axS = display[0] 133 | axR = display[1] 134 | 135 | STPlotRaster(SL=SL, id_list=id_list, t_start=t_start, t_stop=t_stop, 136 | display=axS, kwargs=kwargs) 137 | 138 | min_addr = int(np.min(SL.id_list())) 139 | max_addr = int(np.max(SL.id_list())) 140 | axS.set_xlim([t_start, t_stop]) 141 | axS.set_yticks([min_addr, (max_addr - min_addr) / 2, max_addr]) 142 | axS.set_xticks( 143 | [int(t_start), 100 * (int(t_stop - t_start) / 200), int(t_stop)]) 144 | 145 | rates = np.array(SL.mean_rates(t_start=t_start_rate, t_stop=t_stop_rate)) 146 | barplot = axR.barh(id_list, rates, linewidth=0, **kwargs_bar) 147 | #remove space between bars, remove black lines 148 | pre_lims = axS.set_ylim() 149 | axR.set_ylim(pre_lims[0], pre_lims[1]) 150 | 151 | axR.set_yticks([]) 152 | axR.grid('on') 153 | #axS.xaxis.grid('on') 154 | 155 | axR.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(2)) 156 | pylab.axes(axR) 157 | axR.set_xlabel('Frequency (Hz)') 158 | 159 | return axS, axR 160 | 161 | STCompositePlot = composite_plot 162 | 163 | 164 | def composite_plot_movie(SL, time_bin=10, t_start=None, t_stop=None, output="animation.mpg", bounds=(0, 5), fps=10, display=True, maxrate=None, ratebin=None, kwargs={}): 165 | pylab.ioff() 166 | from NeuroTools.plotting import get_display 167 | subplot = get_display(display) 168 | assert os.system('mencoder') != 32512, "mencoder not found!" 169 | if t_start is None: 170 | t_start = SL.t_start 171 | if t_stop is None: 172 | t_stop = SL.t_stop 173 | if maxrate is None: 174 | maxrate = 100 175 | if ratebin is None: 176 | ratebin = 100 177 | 178 | files = [] 179 | im = pylab.figure(**kwargs) 180 | count = 0 181 | idx = 0 182 | axS, axR = STCompositePlot(SL, t_start=0, t_stop=time_bin, 183 | t_start_rate=0, t_stop_rate=ratebin, kwargs=kwargs) 184 | axR.hold(False) 185 | axS.hold(False) 186 | if t_start != SL.t_start or t_stop != SL.t_stop: 187 | spk = SL.time_slice(t_start, t_stop) 188 | raise RuntimeError('Not implemented') 189 | 190 | while (t_start < t_stop): 191 | STCompositePlot(SL, t_start=0, t_stop=t_start + time_bin, t_start_rate=t_start, 192 | t_stop_rate=t_start + ratebin, display=[axS, axR], kwargs=kwargs) 193 | axS.set_xlim([0, t_stop]) 194 | axR.set_xlim([0, maxrate]) 195 | fname = "_tmp_spikes_%05d.png" % count 196 | pylab.savefig(fname) 197 | files.append(fname) 198 | t_start += time_bin 199 | count += 1 200 | print('Generated frame {0}'.format(count)) 201 | command = "mencoder 'mf://_tmp_*.png' -mf type=png:fps=%d -ovc lavc -lavcopts vcodec=wmv2 -oac copy -o %s" % (fps, output) 202 | os.system(command) 203 | for fname in files: 204 | os.remove(fname) 205 | 206 | 207 | def mapSpikeListAddresses(SL, mapping=None): 208 | ''' 209 | this function maps the addresses of a spike list into another using the given mapping. Useful for logical to physical translation and vice versa 210 | SL=original spike list 211 | mapping=dictionary containing address mapping, If mapping is None, then the addresses will be mapped onto a linear scale, i.e. range(len(SL.id_list())) 212 | ''' 213 | assert isinstance(SL, SpikeList), "SL must be a NeuroTools SpikeList" 214 | mapped_SL = SpikeList([], []) 215 | addr_SL = SL.id_list() 216 | if mapping == None: 217 | mapping = dict(zip(np.sort(SL.id_list()), range(len(SL.id_list())))) 218 | for k, v in mapping.iteritems(): 219 | if k in addr_SL: 220 | try: 221 | mapped_SL[v] = SL[k] 222 | except KeyError: 223 | pass 224 | 225 | all_others = np.setdiff1d(SL.id_list(), mapping.keys()) 226 | for k in all_others: 227 | mapped_SL[k] = SL[k] 228 | 229 | return mapped_SL 230 | 231 | 232 | def ksi(SL, t_stop=800, pow_freq=None, t_bin=10.): 233 | """ 234 | Kuramoto Synchronization Index (KSI) (Kuaramoto 1984) for measuring phase coherency with respect to the strongest freqeuncy of the population activity. 235 | 236 | Returns ksi in the range (0,1). 0 meaning no cohrency and 1 meaning entirely coherent 237 | 238 | Inputs: 239 | SL - SpikeList of duration of at least t_stop 240 | t_stop - the end of the SpikeTrain (in ms) 241 | t_bin - time bin for computing population activity and spectrum 242 | pow_freq- if given, this frequency is taken as the strongest frequency 243 | 244 | """ 245 | #Determine the strongest frequency 246 | N = len(SL) 247 | 248 | if pow_freq == None: 249 | psth = SL.time_slice( 250 | t_start=0, t_stop=t_stop).spike_histogram(t_bin).mean(axis=0) 251 | t = np.arange(0, t_stop * 1e-3, t_bin * 1e-3) 252 | sp = abs(np.fft.fft(psth).real) 253 | freq = abs(np.fft.fftfreq(t.shape[-1], d=t_bin * 1e-3)) 254 | pow_freq = freq[1 + np.argmax(sp.real[1:])] 255 | 256 | l_vs = [[] for i in range(len(SL))] 257 | 258 | for i, k in enumerate(SL.id_list()): 259 | tm = SL[k].spike_times / 1000 # In seconds 260 | l_vs[i] = (tm + .5 / pow_freq) % (1. / pow_freq) - .5 / pow_freq 261 | 262 | vs = np.hstack(l_vs) * pow_freq * 2 * np.pi # Flatten 263 | 264 | return abs(np.sum(np.exp(1j * vs)) / len(vs)), pow_freq 265 | -------------------------------------------------------------------------------- /test/pyNCS_unittest.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: Test pyNCS functions. Currently using pyAex module, but this should change in the future. 3 | # 4 | # Author: Emre Neftci 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | #import pyAex 10 | import pyNCS 11 | import pyNCS.pyST as pyST 12 | import numpy as np 13 | import unittest, warnings, optparse, os, time, sys 14 | 15 | 16 | 17 | def create_default_population(setup,chipname='seq',N=10,*args,**kwargs): 18 | ''' 19 | Creates a default population 20 | ''' 21 | test_pops = pyNCS.Population('default', 'Default Population') 22 | test_pops.populate_by_number(setup, chipname, 'excitatory', N, *args, **kwargs) 23 | return test_pops 24 | 25 | def evs_loopback(nsetup, sequencer): 26 | ''' 27 | This function takes a sequencer object (e.g. returned by 28 | Group.spiketrains_poisson() ) and creates a RawOutput object out of it. This 29 | is usefull for generating synthetic data and treating is as neuromorphic 30 | system ouput. 31 | ''' 32 | evs = nsetup.mon.exportAER(sequencer, isi=False) 33 | ch_evs = nsetup.mon.extract(evs) 34 | return nsetup.mon.rawoutput_from_chevents(ch_evs) 35 | 36 | 37 | class TestSequenceFunctions(unittest.TestCase): 38 | 39 | def setUp(self): 40 | import expSetup 41 | self.nsetup = expSetup.build_setup() 42 | 43 | def testBuildLinearPopulation(self): 44 | N=10 45 | #for transition populations + state populations (for inital and test) 46 | test_pops=create_default_population(self.nsetup,'seq',N) 47 | addrs=self.nsetup.mon[test_pops.soma.channel].addrLogicalConstruct([range(N)]) 48 | for i,a in enumerate(test_pops.soma.laddr): 49 | self.assert_(a in addrs) 50 | 51 | def testMonitors(self): 52 | N=3 53 | s=create_default_population(self.nsetup,'seq',N) 54 | t=create_default_population(self.nsetup, 'ifslwta', N) 55 | c=pyNCS.PConnection(s,t,'excitatory0') 56 | 57 | stmon1=pyNCS.monitors.SpikeMonitor(t.soma) 58 | self.nsetup.monitors.import_monitors([stmon1]) 59 | input_stim=s.soma.spiketrains_poisson(rate = np.linspace(10,100,N), duration=500) 60 | self.nsetup.prepare() 61 | self.nsetup.chips['ifslwta'].set_parameter('nsynstdw0',.6) 62 | out = self.nsetup.run(input_stim) 63 | r= stmon1.sl.mean_rates() 64 | self.assertTrue(np.all(r>0)) 65 | 66 | def testSequencers(self): 67 | N=3 68 | s=create_default_population(self.nsetup,'seq',N) 69 | t=create_default_population(self.nsetup,'ifslwta', N) 70 | c=pyNCS.PConnection(s,t,'excitatory0') 71 | 72 | sequencer = pyNCS.monitors.Monitors() 73 | mon_in, = sequencer.create(s) 74 | mon_in.create_spiketrains('poisson', rate = np.linspace(100,2000,N), duration = 1000) 75 | 76 | stmon1=pyNCS.monitors.SpikeMonitor(t.soma) 77 | self.nsetup.monitors.import_monitors([stmon1]) 78 | 79 | self.nsetup.prepare() 80 | self.nsetup.chips['ifslwta'].set_parameter('nsynstdw0',.7) 81 | 82 | out = self.nsetup.run(sequencer) 83 | r= stmon1.sl.mean_rates() 84 | self.assertTrue(np.all(r > 0)) 85 | 86 | def testSequencers_nsetup(self): 87 | N=3 88 | s=create_default_population(self.nsetup,'seq',N) 89 | t=create_default_population(self.nsetup,'ifslwta', N) 90 | c=pyNCS.PConnection(s,t,'excitatory0') 91 | 92 | sequencers = self.nsetup.sequencers 93 | mon_in, = sequencers.create(s) 94 | mon_in.create_spiketrains('poisson', rate = np.linspace(100,2000,N), duration = 1000) 95 | 96 | stmon1=pyNCS.monitors.SpikeMonitor(t.soma) 97 | self.nsetup.monitors.import_monitors([stmon1]) 98 | 99 | self.nsetup.prepare() 100 | self.nsetup.chips['ifslwta'].set_parameter('nsynstdw0',.7) 101 | 102 | out = self.nsetup.run() 103 | r= stmon1.sl.mean_rates() 104 | self.assertTrue(np.all(r > 0)) 105 | 106 | def testMonitors_from_SpikeList(self): 107 | from pyNCS import monitors 108 | from pylab import close 109 | N=10 110 | test_pops=create_default_population(self.nsetup,'seq',N) 111 | st = test_pops.soma.spiketrains_poisson(10)[0] 112 | mon = monitors.create_SpikeMonitor_from_SpikeList(st) 113 | monitors.MeanRatePlot(mon) 114 | close('all') 115 | 116 | def testPMapping(self): 117 | N=30 118 | p=0.5 119 | #pyAex.MAPVERS=3 120 | s=create_default_population(self.nsetup, 'seq', N) 121 | t=create_default_population(self.nsetup, 'ifslwta', N) 122 | t2=create_default_population(self.nsetup, 'ifslwta', 124-N, offset=N) 123 | mon = self.nsetup.monitors.import_monitors_otf(t)[0] 124 | mon_zero = self.nsetup.monitors.import_monitors_otf(t2)[0] 125 | m=pyNCS.PMapping('') 126 | m.connect(s.soma,t.synapses['excitatory0'], fashion='random_all2all', fashion_kwargs={'p':p}) 127 | m.connect(s.soma,t.synapses['excitatory0'], fashion='one2one',fashion_kwargs={'p':p}, expand = True) 128 | P = int(p*127) 129 | for i in s.soma.paddr: 130 | for j in t.synapses['excitatory0'].paddr: 131 | self.assert_([i, j, P] in m.mapping) 132 | for n in range(len(s.soma.paddr)): 133 | self.assert_([s.soma.paddr[n], t.synapses['excitatory0'].paddr[n], P] in m.mapping) 134 | self.nsetup.mapping.merge(m) 135 | self.nsetup.prepare() 136 | self.nsetup.chips['ifslwta'].set_parameter('nsynstdw0',.5) 137 | input_stim=s.soma.spiketrains_poisson(400) 138 | out = self.nsetup.run(input_stim) 139 | self.assertTrue(np.all(350>mon.sl.mean_rates()) and np.all(mon.sl.mean_rates()>100)) 140 | self.assertTrue(np.all(mon_zero.sl.mean_rates()<2)) 141 | 142 | def testPConnection(self): 143 | N=30 144 | p=0.5 145 | #pyAex.MAPVERS=3 146 | s=create_default_population(self.nsetup, 'seq', N) 147 | t=create_default_population(self.nsetup, 'ifslwta', N) 148 | t2=create_default_population(self.nsetup, 'ifslwta', 124-N, offset=N) 149 | mon = self.nsetup.monitors.import_monitors_otf(t)[0] 150 | mon_zero = self.nsetup.monitors.import_monitors_otf(t2)[0] 151 | c=pyNCS.PConnection(s,t,'excitatory0','random_all2all',{'p':p}) 152 | m=c.mapping 153 | P = int(p*127) 154 | for i in s.soma.paddr: 155 | for j in t.synapses['excitatory0'].paddr: 156 | self.assert_([i, j, P] in m.mapping) 157 | for n in range(len(s.soma.paddr)): 158 | self.assert_([s.soma.paddr[n], t.synapses['excitatory0'].paddr[n], P] in m.mapping) 159 | 160 | self.nsetup.prepare() 161 | input_stim=s.soma.spiketrains_poisson(400) 162 | self.nsetup.chips['ifslwta'].set_parameter('nsynstdw0',.5) 163 | out = self.nsetup.run(input_stim) 164 | self.assertTrue(np.all(350>mon.sl.mean_rates()) and np.all(mon.sl.mean_rates()>100)) 165 | self.assertTrue(np.all(mon_zero.sl.mean_rates()<2)) 166 | 167 | def testPMappingLarge(self): 168 | N=124 169 | p=0.5 170 | #pyAex.MAPVERS=3 171 | s=create_default_population(self.nsetup, 'seq', N) 172 | t=create_default_population(self.nsetup, 'ifslwta', N) 173 | m=pyNCS.PMapping('') 174 | M = np.random.randint(0,2,size=(len(s.soma),2)) 175 | m.mapping.extend(np.random.randint(0,50000,size=(500000,2))) 176 | for j in xrange(len(s)): 177 | print j 178 | m.connect(s.soma[j], t.synapses['inhibitory'][(j*2):((j+1)*2)], fashion = 'by_boolean_matrix', fashion_kwargs={'connection': M[[j],:]}) 179 | 180 | 181 | def testSeqPopulationFunctions(self): 182 | N=5 183 | test_pops1=create_default_population(self.nsetup,'seq',N) 184 | test_pops2=create_default_population(self.nsetup,'seq',2*N,offset=N) 185 | pop=pyNCS.Population() 186 | pop.init(self.nsetup, 'seq', 'excitatory') 187 | pop.union(test_pops1) 188 | pop.union(test_pops2) 189 | testaddr = np.concatenate([test_pops1.soma.paddr,test_pops2.soma.paddr]) 190 | for a in testaddr: 191 | self.assertTrue(a in pop.soma.paddr) 192 | 193 | def testIFSLWTAPopulationFunctions(self): 194 | N=5 195 | test_pops1=create_default_population(self.nsetup,'ifslwta',N) 196 | test_pops2=create_default_population(self.nsetup,'ifslwta',2*N,offset=N) 197 | pop=pyNCS.Population() 198 | pop.init(self.nsetup, 'ifslwta', 'excitatory') 199 | pop.union(test_pops1) 200 | pop.union(test_pops2) 201 | testaddr = np.concatenate([test_pops1.soma.paddr,test_pops2.soma.paddr]) 202 | for a in testaddr: 203 | self.assertTrue(a in pop.soma.paddr) 204 | 205 | def testComAPI_RecordableCommunicatorBase(self): 206 | import pyNCS.api.ComAPI, os 207 | rec_com = pyNCS.ComAPI.RecordableCommunicatorBase() 208 | rec_com.run_rec(np.ones([0,2])) 209 | self.assertTrue(len(rec_com._rec_fns)==2) 210 | self.assertTrue(os.path.exists(rec_com._rec_fns[0])) 211 | self.assertTrue(os.path.exists(rec_com._rec_fns[1])) 212 | fns = rec_com.get_exp_rec() 213 | self.assertTrue(len(rec_com._rec_fns)==0) 214 | 215 | def testExperimentTools(self): 216 | import pyNCS.experimentTools as et 217 | test_pops=create_default_population(self.nsetup,'seq', 5) 218 | input_stim=test_pops.soma.spiketrains_poisson(100) 219 | self.nsetup.run(input_stim) 220 | et.mksavedir(pre='/tmp/test_et/') 221 | et.save_rec_files(self.nsetup) 222 | 223 | def testMonitorsEmptyPlot(self): 224 | #github inincs/pyNCS issue#3 225 | test_pops1=create_default_population(self.nsetup,'seq', N=5) 226 | test_pops2=create_default_population(self.nsetup,'seq', N=5, offset=5) 227 | stmon1=pyNCS.monitors.SpikeMonitor(test_pops1.soma) 228 | stmon2=pyNCS.monitors.SpikeMonitor(test_pops2.soma) 229 | self.nsetup.monitors.import_monitors([stmon1,stmon2]) 230 | mon = test_pops1.soma.spiketrains_poisson(rate = 50) 231 | #Monitor loopback 232 | rawoutput = evs_loopback(self.nsetup, mon) 233 | self.nsetup.monitors.populate_monitors(rawoutput) 234 | pyNCS.monitors.RasterPlot(self.nsetup.monitors.monitors) 235 | #import pylab 236 | #pylab.show() 237 | 238 | def testEmptyMonitorReturnsCorrectDimensions(self): 239 | test_pops1=create_default_population(self.nsetup,'seq', N=5) 240 | stmon1=pyNCS.monitors.SpikeMonitor(test_pops1.soma) 241 | stmon1.populate(pyNCS.pyST.SpikeList()) 242 | self.assertTrue(len(stmon1.sl.mean_rates())==5) 243 | 244 | 245 | 246 | 247 | 248 | def tearDown(self): 249 | del self.nsetup 250 | 251 | 252 | if __name__ == '__main__': 253 | unittest.main() 254 | 255 | 256 | #to debug 257 | #suite.debug() 258 | #or 259 | #TestSequenceFunctions('testStimulation').debug() 260 | 261 | 262 | -------------------------------------------------------------------------------- /src/pyNCS/api/ConfAPI.py: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Purpose: 3 | # 4 | # Author: 5 | # 6 | # Copyright : University of Zurich, Giacomo Indiveri, Emre Neftci, Sadique Sheik, Fabio Stefanini 7 | # Licence : GPLv2 8 | #----------------------------------------------------------------------------- 9 | #ConfAPI 10 | #Biases and mapper 11 | #Api for modules having pyAMDA-like functionality 12 | #Api for modules having pyAEX-like functionality 13 | 14 | from __future__ import absolute_import 15 | from .BaseConfAPI import * 16 | from .ComAPI import ResourceManagerBase 17 | 18 | class ConfiguratorBase(ResourceManagerBase): 19 | def __init__(self): 20 | ''' 21 | ConfiguratorBase() 22 | Base class for managing parameters 23 | Contains functions 24 | - set_parameter (required) 25 | - get_parameter (required) 26 | - add_parameter (required) 27 | - get_parameter_names (required) 28 | - reset (optional) 29 | - set_parameters (optional) 30 | - get_parameters (optional) 31 | - context_get_param (optional) 32 | 33 | Parameters should be stored in the _parameter dictionary. 34 | The dictionary's keys should be the parameter names. 35 | Inherits ResourceManagerBase 36 | ''' 37 | self.parameters = {} 38 | ResourceManagerBase.__init__(self) 39 | 40 | def _readCSV(self, CSVfile): 41 | ''' 42 | Parse the CSV file to build the configurator object. 43 | NOTE: Downward compatibility function 44 | ''' 45 | with open(CSVfile, 'r') as CSV: 46 | csv = CSV.readlines() 47 | 48 | #The following builds bias representations only 49 | tableFlag = False 50 | for line in csv: 51 | line = line.replace('\'', '') # remove single and double quotes 52 | line = line.replace('"', '') 53 | if line.startswith('\t') or line.startswith('\n'): 54 | tableFlag = False 55 | elif 'signal' in line.lower() and not tableFlag: 56 | # TODO: This code assumes that signal is an essential part of 57 | # table 58 | # WARNING: There should be some intelligent way to do this! 59 | tableFlag = True 60 | tableFields = line.strip().split('\t') 61 | elif tableFlag and line.strip(): 62 | row = line.strip().split('\t') 63 | # WARNING: This only works if the word bias exists as a field 64 | if row[tableFields.index('BiasType')]: 65 | parameters = {} 66 | for i in range(len(row)): 67 | val = row[i] 68 | # Check if the string is a number 69 | try: 70 | val = float(val) 71 | except: 72 | pass 73 | parameters[tableFields[i]] = val 74 | self.add_parameter(parameters) 75 | return 76 | 77 | def __getNHML__(self): 78 | doc = etree.Element('parameters') 79 | for p in self.parameters.values(): 80 | doc.append(p.__getNHML__()) 81 | return doc 82 | 83 | def __parseNHML__(self, doc): 84 | ''' 85 | Parse xml file or element tree to generate the object 86 | ''' 87 | if isinstance(doc, str): 88 | # parse the file 89 | doc = etree.parse(doc).getroot() 90 | if not doc.tag == 'parameters': 91 | doc = doc.find('parameters') 92 | else: 93 | # assuming doc is an lxml Element object. 94 | assert doc.tag == 'parameters' 95 | 96 | for param in doc: 97 | self.add_parameter(param) 98 | 99 | def add_parameter(self, param): 100 | #CONVENIENCE FUNCITON. IMPLEMENTATION NOT REQUIRED 101 | ''' 102 | Add a parameter to the configurator 103 | param: dictionary with all attributes of parameter or an xml element or 104 | file name with the element 105 | ''' 106 | if isinstance(param, dict): 107 | self.parameters[param['SignalName']] = Parameter(param, self) 108 | elif isinstance(param, etree._Element): 109 | parameter = Parameter({'SignalName': ''}, self) 110 | parameter.__parseNHML__(param) 111 | self.parameters[parameter.SignalName] = parameter 112 | 113 | def get_parameter(self, param_name): 114 | #IMPLEMENT 115 | ''' 116 | Gets parameter param_name. 117 | ''' 118 | return self.parameters[param_name] 119 | 120 | def get_parameters(self, param_names=None): 121 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 122 | ''' 123 | Returns parameters (dictionary of name-value pairs). 124 | Input: 125 | *param_names:* A list of parameter names 126 | If param_names is None, then this function returns all the parameters 127 | (using self.get_param_names()) 128 | ''' 129 | if param_names is None: 130 | param_names = self.get_param_names() 131 | 132 | if not isinstance(param_names, (list, tuple, GeneratorType)): 133 | raise TypeError('param_names should be a list, tuple or generator, not {0}'. 134 | format(type(param_names))) 135 | 136 | b = dict() 137 | for i, name in enumerate(param_names): 138 | b[name] = self.get_parameter(name) 139 | return b 140 | 141 | def set_parameter(self, param_name, param_value): 142 | #IMPLEMENT 143 | ''' 144 | Sets parameter param_name with param_value 145 | ''' 146 | self.parameters[param_name] = param_value 147 | return None 148 | 149 | def set_parameters(self, param_dict): 150 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 151 | ''' 152 | Set several parameters using a dictionary. 153 | Input: 154 | *param_dict*: dictionary of parameter names (str) - value (float) pairs. 155 | ''' 156 | for name, value in param_dict.iteritems(): 157 | self.set_parameter(name, value) 158 | self.get_parameters(param_dict.keys()) 159 | return None 160 | 161 | def update_parameter(self, param_name, param_value): 162 | #CONVENIENCE FUNCTION. IMPLEMENTATION NOT REQUIRED 163 | ''' 164 | Update/Inform the object of changes made from other clients. 165 | Input: 166 | *param_name*: Parameter name 167 | *param_value*: Parameter value 168 | Ideal to use when the parameters can be changed from multiple clients 169 | simultaneously. 170 | ''' 171 | self.parameters[param_name].v = param_value 172 | return 173 | 174 | def get_param_names(self): 175 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 176 | ''' 177 | Returns names of all the parameters 178 | ''' 179 | return self.parameters.keys() 180 | 181 | def save_parameters(self, filename, *kwargs): 182 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 183 | ''' 184 | Saves parameters to a file 185 | ''' 186 | d = self.get_parameters() 187 | with open(filename, 'w') as f: 188 | f.write("\n".join(["%s\t%.17e" % (k, v) for k, v in d.items()])) 189 | print('Parameters have been saved to the file {0}'.format(filename)) 190 | return None 191 | 192 | def load_parameters(self, filename, *kwargs): 193 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 194 | ''' 195 | Saves parameters to a file 196 | ''' 197 | name_value_pairs = {} 198 | with open(filename, 'r') as f: 199 | while True: 200 | s = f.readline() 201 | if len(s) == 0: 202 | break 203 | else: 204 | s = s.strip() 205 | 206 | if s[0] == '%' or s[0] == '#': 207 | continue 208 | if s.find(' ')!=-1: 209 | sp = s.split(' ') 210 | elif s.find('\t')!=-1: 211 | sp = s.split('\t') 212 | else: 213 | raise Exception('Unknown delimiter. Reads spaces or tabs.') 214 | 215 | name_value_pairs[sp[0]] = sp[1] 216 | self.set_parameters(name_value_pairs) 217 | 218 | 219 | 220 | 221 | return None 222 | 223 | def reset(self): 224 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 225 | ''' 226 | Resets all the parameters to default values 227 | ''' 228 | return None 229 | 230 | @contextmanager 231 | def context_get_param(self): 232 | #CONVENIENCE FUNCTION. IMPLEMENTATION IS NOT REQUIRED 233 | ''' 234 | Convenience contextmanager: 235 | Context used when getting parameter object 236 | ''' 237 | #This implementation raises an informative exception 238 | try: 239 | yield 240 | except KeyError as e: 241 | raise KeyError('There is no parameter {0} in the configurator'. 242 | format(e.message)) 243 | 244 | 245 | class MappingsBase(ResourceManagerBase): 246 | def __init__(self): 247 | ''' 248 | MappingsBase() 249 | Base class for managing mappings 250 | 251 | Contains methods: 252 | - add_mappings() (required) 253 | - set_mappings(mappings) (optional) 254 | - get_mappings() 255 | - clear_mappings() 256 | - del_mappings() (optional, not used by pyNCS by default) 257 | ''' 258 | ResourceManagerBase.__init__(self) 259 | 260 | def add_mappings(self, mappings): 261 | #IMPLEMENT (REQUIRED) 262 | ''' 263 | Adds *mappings* to the mappings table. 264 | 265 | Inputs: 266 | *mappings*: a two-dimenstional iterable 267 | ''' 268 | pass 269 | 270 | def get_mappings(self): 271 | #IMPLEMENT (REQUIRED) 272 | ''' 273 | Returns an array representing the mappings 274 | ''' 275 | return None 276 | 277 | def clear_mappings(self): 278 | #IMPLEMENT (REQUIRED) 279 | ''' 280 | Clears the mapping table. No inputs 281 | ''' 282 | return None 283 | 284 | def set_mappings(self, mappings): 285 | #CONVIENCE FUNCTION, IMPLEMENTATION NOT REQUIRED 286 | ''' 287 | Clears the mapping table and adds *mappings* to the mappings table. 288 | 289 | Inputs: 290 | *mappings*: a two-dimenstional iterable 291 | ''' 292 | self.clear_mappings() 293 | self.add_mappings(mappings) 294 | 295 | def del_mappings(self): 296 | #IMPLEMENT (OPTIONAL) 297 | ''' 298 | Clears the mapping table. No inputs 299 | ''' 300 | raise NotImplementedError('del_mappings has not been implemented') 301 | 302 | def filter_events(self, events): 303 | #CONVIENCE FUNCTION, IMPLEMENTATION NOT REQUIRED 304 | ''' 305 | Before Neurosetup sends the physical events are setup, they are first passed through this function. Useful if there are no virtual neurons. 306 | ''' 307 | return events 308 | 309 | # Default blank initializations 310 | # Override these classes in custom API as required 311 | Configurator = ConfiguratorBase 312 | Mappings = MappingsBase 313 | -------------------------------------------------------------------------------- /docs/general/tutorial.txt: -------------------------------------------------------------------------------- 1 | Step by step tutorial 2 | ===================== 3 | 4 | In this example we will guide you to the first use of the hardware setup. The 5 | neural network we will build has the following structure: 6 | 7 | - a population of 50 neurons 8 | - a DVS sensor that sends excitatory input to the population 9 | 10 | We will assume the hardware setup is on and working properly. If this is not 11 | the case, please refer to the hardware section of the documentation. 12 | 13 | Import 14 | ------ 15 | 16 | :: 17 | 18 | import pyNCS 19 | 20 | That's it. 21 | 22 | Loading a setup 23 | --------------- 24 | 25 | With *setup* we refer to the set of chips, boards, mapper, server, clients... 26 | everything that is used in the hardware experiment. To control the setup we 27 | implemented a `pyNCS.NeuroSetup` class. First copy the contents of `chipfiles`, `biases` and `setupfiles` directory from the pyNCS module to a local folder where you want to the experiments. Then run:: 28 | 29 | #Specifies the path to the setupfiles directory 30 | setupdir = './setupfiles/' 31 | #Constructs the nsetup object. 32 | nsetup = pyNCS.NeuroSetupAPI(setupdir+'zenzero_setuptype.xml', 33 | setupdir+'zenzero.xml', 34 | prefix='./' 35 | ) 36 | 37 | The setup is needed to create all the elements of the experiment, such as 38 | populations, connections, stimuli etc. It encapsulates all the informations 39 | about the hardware used. These informations are contained in xml files. 40 | 41 | 42 | The first xml file contains the setuptype. In this example, the setuptype is a 43 | setup with 4 AER channels: 4 chips can be connected in a loop. 44 | The second xml file contains informations about which chip is connected to 45 | which AEX board and which AMDA board. These informations are needed by the 46 | system to access chips, i.e. get/set biases, send/receive as well as 47 | encode/decode AER events, get/set mapping tables implementing the connectivity 48 | of the network, etc. (see :doc:`installation` for more details). 49 | 50 | .. note:: If you run through the network, which means for this tutorial any computer besides zenzero, then you must have an account on zenzero and copied your public key to it. You can conveniently do this with:: 51 | 52 | ssh-copy-id -i ~/.ssh/id_rsa.pub username@zenzero 53 | 54 | For example, to get all the parameters of a chip:: 55 | 56 | parameters = nsetup.chips['ifslwta0'].get_parameters() 57 | 58 | .. note:: In case there are problems in loading the setup, you may want to take a look at `:doc:` to fix or prevent errors. 59 | 60 | Creating populations 61 | -------------------- 62 | 63 | A population is a group of neurons on a chip. Each chip contains a certain 64 | number of neuronal circuits (somata). Each neuron has a certain number of 65 | synapses. If the chip is a neuromorphic sensor, it is very unlikely to have 66 | synapses... 67 | 68 | Let's create a population of neurons:: 69 | 70 | my_pop = pyNCS.Population( 'my_pop', 'My first population') 71 | 72 | The population is empty until we *populate* it, which means we have to fill it 73 | up:: 74 | 75 | my_pop.populate_by_number( nsetup, 'ifslwta0', 'excitatory', 50) 76 | 77 | There are several ways of populating. In this example we don't care about the 78 | position of the neurons on the chip, we just want to use 50 neurons. To do 79 | this, we called the `populate_by_number` function with the following 80 | arguments: 81 | 82 | - ``nsetup``: the setup 83 | - ``'ifslwta0'``: this is the name of the chip containing the neurons we want to 84 | use 85 | - ``'excitatory'``: in a neuromorphic chip there are in general several groups of 86 | neurons, sharing biases, connectivity or other properties. We have to tell 87 | the system which one of these groups we want to pick-up neurons from. 88 | - ``50``: the number of neurons we need 89 | 90 | Neurons and synapses are represented as digital addresses. This means that the 91 | population is basically a container of addresses. 92 | 93 | Let's create the input population:: 94 | 95 | input_pop = pyNCS.Population('input', 'Virtual input neurons') 96 | input_pop.populate_by_number(nsetup, 'seq', 'excitatory', 100) 97 | 98 | The virtual chip 'seq' has 4096 neurons, but the corresponding population will have 100 neurons. You can check this by typing:: 99 | 100 | len(input_pop) #Should output 100 101 | 102 | Setting parameters 103 | ------------------ 104 | 105 | Each chip has a certain amount of parameters that can be set. Parameters are 106 | mostly biases and we can control them by changing gate voltages of the 107 | corresponding transistors. Normally there is a voltage that controls the leak 108 | of the neuron, one that controls the weight of the excitatory synapses, one for 109 | the time constants, and so on and so forth. Before starting any experiment with 110 | the hardware one has to *set* the biases, which more or less corresponds to the 111 | *boot* operation of traditional computers. 112 | 113 | The relation between a voltage and 114 | the corresponding physical quantity that it controls is what is called 115 | parameter translation. There are several theoretical and empirical methods that 116 | try to operate this translation in a systematic and reliable way in order to 117 | adjust the parameters to each experiment. We will not cover the problem here 118 | and will assume you are already in possess of basic sets of biases. What this 119 | practically means is explained as follows. 120 | 121 | The set of parameters can be very large. Usually we handle this parameters 122 | using text files. We already have bias files for default sets of parameters for 123 | basic experiments but each experiments has usually its own set. Most probably 124 | you have already copied the biase files into the ``biases`` folder. Now you 125 | would like to load this biases to *boot* the system in the proper 126 | configuration. The operation is as simple as the following:: 127 | 128 | nsetup.chips['ifslwta0'].load_parameters('biases/ifslwta_default.biases') 129 | 130 | .. note:: The DVS sensor doesn't have digital biases but physical potentiometers 131 | on the board it is soldered on. Do not change them unless you know what you are doing. 132 | 133 | Creating connections 134 | -------------------- 135 | 136 | We now need to connect the sensor output the excitatory synapses of our 137 | population of 50 neurons. This will be done using the ``pyNCS.Connection`` 138 | class:: 139 | 140 | C = pyNCS.Connection(input_pop, my_pop, 'excitatory0', 'all2all') 141 | 142 | The ``excitatory0`` string is the name of the excitatory synapses the each 143 | neuron of the ``ifslwta0`` chip has. The last argument is the connectivity 144 | *fashion*, the default one is a one-to-one connectivity. With an all-to-all 145 | connectivity, our 50 neurons will represent the average activity of the whole 146 | input array. 147 | 148 | .. note:: There is also a lower level `pyMap module`_ which also has a very 149 | nice interactive GUI. You may want to use it to check that the 150 | mapping is correct. (As of Jan 2012, pyMAP is broken). Try the following:: 151 | 152 | mapper_hostname = 'zanzara2' # change this to the real hostname! 153 | M = pyMap.Mapping(setup, host=mapper_hostname).gui() 154 | M.mainloop() 155 | 156 | .. _pyMap module: pymap.html 157 | 158 | Sending and receiving stimuli 159 | ----------------------------- 160 | 161 | In some experiments you want to interact in real-time with the system. For 162 | example, you might have sets of recordings of calcium concentrations that you 163 | want to convert into spikes and send to the system. Here we will show how to 164 | send and receive events from the hardware. 165 | 166 | Suppose you have vectors of mean-rates of a population of 167 | neurons. You can now create poisson trains with constant mean-rates 168 | corresponding to those of your vector. Let's than turn off the DVS (power off) 169 | to replace the real-time input with the input we will send to the system. 170 | 171 | There are several functions to create trains of spikes. These functions are 172 | usually methods of the ``population.soma`` group. 173 | 174 | :: 175 | 176 | from numpy import random 177 | #Generate a list of random numbers uniformly distributed in [20,30] 178 | meanrates = random.random(len(input_pop))*10 + 20 179 | 180 | stim = input_pop.soma.spiketrains_poisson(meanrates, duration=2000) 181 | 182 | The variable ``stim`` now contains our spike-trains (a ``SpikeList`` instance from 183 | ``pyST.spikes``) with poisson trains of random mean-rates between 20Hz and 30Hz 184 | lasting for 2000ms. 185 | 186 | By default, the input synapse 'excitatory0' is initially turned off by setting its weight to zero. You can increase the weight by setting the appropriate bias as follows:: 187 | 188 | nsetup.chips['ifslwta0'].set_parameter('nsynstdw0',0.4) 189 | 190 | We can not send the input and monitor some output using nsetup.run:: 191 | 192 | output = nsetup.run(stim) 193 | 194 | .. note:: If you are using the 'pyAex.api.com_aextcpclient' as the communicator (see :doc:`installation`), you must be sure that the server is started on the host:: 195 | 196 | #Go to your pyAex direction in a shell on the host computer 197 | cd pyAex/Script/ 198 | #Start the server 199 | python Server.py 200 | 201 | To stop the server, type ``stop`` 202 | 203 | 204 | Monitors and plots 205 | ------------------ 206 | 207 | There are several ways to visualize spiketrains. Assuming stim is a SpikeList object, the most basic vizualization is as follows:: 208 | 209 | from pylab import ion 210 | ion() 211 | 212 | stim[input_pop.soma.channel].raster_plot() 213 | 214 | output[my_pop.soma.channel].raster_plot() 215 | 216 | Monitors are a much more convenient way of visualizing data when dealing with 217 | several populations of neurons. A monitor will slice addresses and times according to the Population it is monitoring. 218 | 219 | Create a monitor with the following:: 220 | 221 | from pyNCS.monitors import SpikeMonitor 222 | my_mon = SpikeMonitor(my_pop.soma) 223 | 224 | Then import it to the setup with:: 225 | 226 | nsetup.monitors.import_monitors([my_mon]) 227 | 228 | When ``nsetup.run`` is run, ``my_mon`` gets automatically populated with the relevant output spikes. You will have to run ``nsetup.run`` again or ``nsetup.monitors.populate_monitors(output)``. 229 | Raster plots and rate plots can be convienently obtained with:: 230 | 231 | from pyNCS.monitors import RasterPlot, MeanRatePlot 232 | RasterPlot(my_mon) 233 | MeanRatePlot(my_mon) 234 | 235 | The results should look like this: 236 | 237 | .. image:: ../images/meanrate_tutorial.png 238 | :width: 400px 239 | 240 | .. image:: ../images/raster_tutorial.png 241 | :width: 400px 242 | 243 | You can also use SpikeMonitors to vizualize inputs:: 244 | 245 | input_mon = SpikeMonitor(input_pop.soma) 246 | input_mon.populate(stim[input_pop.soma.channel]) 247 | RasterPlot(input_mon) 248 | MeanRatePlot(input_mon) 249 | 250 | 251 | Beyond this tutorial 252 | -------------------- 253 | 254 | Congratulations, you have completed the first NCS tutorial and began your neuromorphic hardware career. 255 | If you want to see furhter examples, download the zenzero_unittest folder from the svn repository https://svn.ini.uzh.ch/repos/ncs/ini/code/python/ncs_unittests/zenzero_unittest, and take a look at the folders in the test directory. Each test can be run independently by typing:: 256 | 257 | cd tests/test_swta_ifslwta0 258 | ipython 259 | run expRun 260 | 261 | The entire unittests can be run with:: 262 | 263 | python zenzero_unittest.py 264 | 265 | 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /docs/general/installation.txt: -------------------------------------------------------------------------------- 1 | Software Installation 2 | ===================== 3 | 4 | Preliminary remarks 5 | ------------------- 6 | 7 | The software is mainly tested on Linux. It has been reported to work on Mac OS X without considerable difficulty, but is is currently not supported by Windows. 8 | 9 | Prerequisites 10 | ............. 11 | 12 | You first need the following python packages 13 | 14 | - `python `_ 15 | - `python-dev `_ 16 | - `numpy `_ 17 | - `scipy `_ 18 | - `matplotlib `_ 19 | - `pydot `_ 20 | - `lxml `_ 21 | 22 | For real-time vizualization, you will need Enthoughts Chaco Module: 23 | 24 | - `TraitsGUI `_ 25 | - `chaco `_ 26 | 27 | 28 | Finally, a nice matlab--style Python prompt is IPython. 29 | 30 | - (Optional) `IPython `_ 31 | 32 | You can try to install all these packages in ubuntu, add the "universe" repository and run the following command in a terminal: 33 | 34 | ``sudo apt-get install python python-pydot python-dev python-numpy python-matplotlib iPython python-scipy python-chaco python-lxml`` 35 | 36 | 37 | Optional packages: 38 | 39 | - `interval `_ 40 | - `Python Imaging Library (PIL) `_ 41 | - `TableIO `_ 42 | - `setuptools `_ 43 | - `wxPython `_ 44 | 45 | Installation of pyNCS 46 | --------------------- 47 | 48 | - This packages contains all the objects needed for the setup. You can download 49 | the latest version of pyNCS by running the following command through your commandline tools. 50 | 51 | ``git clone https://github.com/inincs/pyNCS.git`` 52 | 53 | For installing the python package go to the downloaded directory and run 54 | 55 | ``sudo python setup.py install`` 56 | 57 | You can do the same for any python package. 58 | 59 | 60 | Installation of INI python packages 61 | ----------------------------------- 62 | 63 | 64 | The NCS drivers can be downloaded directly from their respective repositories. 65 | 66 | - pyAMDA: this module is required by pyNCS and contains the module to set the biases (responsible: Sadique Sheik, Daniel Sonnleithner) 67 | 68 | ``svn co https://svn.ini.unizh.ch/repos/ncs/ini/code/python/pyAMDA`` 69 | 70 | - pyAex: This module has the client and servers classes used for Stimulation/Monitoring module the chips and setting the mappings (responsible: Emre_) 71 | 72 | ``svn co https://svn.ini.uzh.ch/repos/ncs/ini/code/python/pyAex`` 73 | 74 | 75 | This will install the python module to the appropriate place on your system. 76 | 77 | **The following is only needed if your computer is going to act as a server, i.e. it will be directly connected to an AEX board. If you don't know what this means, this means it is probably not required** 78 | 79 | If your computer is going to act as a Server (i.e. you are going to connect 80 | chips to your computer), you also need 81 | 82 | - fxload 83 | 84 | ``sudo apt-get install fxload`` 85 | 86 | - aerfx2 and fx2: the driver for the AEX boards (Daniel_) 87 | - udevamda: the udev rule for the amda boards (Sadique Sheik, Daniel Sonnleithner). you may install the udev rules by running ``make install`` as root in the udevamda directory 88 | 89 | Setup files and chip files explained 90 | ------------------------------------ 91 | 92 | The "setup files" and the "chip files" contain information about the hardware setup, such 93 | as IP addresses of the servers and mappers, ID of the boards connected, the list of the chips connected to the hardware, how to interpret AER packets, and so on. 94 | The pyNCS package comes with them in the ``test/setupfiles`` and ``test/chipfiles`` 95 | folders. Here we explain some details about them. 96 | 97 | Chip files 98 | .......... 99 | 100 | Chip files contain information that the driver needs to get/set biases (parameters) on the chip and translate its address events. This information is contained in a csv file, for example ``ifslwta.csv``. Higher level information relative to the neurons and the synapses present on the chip is contained in an xml file with the same basename, for example ``ifslwta.xml``. 101 | Chip files are usually written once for every type of chip, and do not need to be changed. 102 | 103 | Setup files 104 | ........... 105 | 106 | The setup files indicate which chip is connected to which AER interface (e.g. AEX board), the latter being referred to as a `slot`. Each slot is associated to one channel. There are at least as many slots as there are chips. 107 | 108 | There are two xml files for the setup. One is a *setup type file*, for example ``setuptype.xml``, 109 | the other is a *setup file*, for example ``setup.xml``. The former is the general description of the setup, which you need to modify if you are building a new setup, but stays fixed otherwise. The latter one described which chips are present in the actual setup, and which software modules it should use to access it. 110 | 111 | setuptype.xml 112 | """"""""""""" 113 | Here is an example of setup type file:: 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | ``channelAddressing`` 137 | 138 | First, the setuptype must contain two ```` tags. These indicate the encoding of the channels, one for the monitoring ( with attribute ``type="monitor"``), one for the sequencing ( with attribute ``type="sequencer"`` input to chip). The attribute ``bits`` defines the list of bit positions which encode the channel. 139 | For example, the address space used in the above setup type file is:: 140 | 141 | | channel | chip address space | 142 | | 16 15 14 | 13 12 11 10 9 8 7 6 5 4 3 2 1 | 143 | 144 | meaning, for instance, that the address event ``0x64d2`` monitored from the setup will be decoded into channel ``3`` and chip address ``0x4d2``. 145 | 146 | 147 | ``slot`` 148 | 149 | The setup type then contains a number of ```` tags. One chip will occupy one slot, as defined by the associated ``setup.xml`` file (see below). The ``id`` can be anything, but it must match with the associated setup file. In the setup type file, the slots define how the channel of its sequencer and the monitor. 150 | Usually, you only need to define the channel number in the attribute ``out`` for ```` and ``in`` for ````. The others are used in special cases. 151 | 152 | For example, take ````:: 153 | 154 | 155 | 156 | 157 | 158 | 159 | This slot has ```` , meaning that the address ``0x64d2`` will be interpreted as originating from channel number ``3``, meaning the chip in slot ``3``. The number in brackets refers to the channel number encoded by the channel bits. In the example above these were bits 16 15 and 14. 160 | The same slot contains the tag ````. This indicates that, to stimulate synapse ``0x4d2``, a ``0xe000`` (corresponding to ``7 * 2^13``) must be added. 161 | 162 | Again the ``in`` in aerMon and the ``out`` in aerSeq are usally not used, so their function is not covered here. 163 | 164 | If possible, the setuptype will be checked against a DTD available online (Document Type Definition) 165 | 166 | 167 | setup.xml 168 | """"""""" 169 | 170 | The ``setup.xml`` file describes which chips fit in the slots defined in the setup type. All the tags in setup.xml are enclosed by the `` `` tags. The ```` should contain ```` tags, one for each chip. Here is an example:: 171 | 172 | 173 | 174 | 175 | 176 | zsd 177 | T03 178 | 179 | 180 | 181 | 182 | 183 | zsd 184 | 5 185 | 186 | 187 | zanzara2 188 | 1.0 189 | 190 | 191 | 192 | Let's analyze it attribute by attribute. 193 | 194 | ``chipfile`` 195 | Usually chipfiles and setupfiles are stored in the client in some common 196 | directory, it could be ``/usr/share/ncs/`` or ``~/.ncs``, so that every 197 | experiment just refers to that common source. If this is not the case you have 198 | to make sure setupfiles correctly point to chipfiles. 199 | 200 | ``id`` 201 | This defines the name of the chip. This name will be used in pyNCS to identify it. 202 | 203 | ```` 204 | indicates the configurator API which should be used to access the chip 205 | biases. In this case, it contains the information about which chip is 206 | connected to which host (server) and which AMDA board -- the board that 207 | gets/sets biases on the chip. The attribute ``module=pyAmda.api`` is the 208 | python module implementing the configurator API. The parameter elements are 209 | used as keyword arguments for that module, in this case 210 | {'host':'zsd','board':'T03'}. The actual id of the AMDA board should be 211 | written on a sticker below the board itself, e.g. could be ``AMDA #2.09``. 212 | 213 | ``slot`` 214 | what we call the channel. On top of the FPGA mounted on the AEX board there 215 | should be a sticker referring to the channel number. In this case it should be 216 | ``FES 0``. 217 | 218 | In addition, there are ```` and ```` tags. The former defines a chip which does not physically exist, therefore does not have a configurator. It is typically used to provide 'input neurons'. 219 | The latter (````) defines the default virtual chip to use if a slot that is defined in setuptup is not present in the setup.xml. Note that ```` does not take a configurator element, therefore defaultchip is only specifies virtual chips. 220 | 221 | The last fields of the ``setup.xml`` file describes which modules should be used to communicate with the setup:: 222 | 223 | 224 | zsd 225 | 5 226 | 227 | 228 | zanzara2 229 | 1.0 230 | 231 | 232 | 233 | ```` and ```` 234 | indicate the modules implementing the respective pyNCS API (communicator or mapper). As with the ````, the parameter elements are used as keyword arguments for that module. The ones indicated above are probably the ones you would like to use. See pyNCS documentation otherwise. 235 | 236 | .. image:: ../images/amda_and_aex.jpg 237 | :width: 400px 238 | 239 | .. _Emre: mailto:emre(at)ini.phys.ethz.ch 240 | .. _Daniel: mailto:fasnacht(at)sos.phys.ethz.ch 241 | .. _ncs: http://ncs.ethz.ch 242 | --------------------------------------------------------------------------------