Exemplo n.º 1
0
    def testMisfitOfSameTracesZero(self):
        y = num.random.random(10000)
        y -= max(y) * 0.5
        t1 = trace.Trace(tmin=0, ydata=y, deltat=0.01)
        t2 = trace.Trace(tmin=0, ydata=y, deltat=0.01)
        # ttraces = [t2]
        fresponse = trace.FrequencyResponse()
        taper = trace.CosFader(xfade=2.)
        norms = [1, 2]
        domains = ['time_domain', 'frequency_domain', 'envelope', 'absolute']
        setups = [
            trace.MisfitSetup(norm=n,
                              taper=taper,
                              domain=domain,
                              filter=fresponse) for domain in domains
            for n in norms
        ]

        for setup in setups:
            m, n, tr, tc = t1.misfit(candidate=t2, setup=setup, debug=True)
            if isinstance(tr, trace.Trace):
                self.assertEqual(tr.tmin, tc.tmin)
                self.assertTrue(all(tr.get_ydata() == tc.get_ydata()))
            else:
                self.assertTrue(all(tc == tr))

            self.assertEqual(m, 0., 'misfit\'s m of equal traces is != 0')
Exemplo n.º 2
0
    def __init__(self, markers, stations=None):
        # Targets================================================
        store_id = 'castor'

        if store_id=='local1':
            phase_ids_start = 'p|P|Pv20p|Pv35p'
            phase_ids_end =   's|S|Sv20s|Sv35s'

        if store_id=='very_local':
            phase_ids_start = 'p|P|Pv3p|Pv8p|Pv20p|Pv35p'
            phase_ids_end =   's|S|Sv3s|Sv8s|Sv20s|Sv35s'

        if store_id=='very_local_20Hz':
            phase_ids_start = 'begin_fallback|p|P|Pv1p|Pv3p|Pv8p|Pv20p|Pv35p'
            phase_ids_end =   's|S|Sv1s|Sv3s|Sv8s|Sv20s|Sv35s'

        if store_id=='very_local_20Hz':
            phase_ids_start = 'begin_fallback|p|P|Pv1p|Pv3p|Pv8p|Pv20p|Pv35p'
            phase_ids_end =   's|S|Sv1s|Sv3s|Sv8s|Sv20s|Sv35s'

        if store_id=='castor':
            # bug?! bei Pv1.5p gibt's bei nahen Entfernungen ein index ot of
            # bounds
            phase_ids_start = 'p|P|Pv12.5p|Pv2.5p|Pv18.5p|Pv20p|Pv35p'
            phase_ids_end= 's|S|Sv12.5s|Sv2.5s|Sv18.5s|Sv20s|Sv35s'

        # Event==================================================
        event = filter(lambda x: isinstance(x, gui_util.EventMarker), markers)
        assert len(event) == 1
        event = event[0].get_event()
        event.magnitude = 4.3
        event.moment_tensor = moment_tensor.MomentTensor(
                                        m=num.array([[0.0, 0.0, 1.0],
                                                     [0.0, 0.0, 0.0],
                                                     [0.0, 0.0, 0.0]]))
    

        # generate stations from olat, olon:
        if not stations:
            print 'Generating station distribution.'
            stations = du.station_distribution((event.lat,event.lon),
                                           [[10000., 4], [130000., 8]], 
                                           rotate={3000.:45, 130000.:0})

        targets = stations2targets(stations, store_id)

        derec_home = os.environ["DEREC_HOME"]
        store_dirs = [derec_home + '/fomostos']

        engine = LocalEngine(store_superdirs=store_dirs)
        model = get_earthmodel_from_engine(engine, store_id) 

        #TESTSOURCES===============================================
        
        offset = 3*km
        zoffset= 1000.
        ref_source = event2source(event, 'DC', strike=37.3, dip=30, rake=-3)
        center_lat = ref_source.lat
        center_lon = ref_source.lon

        negative_lat_offset, negative_lon_offset = du.lat_lon_relative_shift(
                center_lat, center_lon, -offset, -offset)

        positive_lat_offset, positive_lon_offset = du.lat_lon_relative_shift(
                center_lat, center_lon, offset, offset)

        lats=num.linspace(negative_lat_offset, positive_lat_offset, 3) 
        #lats = [ref_source.lat]

        lons=num.linspace(negative_lon_offset, positive_lon_offset, 3)
        #lons = [ref_source.lon]

        depths=num.linspace(ref_source.depth-zoffset, ref_source.depth+zoffset, 3)
        depths = [ref_source.depth]

        #strikes = num.linspace(ref_source.strike-90, ref_source.strike+90, 25)
        strikes = [ref_source.strike]

        #dips = num.linspace(ref_source.dip-45, ref_source.dip+45, 25)
        dips = [ref_source.dip]

        #rakes = num.linspace(ref_source.rake-180, ref_source.rake+180, 25)
        rakes = [ref_source.rake]

        print lats, '<- lats'
        print lons, '<- lons'
        print depths, '<- depths'
        print ref_source.lat, '<- event lat'
        print ref_source.lon, '<- event lon'
        print ref_source.depth, '<- event depth'
        print ref_source.strike, ref_source.dip, ref_source.rake, '<- event S D R'
        location_test_sources = [DCSource(lat=lat,
                               lon=lon,
                               depth=depth,
                               time=event.time,
                               strike=strike,
                               dip=dip,
                               rake=rake,
                               magnitude=event.magnitude) for strike in strikes 
                                                        for dip in dips 
                                                        for rake in rakes 
                                                        for lat in lats 
                                                        for lon in lons 
                                                        for depth in depths]

        for s in location_test_sources:
            s.regularize()
        #==========================================================

        test_case = TestCase(location_test_sources, 
                             targets, 
                             engine, 
                             store_id, 
                             test_parameters={'lat':lats, 
                                              'lon':lons, 
                                              'depth':depths})
        test_case.ref_source = ref_source

        test_case.request_data()

        print 'source location: ', test_case.ref_source
        reference_seismograms = make_reference_trace(test_case.ref_source,
                                                     test_case.targets, 
                                                     engine)
        
        extended_ref_marker = du.chop_ranges(test_case.ref_source, 
                                             test_case.targets, 
                                             test_case.store,
                                             phase_ids_start,
                                             phase_ids_end)

        print('test data marker....')
        extended_test_marker = du.chop_ranges(test_case.sources,
                                              test_case.targets,
                                              test_case.store,
                                              phase_ids_start, 
                                              phase_ids_end)
        
        test_case.test_markers = extended_test_marker
        test_case.ref_markers = extended_ref_marker

        print('chopping ref....')
        test_case.references = du.chop_using_markers(
                reference_seismograms.iter_results(), extended_ref_marker, 
                                                        t_shift_frac=0.1)

        print('chopping cand....')
        test_case.seismograms = du.chop_using_markers(
                test_case.response.iter_results(), extended_test_marker, 
                                                        t_shift_frac=0.1)

        norm = 2.
        #taper = trace.CosFader(xfade=4) # Seconds or samples?
        taper = trace.CosFader(xfrac=0.1) 
        
        z, p, k = butter(4, (2.*num.pi*2. ,0.4*num.pi*2.) , 
                           'bandpass', 
                           analog=True, 
                           output='zpk')

        z = num.array(z, dtype=complex)
        p = num.array(p, dtype=complex)
        k = num.complex(k)
        fresponse = trace.PoleZeroResponse(z,p,k)
        fresponse.regularize()
        setup = trace.MisfitSetup(norm=norm,
                                  taper=taper,
                                  domain='envelope',
                                  filter=fresponse)

        test_case.set_misfit_setup(setup)
        du.calculate_misfit(test_case)
        #test_case.yaml_dump()

        # Display results===================================================
        #test_case.plot1d(order, event.lon)
        #test_case.contourf(xkey='lon', ykey='lat')

        test_case.check_plot({'lat':ref_source.lat, 'depth':ref_source.depth})

        optics = OpticBase(test_case)
        #optics.plot_1d(fix_parameters={'lat':event.lat, 'lon':event.lon})
        optics.gmt_map(stations=True, events=True)
