Changeset 356

Show
Ignore:
Timestamp:
11/19/08 15:41:48 (2 months ago)
Author:
apdavison
Message:

Changed the behaviour of the AnalogSignal constructor. Before, t_start and t_stop were used to throw away data, on the assumption that the signal always started at t=0 - see [45]. Now, these arguments are used as metadata, and we check that they are consistent with the number of elements in the signal array.

Also added some checks that all the AnalogSignals in an AnalogSignalList are consistent in terms of length, dt, etc.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/signals.py

    r346 r356  
    519519            self.t_start      = 0.0 
    520520 
    521     def distance_victorpurpura(self, spktrain, cost): 
     521    def distance_victorpurpura(self, spktrain, cost=0.5): 
    522522        """ 
    523523        Function to calculate the Victor-Purpura distance between two spike trains. 
    524524        See J. D. Victor and K. P. Purpura, 
    525525            Nature and precision of temporal coding in visual cortex: a metric-space 
    526            analysis., 
     526            analysis., 
    527527            J Neurophysiol,76(2):1310-1326, 1996 
    528528         
    529529        Inputs: 
    530530            spktrain - the other SpikeTrain 
    531             cost     - The cost parameter. See the paper for more informations 
     531            cost     - The cost parameter. See the paper for more information 
    532532        """ 
    533533        nspk_1      = len(self) 
     
    21512151class AnalogSignal(object): 
    21522152    """ 
    2153     AnalogSignal(signal, dt, t_start=None, t_stop=None) 
    2154      
    2155     Return a AnalogSignal object which will be a analog signal trace 
     2153    AnalogSignal(signal, dt, t_start=0, t_stop=None) 
     2154     
     2155    Return a AnalogSignal object which will be an analog signal trace 
    21562156 
    21572157    Inputs: 
    21582158        signal  - the vector with the data of the AnalogSignal 
    21592159        dt      - the time step between two data points of the sampled analog signal 
    2160         t_start - begining of the signal, in ms. If None, will be set to 0 
    2161         t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
     2160        t_start - begining of the signal, in ms. 
     2161        t_stop  - end of the SpikeList, in ms. If None, will be inferred from the data 
    21622162     
    21632163    Examples: 
    2164         >> as = AnalogSignal(range(100), dt=0.1, t_start=0, t_stop=10) 
     2164        >> s = AnalogSignal(range(100), dt=0.1, t_start=0, t_stop=10) 
    21652165 
    21662166    See also 
    21672167        AnalogSignalList, load_currentlist, load_vmlist, load_conductancelist, load 
    21682168    """ 
    2169     def __init__(self, signal, dt, t_start=None, t_stop=None): 
    2170  
    2171         self.signal  = numpy.array(signal,float) 
    2172         self.dt      = dt 
    2173         self.t_start = t_start 
     2169    def __init__(self, signal, dt, t_start=0, t_stop=None): 
     2170 
     2171        self.signal  = numpy.array(signal, float) 
     2172        self.dt      = float(dt) 
     2173        self.t_start = float(t_start) 
    21742174        self.t_stop  = t_stop 
    21752175         
    2176         # If t_start is not None, we resize the signal keeping only 
    2177         # elements with t >= t_start 
    2178         if self.t_start is not None: 
    2179            self.signal = self.signal[numpy.floor(self.t_start/self.dt):] 
    2180          
    2181         # If t_stop is not None, we resize the signal keeping only 
    2182         # elements with t <= t_stop 
     2176        # If t_stop is not None, we test that the signal has the correct number 
     2177        # of elements 
    21832178        if self.t_stop is not None: 
    2184            self.signal = self.signal[:numpy.floor((self.t_stop-self.t_start)/self.dt)] 
    2185  
    2186         if len(self.signal) > 0: # spike list may be empty 
    2187             if self.t_start is None: 
    2188                 self.t_start = 0. 
    2189             if self.t_stop is None: 
    2190                 self.t_stop = len(self.signal)*self.dt 
    2191         else: 
    2192             self.t_start = 0. 
    2193             self.t_stop = self.dt 
     2179            if self.t_stop-self.t_start != self.dt * len(self.signal): 
     2180                raise Exception("Inconsistent arguments: t_start=%g, t_stop=%g, dt=%g implies %d elements, actually %d" % ( 
     2181                                    t_start, t_stop, dt, int((t_stop-t_start)/float(dt)), len(signal))) 
     2182        else: 
     2183            self.t_stop = self.t_start + len(self.signal)*self.dt 
     2184 
    21942185        # TODO raise an error if some data is outside [t_start, t_stop] ? 
    21952186        # TODO return an exception if self.t_stop < self.t_start (when not empty) 
    2196         if self.t_start >= self.t_stop
     2187        if self.t_start >= self.t_stop
    21972188            raise Exception("Incompatible time interval for the creation of the AnalogSignal") 
    21982189 
     
    22382229        else: 
    22392230            norm = 0. 
    2240         return numpy.linspace(self.t_start-norm, self.t_stop-norm, len(self.signal)) 
    2241  
     2231        return numpy.arange(self.t_start-norm, self.t_stop-norm, self.dt) 
    22422232     
    22432233    def time_offset(self, offset): 
     
    23012291            t_stop  - end of the new SpikeTrain, in ms. 
    23022292        """ 
    2303         assert t_start>self.t_start 
    2304         assert t_stop<=self.t_stop 
    2305         assert t_stop>t_start 
     2293        assert t_start >= self.t_start 
     2294        assert t_stop <= self.t_stop 
     2295        assert t_stop > t_start 
    23062296         
    23072297        t = self.time_axis() 
    2308         i_start = numpy.searchsorted(t,t_start,'right')-1 
    2309         i_stop = numpy.searchsorted(t,t_stop,'right')-1 
    2310  
     2298        i_start = int((t_start-self.t_start)/self.dt) 
     2299        i_stop = int((t_stop-self.t_start)/self.dt) 
    23112300        signal = self.signal[i_start:i_stop] 
    2312         result = AnalogSignal(signal, self.dt, 0.0, t_stop-t_start) 
    2313         result.time_offset(t_start) 
     2301        result = AnalogSignal(signal, self.dt, t_start, t_stop) 
    23142302        return result 
    23152303 
     
    24392427    def slice_by_events(self,events,t_min=100,t_max=100): 
    24402428        """ 
    2441         Returns a dict containing new AnalogSignals coutout around events. 
     2429        Returns a dict containing new AnalogSignals cutout around events. 
    24422430 
    24432431        Inputs: 
     
    24652453                t_start_new = (spike-t_min) 
    24662454                t_stop_new = (spike+t_max) 
    2467                 result[index] = AnalogSignal(self.signal, self.dt, t_start=t_start_new, t_stop=t_stop_new) 
    2468  
     2455                result[index] = self.time_slice(t_start_new, t_stop_new) 
    24692456        return result 
    24702457         
     
    24832470        id_list - the list of the ids of all recorded cells (needed for silent cells) 
    24842471        dt      - if dt is specified, time values should be floats 
    2485         t_start - begining of the SpikeList, in ms. If None, will be infered from the data 
     2472        t_start - begining of the SpikeList, in ms. 
    24862473        t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
    24872474        dims    - dimensions of the recorded population, if not 1D population 
     
    24922479        load_currentlist load_vmlist, load_conductancelist 
    24932480    """ 
    2494     def __init__(self, signals, id_list, dt, t_start=None, t_stop=None, dims=None): 
    2495          
    2496         self.t_start        = t_start 
     2481    def __init__(self, signals, id_list, dt, t_start=0, t_stop=None, dims=None): 
     2482         
     2483        self.t_start        = float(t_start) 
    24972484        self.t_stop         = t_stop 
    2498         self.dt             = dt 
     2485        self.dt             = float(dt) 
    24992486        self.dimensions     = dims 
    25002487        self.analog_signals = {} 
     
    25132500                self.analog_signals.pop(id) 
    25142501         
    2515         if t_start is None or t_stop is None: 
    2516             self.__calc_startstop() 
     2502        if id_list: 
     2503            self.signal_length = len(self.analog_signals[min(id_list)]) 
     2504            for signal in self.analog_signals.values(): 
     2505                if len(signal) != self.signal_length: 
     2506                    raise Exception("Signals must all be the same length %d != %d" % (self.signal_length, len(signal))) 
     2507        else: 
     2508            self.signal_length = 0 
     2509         
     2510        if t_stop is None: 
     2511            self.t_stop = self.t_start + self.signal_length*self.dt 
    25172512 
    25182513    def id_list(self): 
     
    25322527            aslist.append(id, self.analog_signals[id]) 
    25332528        return aslist 
    2534  
    2535     def __calc_startstop(self): 
    2536         """ 
    2537         t_start and t_stop are shared for all neurons, so we take min and max values respectively. 
    2538         TO DO : check the t_start and t_stop parameters for a SpikeList. Is it commun to 
    2539         all the spikeTrains within the spikelist or each spikelistes do need its own. 
    2540         """ 
    2541         if len(self) > 0: 
    2542             if self.t_start is None: 
    2543                 start_times  = numpy.array([self.analog_signals[idx].t_start for idx in self.id_list()]) 
    2544                 self.t_start = numpy.min(start_times) 
    2545                 logging.debug("Warning, t_start is infered from the data : %f" %self.t_start) 
    2546                 for id in self.analog_signals.keys(): 
    2547                     self.analog_signals[id].t_start = self.t_start 
    2548             if self.t_stop is None: 
    2549                 stop_times  = numpy.array([self.analog_signals[idx].t_stop for idx in self.id_list()]) 
    2550                 self.t_stop = numpy.max(stop_times) 
    2551                 logging.debug("Warning, t_stop  is infered from the data : %f" %self.t_stop) 
    2552                 for id in self.analog_signals.keys(): 
    2553                     self.analog_signals[id].t_stop = self.t_stop 
    2554         else: 
    2555             raise Exception("No Analog Signals !") 
    25562529     
    25572530    def __getitem__(self, id): 
     
    25632536    def __setitem__(self, i, val): 
    25642537        assert isinstance(val, AnalogSignal), "An AnalogSignalList object can only contain AnalogSignal objects" 
     2538        if len(self) > 0: 
     2539            errmsgs = [] 
     2540            for attr in "dt", "t_start", "t_stop": 
     2541                if getattr(val, attr) != getattr(self, attr): 
     2542                    errmsgs.append("%s: %g != %g" % attr, getattr(val, attr), getattr(self, attr)) 
     2543            if len(val) != self.signal_length: 
     2544                errmsgs.append("signal length: %g != %g" % (len(val), self.signal_length)) 
     2545            if errmsgs: 
     2546                raise Exception("AnalogSignal being added does not match the existing signals: "+", ".join(errmsgs)) 
     2547        else: 
     2548            self.signal_length = len(val) 
    25652549        self.analog_signals[i] = val 
    2566         self.__calc_startstop() 
    25672550 
    25682551    def __len__(self): 
     
    25982581            raise Exception("Id already present in AnalogSignalList. Use setitem instead()") 
    25992582        else: 
    2600             self.analog_signals[id] = signal 
    2601         self.__calc_startstop() 
     2583            self[id] = signal 
    26022584 
    26032585    def time_axis(self): 
     
    26052587        Return the time axis of the AnalogSignalList object 
    26062588        """ 
    2607         return numpy.arange(self.t_start,self.t_stop,self.dt) 
     2589        return numpy.arange(self.t_start, self.t_stop, self.dt) 
    26082590 
    26092591    def id_offset(self, offset): 
     
    26222604                [10,11,12,13,14] 
    26232605        """ 
    2624         id_list     = numpy.sort(self.id_list()) 
    2625         N           = len(id_list) 
    2626          
     2606        id_list = numpy.sort(self.id_list()) 
     2607        N       = len(id_list) 
    26272608        for idx in xrange(1,len(id_list)+1): 
    26282609            id  = id_list[N-idx] 
    26292610            spk = self.analog_signals.pop(id) 
    26302611            self.analog_signals[id + offset] = spk 
    2631      
    26322612 
    26332613    def id_slice(self, id_list): 
     
    26672647        for id in self.id_list(): 
    26682648            new_AnalogSignalList.append(id, self.analog_signals[id].time_slice(t_start, t_stop)) 
    2669         new_AnalogSignalList.__calc_startstop() 
    26702649        return new_AnalogSignalList 
    26712650 
     
    27922771        result = numpy.zeros((len(self), int((self.t_stop - self.t_start)/self.dt)),float) 
    27932772        for count, id in enumerate(self.id_list()): 
    2794              result[count,:] = self.analog_signals[id].signal 
    2795         return numpy.var(result, axis=0) 
     2773            try: 
     2774                result[count,:] = self.analog_signals[id].signal 
     2775            except ValueError: 
     2776                print result[count,:].shape, self.analog_signals[id].signal.shape 
     2777                raise 
     2778        return numpy.std(result, axis=0) 
    27962779 
    27972780    def event_triggered_average(self, eventdict, events_ids = None, analogsignal_ids = None, average = True, t_min = 0, t_max = 100, ylim = None, display = False, mode = 'same', kwargs={}): 
     
    29042887                subplot.plot(time_axis, to_be_plot, **kwargs) 
    29052888                subplot.hold(1) 
    2906             pylab.draw() 
     2889            #pylab.draw() 
    29072890 
    29082891 
     
    30343017 
    30353018 
    3036 def load_vmlist(user_file, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
     3019def load_vmlist(user_file, id_list=None, dt=None, t_start=0, t_stop=None, dims=None): 
    30373020    """ 
    30383021    Returns a VmList object from a file. If the file has been generated by PyNN,  
  • trunk/src/stgen.py

    r352 r356  
    700700            return (y,t) 
    701701 
    702         result = AnalogSignal(y,dt,t_start=0,t_stop=t_stop-t_start) 
    703         result.time_offset(t_start) 
     702        result = AnalogSignal(y, dt, t_start, t_stop) 
    704703        return result 
    705704         
     
    755754            return (y,t) 
    756755 
    757         result = AnalogSignal(y,dt,t_start=0,t_stop=t_stop-t_start) 
    758         result.time_offset(t_start) 
     756        result = AnalogSignal(y, dt, t_start, t_stop) 
    759757        return result 
    760758         
     
    829827            return (y,t) 
    830828 
    831         result = AnalogSignal(y,dt,t_start=0,t_stop=t_stop-t_start) 
    832         result.time_offset(t_start) 
     829        result = AnalogSignal(y,dt,t_start,t_stop) 
    833830        return result 
    834831 
     
    881878    st = spike_train 
    882879 
    883     assert t_stop>t_start 
     880    if t_start is not None and t_stop is not None: 
     881        assert t_stop>t_start 
    884882 
    885883    # time of vanishing significance 
  • trunk/test/test_signals.py

    r320 r356  
    411411    def testCreateAnalogSignalWithTstart(self): 
    412412        sig = signals.AnalogSignal(numpy.sin(numpy.arange(10000.)), 0.1, 10) 
    413         assert len(sig) == (10000 - 10/0.1) 
     413        self.assertEqual(len(sig), 10000) 
     414        self.assertEqual(sig.t_start, 10.0) 
     415        self.assertEqual(sig.t_stop, 10.0+10000*0.1) 
    414416     
    415417    def testCreateAnalogSignalWithTstartTstop(self): 
    416         sig = signals.AnalogSignal(numpy.sin(numpy.arange(10000.)), 0.1, 10, 990) 
    417         assert len(sig) == (10000 - 20/0.1) 
     418        sig = signals.AnalogSignal(numpy.sin(numpy.arange(10000.)), 0.1, 10, 1010) 
     419        self.assertEqual(len(sig), 10000) 
     420        self.assertEqual(sig.t_start, 10.0) 
     421        self.assertEqual(sig.t_stop, 1010.0) 
    418422 
    419423    def testCreateAnalogSignalWrongTimes(self): 
     
    427431        sig = signals.AnalogSignal(numpy.sin(numpy.arange(10000.)), 0.1) 
    428432        res = sig.time_slice(0,500) 
    429         assert len(res) == 5000 
     433        self.assertEqual(len(res), 5000) 
     434        res = sig.time_slice(250,750) 
     435        self.assertEqual(len(res), 5000) 
    430436 
    431437    def testSliceByEvents(self): 
     
    470476        new_analog = self.analog.time_slice(0, 50.) 
    471477        assert (new_analog.t_start == self.analog.t_start) and (new_analog.t_stop == 50.) 
     478        new_analog = self.analog.time_slice(self.analog.t_start, self.analog.t_stop) 
     479        self.assertEqual(len(new_analog[0]), len(self.analog[0])) 
    472480     
    473481    def testCreateAnalogSignalList(self): 
    474         analog = signals.AnalogSignalList(self.values, range(10), 0.1, 0, 20) 
    475         assert analog.t_start == 0 and analog.t_stop == 2
     482        analog = signals.AnalogSignalList(self.values, range(10), 0.1, 0, 100) 
     483        assert analog.t_start == 0 and analog.t_stop == 10
    476484     
    477485    def testSaveAndLoadTxt(self): 
     
    482490    def testSaveAndLoadTxtTimePart(self): 
    483491        self.analog.save("tmp.txt") 
    484         analog2 = signals.load_vmlist("tmp.txt", t_start=0, t_stop=50) 
    485         assert analog2.t_stop == 5
     492        analog2 = signals.load_vmlist("tmp.txt", t_start=0, t_stop=100) 
     493        assert analog2.t_stop == 10
    486494     
    487495    def testSaveAndLoadTxtIdsPart(self): 
     
    499507        file = io.StandardPickleFile("tmp.pickle") 
    500508        self.analog.save(file) 
    501         analog2 = signals.load_vmlist(file, t_start=0, t_stop=50) 
    502         assert analog2.t_stop == 5
     509        analog2 = signals.load_vmlist(file, t_start=0, t_stop=100) 
     510        assert analog2.t_stop == 10
    503511     
    504512    def testSaveAndLoadPickleIdsPart(self): 
  • trunk/test/test_stgen.py

    r337 r356  
    303303        st = stg.poisson_generator(10.0,0.0,1000.0) 
    304304         
    305         ge = shotnoise_fromspikes(st,2.0,10.0,dt=0.1) 
     305        ge = stgen.shotnoise_fromspikes(st,2.0,10.0,dt=0.1) 
    306306 
    307307        assert ge.t_start==0.0 
     
    309309 
    310310        st = stg.poisson_generator(10.0,0.0,1000.0) 
    311         ge = shotnoise_fromspikes(st,2.0,10.0,dt=0.1,t_start=500.0,t_stop=1500.0) 
     311        ge = stgen.shotnoise_fromspikes(st,2.0,10.0,dt=0.1,t_start=500.0,t_stop=1500.0) 
    312312         
    313313        assert ge.t_start==500.0