Exemplo n.º 3
0
def optimization(*params, **args):
    counter = params[1]
    Config = params[2]
    Wdf = params[3]
    FilterMeta = params[4]
    mint = params[5]
    maxt = params[6]
    TTTGridMap = params[7]
    Folder = params[8]
    Origin = params[9]
    ntimes = params[10]
    switch = params[11]
    ev = params[12]
    arrayfolder = params[13]
    syn_in = params[14]
    data = params[15]
    evpath = params[16]
    XDict = params[17]
    RefDict = params[18]
    workdepth = params[19]
    filterindex = params[20]
    Wdfs = params[21]

    networks = Config['networks'].split(',')
    params = num.asarray(params)
    parameter = num.ndarray.tolist(params)
    ASL_syn = []


    C  = config.Config (evpath)
    Config = C.parseConfig ('config')
    cfg = ConfigObj (dict=Config)
    if cfg.pyrocko_download() == True:
        Meta = C.readpyrockostations()#

    elif cfg.colesseo_input() == True:
        scenario = guts.load(filename=cfg.colosseo_scenario_yml())
        scenario_path = cfg.colosseo_scenario_yml()[:-12]
        Meta = C.readcolosseostations(scenario_path)
    else:
        Meta = C.readMetaInfoFile()
    l = 0
    for i in networks:

        arrayname = i
        arrayfolder = os.path.join (Folder['semb'],arrayname)

        network = Config[i].split('|')

        FilterMeta = ttt.filterStations (Meta,Config,Origin,network)

        if len(FilterMeta)  < 3: continue

        W = XDict[i]
        refshift = RefDict[i]

        FilterMeta = cmpFilterMetavsXCORR (W, FilterMeta)

        Logfile.add ('BOUNDING BOX DIMX: %s  DIMY: %s  GRIDSPACING: %s \n'
                 % (Config['dimx'],Config['dimy'],Config['gridspacing']))

        f = open('../tttgrid/tttgrid_%s_%s_%s.pkl' % (ev.time, arrayname, workdepth), 'rb')
        TTTGridMap,mint,maxt = pickle.load(f)
        f.close()


        switch = filterindex

        tw  = times.calculateTimeWindows (mint,maxt,Config,ev, switch)
        Wdf = Wdfs[l]
        semb_syn = doCalc_syn (counter,Config,Wdf,FilterMeta,mint,maxt,TTTGridMap,
                                     Folder,Origin,ntimes,switch, ev,arrayfolder, syn_in,
                                      parameter[0])
        ASL_syn.append(semb_syn)
        counter += 1
        l += 1

    sembmax_syn = sembCalc.collectSemb(ASL_syn,Config,Origin,Folder,ntimes,len(networks),switch)

    misfit_list = []  # init a list for a all the singular misfits
    norm_list = []  # init a list for a all the singular normalizations
    taper = trace.CosFader(xfade=2.0)  # Cosine taper with fade in and out of 2s.
    bw_filter = trace.ButterworthResponse(corner=0.000055,  # in Hz
                                      order=4,
                                      type='high')  # "low"pass or "high"pass
    setup = trace.MisfitSetup(description='Misfit Setup',
                              norm=2,  # L1 or L2 norm
                              taper=taper,
                              filter=bw_filter,
                              domain='time_domain')
    nsamples = len(data)
    tmin = util.str_to_time('2010-02-20 15:15:30.100')
    tr = trace.Trace(station='TEST', channel='Z',
                     deltat=0.5, tmin=tmin, ydata=data)
    syn = trace.Trace(station='TEST', channel='Z',
                     deltat=0.5, tmin=tmin, ydata=sembmax_syn)
    misfit, norm = tr.misfit(candidate=syn, setup=setup) # calculate the misfit of a single observed trace with its synthetics
    # with the setup from above
    misfit_list.append(misfit), norm_list.append(norm)  # append the misfit into a list
    global_misfit_normed = num.sqrt(num.nansum((num.asarray(misfit_list))**2) / # sum all the misfits and normalize to get a single minimizable value
                                    num.nansum((num.asarray(norm_list))**2))
    return global_misfit_normed
Exemplo n.º 4
0
    def process(self,
                event,
                timing,
                bazi=None,
                slow=None,
                restitute=False,
                *args,
                **kwargs):
        '''
      :param timing: CakeTiming. Uses the definition without the offset.
      :param fn_dump_center: filename to where center stations shall be dumped
      :param fn_beam: filename of beam trace
      :param model: earthmodel to use(optional)
      :param earthmodel to use(optional)
      :param network: network code(optional)
      :param station: station code(optional)
        '''
        logger.debug('start beam forming')
        stations = self.stations
        network_code = kwargs.get('responses', None)
        network_code = kwargs.get('network', '')
        station_code = kwargs.get('station', 'STK')
        c_station_id = (network_code, station_code)
        t_shifts = []
        lat_c, lon_c, z_c = self.c_lat_lon_z

        self.station_c = Station(lat=float(lat_c),
                                 lon=float(lon_c),
                                 elevation=float(z_c),
                                 depth=0.,
                                 name='Array Center',
                                 network=c_station_id[0],
                                 station=c_station_id[1][:5])
        fn_dump_center = kwargs.get('fn_dump_center', 'array_center.pf')
        fn_beam = kwargs.get('fn_beam', 'beam.mseed')
        if event:
            mod = cake.load_model(crust2_profile=(event.lat, event.lon))
            dist = ortho.distance_accurate50m(event, self.station_c)
            ray = timing.t(mod, (event.depth, dist), get_ray=True)

            if ray is None:
                logger.error(
                    'None of defined phases available at beam station:\n %s' %
                    self.station_c)
                return
            else:
                b = ortho.azimuth(self.station_c, event)
                if b >= 0.:
                    self.bazi = b
                elif b < 0.:
                    self.bazi = 360. + b
                self.slow = ray.p / (cake.r2d * cake.d2m)
        else:
            self.bazi = bazi
            self.slow = slow

        logger.info(
            'stacking %s with slowness %1.4f s/km at back azimut %1.1f '
            'degrees' %
            ('.'.join(c_station_id), self.slow * cake.km, self.bazi))

        lat0 = num.array([lat_c] * len(stations))
        lon0 = num.array([lon_c] * len(stations))
        lats = num.array([s.lat for s in stations])
        lons = num.array([s.lon for s in stations])
        ns, es = ortho.latlon_to_ne_numpy(lat0, lon0, lats, lons)
        theta = num.float(self.bazi * num.pi / 180.)
        R = num.array([[num.cos(theta), -num.sin(theta)],
                       [num.sin(theta), num.cos(theta)]])
        distances = R.dot(num.vstack((es, ns)))[1]
        channels = set()
        self.stacked = {}
        num_stacked = {}
        self.t_shifts = {}
        self.shifted_traces = []
        taperer = trace.CosFader(xfrac=0.05)
        if self.diff_dt_treat == 'downsample':
            self.traces.sort(key=lambda x: x.deltat)
        elif self.diff_dt_treat == 'oversample':
            dts = [t.deltat for t in self.traces]
            for tr in self.traces:
                tr.resample(min(dts))

        for tr in self.traces:
            if tr.nslc_id[:2] == c_station_id:
                continue
            tr = tr.copy(data=True)
            tr.ydata = tr.ydata.astype(
                num.float64) - tr.ydata.mean(dtype=num.float64)
            tr.taper(taperer)
            try:
                stack_trace = self.stacked[tr.channel]
                num_stacked[tr.channel] += 1
            except KeyError:
                stack_trace = tr.copy(data=True)
                stack_trace.set_ydata(num.zeros(len(stack_trace.get_ydata())))

                stack_trace.set_codes(network=c_station_id[0],
                                      station=c_station_id[1],
                                      location='',
                                      channel=tr.channel)

                self.stacked[tr.channel] = stack_trace
                channels.add(tr.channel)
                num_stacked[tr.channel] = 1

            nslc_id = tr.nslc_id

            try:
                stats = list(
                    filter(
                        lambda x: util.match_nslc('%s.%s.%s.*' % x.nsl(),
                                                  nslc_id), stations))
                stat = stats[0]
            except IndexError:
                break

            i = stations.index(stat)
            d = distances[i]
            t_shift = d * self.slow
            t_shifts.append(t_shift)
            tr.shift(t_shift)
            self.t_shifts[tr.nslc_id[:2]] = t_shift
            if self.normalize_std:
                tr.ydata = tr.ydata / tr.ydata.std()

            if num.abs(tr.deltat - stack_trace.deltat) > 0.000001:
                if self.diff_dt_treat == 'downsample':
                    stack_trace.downsample_to(tr.deltat)
                elif self.diff_dt_treat == 'upsample':
                    raise Exception(
                        'something went wrong with the upsampling, previously')
            stack_trace.add(tr)
            self.shifted_traces.append(tr)

        if self.post_normalize:
            for ch, tr in self.stacked.items():
                tr.set_ydata(tr.get_ydata() / num_stacked[ch])

        self.save_station(fn_dump_center)
        self.checked_nslc([stack_trace])
        self.save(stack_trace, fn_beam)
        return self.shifted_traces, stack_trace, t_shifts
Exemplo n.º 5
0
def optimization(*params, **args):
    counter = params[1]
    Config = params[2]
    Wdf = params[3]
    FilterMeta = params[4]
    mint = params[5]
    maxt = params[6]
    TTTGridMap = params[7]
    Folder = params[8]
    Origin = params[9]
    ntimes = params[10]
    switch = params[11]
    ev = params[12]
    arrayfolder = params[13]
    syn_in = params[14]
    data = params[15]

    params = num.asarray(params)
    parameter = num.ndarray.tolist(params)
    #    parameter = [val for sublist in parameter for val in sublist]

    semb_syn = doCalc_syn(counter, Config, Wdf, FilterMeta, mint, maxt,
                          TTTGridMap, Folder, Origin, ntimes, switch, ev,
                          arrayfolder, syn_in, parameter[0])
    misfit_list = []  # init a list for a all the singular misfits
    norm_list = []  # init a list for a all the singular normalizations
    taper = trace.CosFader(
        xfade=2.0)  # Cosine taper with fade in and out of 2s.
    bw_filter = trace.ButterworthResponse(
        corner=0.000055,  # in Hz
        order=4,
        type='high')  # "low"pass or "high"pass
    setup = trace.MisfitSetup(
        description='Misfit Setup',
        norm=2,  # L1 or L2 norm
        taper=taper,
        filter=bw_filter,
        domain='time_domain')
    for t_data, t_syn in zip(data, semb_syn):
        nsamples = len(t_data)
        tmin = util.str_to_time('2010-02-20 15:15:30.100')
        tr = trace.Trace(station='TEST',
                         channel='Z',
                         deltat=0.5,
                         tmin=tmin,
                         ydata=t_data)
        syn = trace.Trace(station='TEST',
                          channel='Z',
                          deltat=0.5,
                          tmin=tmin,
                          ydata=t_syn)
        misfit, norm = tr.misfit(
            candidate=syn, setup=setup
        )  # calculate the misfit of a single observed trace with its synthetics
        # with the setup from above
        misfit_list.append(misfit), norm_list.append(
            norm)  # append the misfit into a list
    global_misfit_normed = num.sqrt(
        num.nansum((num.asarray(misfit_list))**2)
        /  # sum all the misfits and normalize to get a single minimizable value
        num.nansum((num.asarray(norm_list))**2))
    print global_misfit_normed
    return global_misfit_normed
Exemplo n.º 6
0
from pyrocko import trace
import numpy as num

# Let's create three traces: One trace as the reference (rt) and two as test
# traces (tt1 and tt2):
ydata1 = num.random.random(1000)
ydata2 = num.random.random(1000)
rt = trace.Trace(station='REF', ydata=ydata1)
candidate1 = trace.Trace(station='TT1', ydata=ydata1)
candidate2 = trace.Trace(station='TT2', ydata=ydata2)

# Define a fader to apply before fft.
taper = trace.CosFader(xfade=5)

# Define a frequency response to apply before performing the inverse fft.
# This can be basically any funtion, as long as it contains a function called
# *evaluate*, which evaluates the frequency response function at a given list
# of frequencies.
# Please refer to the :py:class:`FrequencyResponse` class or its subclasses for
# examples.
# However, we are going to use a butterworth low-pass filter in this example.
bw_filter = trace.ButterworthResponse(corner=2, order=4, type='low')

# Combine all information in one misfit setup:
setup = trace.MisfitSetup(description='An Example Setup',
                          norm=2,
                          taper=taper,
                          filter=bw_filter,
                          domain='time_domain')

# Calculate misfits of each candidate against the reference trace:
Exemplo n.º 7
0
    # Where is your data stored?:
    datapath = '/media/usb/webnet/pole_zero/restituted_displacement/2013Mar'
    data_pile = pile.make_pile(datapath)

    # And the stations:
    stations = model.load_stations('/media/usb/webnet/meta/stations.pf')

    # Station code of the trace you want to scale agains:
    reference_id = 'NKC'

    # Frequency band to use:
    fband = {'order': 4, 'corner_hp': 1.0, 'corner_lp': 4.}

    # And a taper to avoid filtering artefacts.
    taper = trace.CosFader(xfrac=0.25)

    # Define a window to chop traces. In this case a static length of 20
    # seconds will be used and the synthetic phase arrival will be in the
    # center. The relative position can be changed between 0 (phase at t=0) and
    # 1 (phase at t=tmax).
    window = autogain.StaticLengthWindow(static_length=20., phase_position=0.5)

    #candidate_fn = 'candidates2013new.pf'
    #candidates = [m.get_event() for m in gui_util.Marker.load_markers(candidate_fn)]

    # If you have a catalog of events that you want to use, load them and make
    # and event EventCollection from those events:
    #candidates = model.load_events('events.pf')

    #event_selector = autogain.EventCollection(events=candidates)
Exemplo n.º 8
0
    def __init__(self,
                 network,
                 reduction,
                 wdir,
                 event,
                 weight=1.,
                 phase='P',
                 component='Z',
                 filter_corner=0.055,
                 filter_order=4,
                 filter_type='low',
                 misfit_norm=2,
                 taper_fade=2.0,
                 base=0,
                 sig_base=0,
                 extension='',
                 dist='Unif'):

        self.network = network
        self.reduction = reduction
        self.wdir = wdir
        self.event = event
        self.phase = phase
        self.component = component
        self.filter_corner = filter_corner
        self.filter_order = filter_order
        self.filter_type = filter_type
        self.misfit_norm = misfit_norm
        self.taper_fade = taper_fade
        self.sigmad = 1. / weight

        self.base = base
        self.sig_base = sig_base
        self.Mbase = 1

        self.extension = extension
        self.dist = dist

        self.taper = trace.CosFader(
            xfade=self.taper_fade)  # Cosine taper with fade in and out of 2s.
        self.bw_filter = trace.ButterworthResponse(
            corner=self.filter_corner,  # in Hz
            order=self.filter_order,
            type=self.filter_type)  # "low"pass or "high"pass

        self.setup = trace.MisfitSetup(
            description='Misfit Setup',
            norm=2,  # L1 or L2 norm
            taper=self.taper,
            filter=self.bw_filter,
            domain='time_domain')  # Possible domains are:
        # time_domain, cc_max_norm (correlation)
        # and frequency_domain
        self.events = []
        self.events.extend(model.load_events(filename=wdir + self.event))
        origin = gf.Source(lat=np.float(self.events[0].lat),
                           lon=np.float(self.events[0].lon))
        # print util.time_to_str(events[0].time)

        self.base_source = gf.MTSource.from_pyrocko_event(self.events[0])
        self.base_source.set_origin(origin.lat, origin.lon)
        # print util.time_to_str(self.base_source.time), events[0].lon, events[0].lat
        # sys.exit()
        self.type = 'Waveform'
Exemplo n.º 9
0
    def call(self):
        self.cleanup()
        c_station_id = ('_', 'STK')
        if self.unit == 's/deg':
            slow_factor = 1. / onedeg
        elif self.unit == 's/km':
            slow_factor = 1. / 1000.

        slow = self.slow * slow_factor
        if self.stacked_traces is not None:
            self.add_traces(self.stacked_traces)
        viewer = self.get_viewer()
        if self.station_c:
            viewer.stations.pop(c_station_id)

        stations = self.get_stations()
        if len(stations) == 0:
            self.fail('No station meta information found')

        traces = list(self.chopper_selected_traces(fallback=True))
        traces = [tr for trs in traces for tr in trs]
        visible_nslcs = [tr.nslc_id for tr in traces]
        stations = [
            x for x in stations
            if util.match_nslcs("%s.%s.%s.*" % x.nsl(), visible_nslcs)
        ]
        if not self.lat_c or not self.lon_c or not self.z_c:
            self.lat_c, self.lon_c, self.z_c = self.center_lat_lon(stations)
            self.set_parameter('lat_c', self.lat_c)
            self.set_parameter('lon_c', self.lon_c)

        self.station_c = Station(lat=float(self.lat_c),
                                 lon=float(self.lon_c),
                                 elevation=float(self.z_c),
                                 depth=0.,
                                 name='Array Center',
                                 network=c_station_id[0],
                                 station=c_station_id[1])

        viewer.add_stations([self.station_c])
        lat0 = num.array([self.lat_c] * len(stations))
        lon0 = num.array([self.lon_c] * len(stations))
        lats = num.array([s.lat for s in stations])
        lons = num.array([s.lon for s in stations])
        ns, es = ortho.latlon_to_ne_numpy(lat0, lon0, lats, lons)
        theta = num.float(self.bazi * num.pi / 180.)
        R = num.array([[num.cos(theta), -num.sin(theta)],
                       [num.sin(theta), num.cos(theta)]])
        distances = R.dot(num.vstack((es, ns)))[1]
        channels = set()
        self.stacked = {}
        num_stacked = {}
        self.t_shifts = {}
        shifted_traces = []
        taperer = trace.CosFader(xfrac=0.05)
        if self.diff_dt_treat == 'downsample':
            traces.sort(key=lambda x: x.deltat)
        elif self.diff_dt_treat == 'oversample':
            dts = [t.deltat for t in traces]
            for tr in traces:
                tr.resample(min(dts))

        for tr in traces:
            if tr.nslc_id[:2] == c_station_id:
                continue
            tr = tr.copy(data=True)
            tr.ydata = tr.ydata.astype(num.float64)
            tr.ydata -= tr.ydata.mean(dtype=num.float64)
            tr.taper(taperer)
            try:
                stack_trace = self.stacked[tr.channel]
                num_stacked[tr.channel] += 1
            except KeyError:
                stack_trace = tr.copy(data=True)
                stack_trace.set_ydata(num.zeros(len(stack_trace.get_ydata())))

                stack_trace.set_codes(network=c_station_id[0],
                                      station=c_station_id[1],
                                      location='',
                                      channel=tr.channel)

                self.stacked[tr.channel] = stack_trace
                channels.add(tr.channel)
                num_stacked[tr.channel] = 1

            nslc_id = tr.nslc_id

            try:
                stats = [
                    x for x in stations
                    if util.match_nslc('%s.%s.%s.*' % x.nsl(), nslc_id)
                ]

                stat = stats[0]
            except IndexError:
                break

            i = stations.index(stat)
            d = distances[i]
            t_shift = d * slow
            tr.shift(t_shift)
            stat = viewer.get_station(tr.nslc_id[:2])
            self.t_shifts[stat] = t_shift
            if self.normalize_std:
                tr.ydata = tr.ydata / tr.ydata.std()

            if num.abs(tr.deltat - stack_trace.deltat) > 0.000001:
                if self.diff_dt_treat == 'downsample':
                    stack_trace.downsample_to(tr.deltat)
                elif self.diff_dt_treat == 'upsample':
                    print(
                        'something went wrong with the upsampling, previously')
            stack_trace.add(tr)

            if self.add_shifted:
                tr.set_station('%s_s' % tr.station)
                shifted_traces.append(tr)

        if self.post_normalize:
            for ch, tr in self.stacked.items():
                tr.set_ydata(tr.get_ydata() / num_stacked[ch])

        self.cleanup()

        for ch, tr in self.stacked.items():
            if num_stacked[ch] > 1:
                self.add_trace(tr)

        if self.add_shifted:
            self.add_traces(shifted_traces)