示例#1
0
    def dataless_resp(self):
        """
        Function used in order to extract both instrument response and 
        instrument sensor make and model information from channel 
        information. 
        """

        sp = self.import_dataless()

        # get station information
        min_freq = 1e-4

        inventory = sp.getInventory()
        channels = inventory['channels']
        for channel in channels:
            try:
                code = channel["channel_id"]
                net, stat, loc, chan = code.split('.')
                # check for and resolve channel naming problems from IRIS
                if chan == 'MHE':
                    chan = 'LHE'
                if chan == 'MHZ':
                    chan = 'LHZ'
                if chan == 'MHN':
                    chan = 'LHN'

                sample_rate = channel['sampling_rate']
                data = sp.getPAZ(code)
                poles = data['poles']
                zeros = data['zeros']

                t_samp = 1.0 / sample_rate
                #nyquist = sampling_rate / 2.0
                nfft = sample_rate / min_freq

                cpx_resp, freqs = pazToFreqResp(poles,
                                                zeros,
                                                1,
                                                t_samp,
                                                nfft,
                                                freq=True)

                #print "cpx_resp before: ", cpx_resp
                #print "freqs before: ", freqs

                # reduce the number of values saved to database; factor of 100
                cpx_resp, freqs = (np.real(cpx_resp[::100]),
                                   np.real(freqs[::100]))
                cpx_resp, freqs = (np.abs(cpx_resp), np.abs(freqs))
                #print "cpx_resp after: ", cpx_resp
                #print "freqs after: ", freqs
                out_code = '{}_{}_{}'.format(net, stat, chan)
                #print out_code,

                self.output_SQL(out_code, cpx_resp, freqs)
                self.output_resp(out_code, cpx_resp, freqs)
            except:
                a = 5
示例#2
0
    def dataless_resp(self):
        """
        Function used in order to extract both instrument response and 
        instrument sensor make and model information from channel 
        information. 
        """
        
        sp = self.import_dataless()
        
        # get station information
        min_freq = 1e-4
        
        inventory = sp.getInventory()
        channels = inventory['channels']
        for channel in channels:
            try:
                code = channel["channel_id"]
                net, stat, loc, chan = code.split('.')
                # check for and resolve channel naming problems from IRIS
                if chan == 'MHE':
                    chan = 'LHE'
                if chan == 'MHZ':
                    chan = 'LHZ'                    
                if chan == 'MHN':
                    chan = 'LHN'                    
                    
                sample_rate = channel['sampling_rate']
                data = sp.getPAZ(code)
                poles = data['poles']
                zeros = data['zeros']

             
                t_samp = 1.0 / sample_rate
                #nyquist = sampling_rate / 2.0
                nfft = sample_rate / min_freq
                
                cpx_resp, freqs = pazToFreqResp(poles, zeros, 1,
                                                t_samp, nfft, freq=True)
                                                
                #print "cpx_resp before: ", cpx_resp
                #print "freqs before: ", freqs
                
                # reduce the number of values saved to database; factor of 100
                cpx_resp, freqs  =(np.real(cpx_resp[::100]), 
                                   np.real(freqs[::100]))
                cpx_resp, freqs  =(np.abs(cpx_resp), 
                                   np.abs(freqs))
                #print "cpx_resp after: ", cpx_resp
                #print "freqs after: ", freqs                       
                out_code = '{}_{}_{}'.format(net,stat,chan)
                #print out_code,

                self.output_SQL(out_code, cpx_resp, freqs)
                self.output_resp(out_code, cpx_resp, freqs)
            except:
                a = 5
    def dataless_resp(self):
        """
        Function used in order to extract both instrument response and 
        instrument sensor make and model information from channel 
        information. 
        """

        sp = self.import_dataless()

        # get station information
        min_freq = 1e-4

        inventory = sp.getInventory()
        channels = inventory['channels']
        for channel in channels:
            try:
                code = channel["channel_id"]
                net, stat, loc, chan = code.split('.')
                sample_rate = channel['sampling_rate']
                data = sp.getPAZ(code)
                poles = data['poles']
                zeros = data['zeros']

                t_samp = 1.0 / sample_rate
                #nyquist = sampling_rate / 2.0
                nfft = sample_rate / min_freq

                cpx_resp, freqs = pazToFreqResp(poles,
                                                zeros,
                                                1,
                                                t_samp,
                                                nfft,
                                                freq=True)

                cpx_resp, freqs = cpx_resp[::100], freqs[::100]
                out_code = '{}_{}_{}'.format(net, stat, chan)
                print out_code,
                self.output_SQL(out_code, cpx_resp, freqs)

            except:
                continue
示例#4
0
 def dataless_resp(self):
     """
     Function used in order to extract both instrument response and 
     instrument sensor make and model information from channel 
     information. 
     """
     
     sp = self.import_dataless()
     
     # get station information
     min_freq = 1e-4
     
     inventory = sp.getInventory()
     channels = inventory['channels']
     for channel in channels:
         try:
             code = channel["channel_id"]
             net, stat, loc, chan = code.split('.')
             sample_rate = channel['sampling_rate']
             data = sp.getPAZ(code)
             poles = data['poles']
             zeros = data['zeros']
             
             t_samp = 1.0 / sample_rate
             #nyquist = sampling_rate / 2.0
             nfft = sample_rate / min_freq
         
             cpx_resp, freqs = pazToFreqResp(poles, zeros, 1,
                                             t_samp, nfft, freq=True)
                                             
             cpx_resp, freqs  = cpx_resp[::100], freqs[::100]                            
             out_code = '{}_{}_{}'.format(net,stat,chan)
             print out_code,
             self.output_SQL(out_code, cpx_resp, freqs)
                             
         except:
             continue
示例#5
0
def plot_response_curves(resp, freq_msu, amp_msu, best_freep, best_damp, best_scale, msu_freep,\
msu_damp, amp_average, amp_label, seismometer, sac_pz_file):

                             # build an array of zeros with same length as freq_msu

    amp_predicted = np.zeros_like(freq_msu)

                             # loop over the frequencies present in the msu data file one at a time
                             # to find the amplitudes predicted for a given frequency 
                             # based on the best resp file

    for i, freq in enumerate(freq_msu):
        amp_predicted[i] = sim.paz2AmpValueOfFreqResp(resp, freq) 

                             # this code taken straight from the Obspy webpage examples 
                             # numbers for obspy to create a resp curve, based on an fft of a time series
                             # with sample rate of 0.01

    samp_rate = 0.01
    npts = 16384

                             # obtain "continuous" amp and freq values from obsby function to display continuous response curve

    poles = resp['poles']
    zeros = resp['zeros']
    h, f = sim.pazToFreqResp(poles, zeros, best_scale, samp_rate, npts, freq=True)

                             # plotting amp vs freq

    plt.figure()

#plt.subplot(121)
                             # plot the continuous response curve, and the msu data, 

    plt.loglog(f, abs(h), freq_msu, amp_msu, 'go', markersize=6 )

                             # plot the predicted amplitudes at the MSU frequencies

    plt.loglog(freq_msu, amp_predicted, 'ro', markersize=4 )

                             # labels

    plt.xlabel('Frequency [Hz]')

                             # this str function is part of the standard Python, no need to "import" a special "package"

    plt.ylabel( str(amp_label) )
    plt.suptitle('Frequency vs Amplitude: Channel ' + str(seismometer) )

                             # plot over range from 2/3 * minimum frequency to 2.0 * maximum frequency  
                             # and over range from 2/3 * minimum amplitude to 2.0 * maximum amplitude  

    plx_min = 0.05 # freq_msu[0] * 0.66
    plx_max = 40.0 # freq_msu[len(freq_msu) - 1] * 2.00
    ply_min = 0.10 # amp_msu[0] * 0.66
    ply_max = 1000.0 # amp_msu[len(freq_msu) - 1] * 2.00
    plt.axis([plx_min, plx_max, ply_min, ply_max])

    freep_per = 100. * ( abs ( best_freep - msu_freep ) / msu_freep )
    damp_per = 100. * ( abs ( best_damp - msu_damp ) / msu_damp )
    scale_per = 100. * ( abs ( best_scale - amp_average ) / amp_average )
    rsp = ""
    cdt = "Calibration date = "+ (time.strftime("%d/%m/%Y %H:%M:%S"))
    tfp = "free period = %.3f Hz (%.2f%% MSU: %.3f)" % ( 1./best_freep, freep_per, 1./msu_freep )
    print ( "\n" )
    print tfp
    tdr = "damping = %.3f (%.2f%% MSU: %.3f)" % ( best_damp, damp_per, msu_damp )
    print tdr
    tsf = "scale = %.2f V.m/sec( Avg. amp: %.2f)" % ( best_scale, amp_average )
    print tsf
    spz = "File: %s" % ( sac_pz_file )
    #f.write("ZEROS {}\n".format(len(resp['zeros']) + 1 ))
    zzz = "ZEROS: {}".format(len(resp['zeros']) + 1 )
     #   f.write("POLES {}\n".format(len(resp['poles'])))
    ppp = "POLES {}\n".format(len(resp['poles']))
    for pole in resp['poles']:
      #      f.write("{:e} {:e}\n".format(pole.real, pole.imag))
        rsp = rsp+"real:  {:e} Imaginary:  {:e}\n".format(pole.real, pole.imag)
       # f.write("CONSTANT {:e}".format(resp['gain']))
    print "\nsensor gain constant {:e} V.m/sec".format(resp['gain'])
 

                             # post results as text lines on the plot

    xtext = plx_min * 7.
    ytext = ply_min * 60
    plt.text( xtext, ytext, cdt )
    ytext = ply_min * 40
    plt.text( xtext, ytext, tfp )
    ytext = ply_min * 30
    plt.text( xtext, ytext, tdr )
    ytext = ply_min * 20
    plt.text( xtext, ytext, tsf )
    ytext = ply_min * 10
    plt.text( xtext, ytext, zzz )
    ytext = ply_min * 5
    plt.text( xtext, ytext, ppp )
    ytext = ply_min * 2
    plt.text( xtext, ytext, rsp )

                             # post some symbols and text for a legend

    amp_symbol = np.zeros(1)
    amp_symbol[0] = best_scale * 1.0
    freq_symbol = np.zeros(1)
    freq_symbol[0] = freq_msu[0]
    plt.loglog(freq_symbol, amp_symbol, 'go', markersize=6 )
    plt.text( freq_symbol[0] * 1.1, amp_symbol[0], 'Measurement', va='center' )
    amp_symbol[0] = best_scale * 0.70
    freq_symbol[0] = freq_msu[0]
    plt.loglog(freq_symbol, amp_symbol, 'ro', markersize=4 )
    plt.text( freq_symbol[0] * 1.1, amp_symbol[0], 'Model Best Fit', va='center' )
    plt.grid(True, which='major')
    plt.grid(True, which='minor')

    fileopts = getoptions()           # Use the getoptions def to parse the command line options.
    wdir     = fileopts[0]            # working directory

    fig = wdir+"\\"+seismometer + '_freq_v_amp' + '.png' # Place it in current working directory - drb
    txt = "best-fit freq. vs ampl. plot: %s" % ( fig )
    print "\n"
    print txt
    plt.savefig( fig )

    plt.show()
#    plt.close()


                             # plotting phase vs freq, not sure how much this can be trusted

#plt.subplot(122)

    plt.figure()

                             #take negative of imaginary part

    phase = np.unwrap(np.arctan2(-h.imag, h.real))
    plt.semilogx(f, phase)
    plt.xlabel('Frequency [Hz]')

    plt.ylabel('Phase [radians]')

                             # title, centered above both subplots

    plt.suptitle('Frequency vs Phase: Seismometer ' + str(seismometer) )
    plt.axis([0.004, 100, -3.5, 0.5])

                             # make more room in between subplots for the ylabel of right plot

#plt.subplots_adjust(wspace=0.3)
    plt.grid(True, which='major')
    plt.grid(True, which='minor')
    fig = wdir+"\\"+ seismometer + '_freq_v_phase' + '.png' # save in data directory
    txt = "plotted best-fit frequency vs phase results - saved in file: %s" % ( fig )
    print "\n"
    print txt
    plt.savefig( fig )
示例#6
0
def correct_response(st, removeResp=False, removePAZ=False, simPAZ=False, pre_filt=None, cornFreq=0.0083):
    """
    Correct the seismometer response.
    
    Seismometer response is given in either a dictionary ``removeResp''
    or a dictionary ``removePAZ''. ``removeResp has precedence. The
    dictionaries have the following structure

    removeResp: dictionary with Response information to be removed
        has the following keys:
        respfile: (str) filename of evalresp response file.
        units: (str) Units to return response in. Can be either DIS, VEL or ACC
        start_stage: (int) integer stage numbers of start stage (<0 causes
            default evalresp bahaviour).
        stop_stage: (int) integer stage numbers of stop stage
    removePAZ: dictionary with poles and zeros to be removed has the following
        keys:
            poles: (list of complex numbers) location of poles
            zeros: (list of complex numbers) location of zeros
            gain: (float) gain
            sensitivity: (float) sensitivity
        It can easily be retrieved with obspy.arclink.client.Client.getPAZ

    if ``removeResp'' is given the response of each trace must be present in
    the respfile. If ``removePAZ'' is used the response is assumed to be the
    same for all traces in the stream.
    A filter specified in pre_filt can be applied in to avoid amplification of
    noise.
    The instrument to be simulated is either described in the dictionary simPAZ
    or if simPAZ is False by the corner frequency ``cornFreq''. Response
    correction is done in place and original data is overwritten.
    
    The input stream ``st'' should be demeaned and tapered.
    
    :type st: obspy.core.stream.Stream
    :param st: data stream to be corrected
    :type removeResp: dict
    :param removeResp: Response information to be removed
    :type removePAZ: dict
    :param removePAZ: Response information to be removed
    :type simPAZ: dict
    :param simPAZ: Response information to be simulated
    :type cornFreq: float
    :param cornFreq: corner frequency of instrument to be simulated
    :type pre_filt: list
    :param pre_filt: 4 corners of the filter
    """
    
    for tr in st:
        starttime = tr.stats['starttime']
        endtime = tr.stats['endtime']
        network = tr.stats['network']
        station = tr.stats['station']
        channel = tr.stats['channel']
        location = tr.stats['location']
        length = tr.stats['npts']
        sampling_rate = tr.stats['sampling_rate']
        np2l = nextpow2(2.*length)
        
        if not simPAZ:
            simPAZ = cornFreq2Paz(cornFreq, damp=0.70716)
        simresp, freqs = np.conj(pazToFreqResp(simPAZ['poles'], simPAZ['zeros'],
                          scale_fac=simPAZ['gain']*simPAZ['sensitivity'],
                          t_samp=1./sampling_rate,
                          nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj()
        
        if removeResp:
            freqresp, freqs = evalresp(1./sampling_rate,np2l,removeResp['respfile'],
                                starttime, network=network, station=station,
                                channel=channel, locid=location,
                                start_stage=removeResp['start_stage'],
                                stop_stage=removeResp['stop_stage'],
                                units=removeResp['units'], freq=True)
        else:
            freqresp, freqs = np.conj(pazToFreqResp(removePAZ['poles'], removePAZ['zeros'],
                          scale_fac=removePAZ['gain']*removePAZ['sensitivity'],
                          t_samp=1./sampling_rate,
                          nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj()
        
        ftr = np.fft.rfft(tr.data,n=np2l)
        ftr /= freqresp
        ftr[0] = 0.j  # correct the NaN in the DC component
        ftr *= simresp
        
        if pre_filt:
            ftr *= c_sac_taper(freqs, flimit=pre_filt)

        tr.data = np.fft.irfft(ftr)
        tr.trim(starttime,endtime)
    
    return   
def correct_response(st,
                     removeResp=False,
                     removePAZ=False,
                     simPAZ=False,
                     pre_filt=None,
                     cornFreq=0.0083):
    """
    Correct the seismometer response.
    
    Seismometer response is given in either a dictionary ``removeResp''
    or a dictionary ``removePAZ''. ``removeResp has precedence. The
    dictionaries have the following structure

    removeResp: dictionary with Response information to be removed
        has the following keys:
        respfile: (str) filename of evalresp response file.
        units: (str) Units to return response in. Can be either DIS, VEL or ACC
        start_stage: (int) integer stage numbers of start stage (<0 causes
            default evalresp bahaviour).
        stop_stage: (int) integer stage numbers of stop stage
    removePAZ: dictionary with poles and zeros to be removed has the following
        keys:
            poles: (list of complex numbers) location of poles
            zeros: (list of complex numbers) location of zeros
            gain: (float) gain
            sensitivity: (float) sensitivity
        It can easily be retrieved with obspy.arclink.client.Client.getPAZ

    if ``removeResp'' is given the response of each trace must be present in
    the respfile. If ``removePAZ'' is used the response is assumed to be the
    same for all traces in the stream.
    A filter specified in pre_filt can be applied in to avoid amplification of
    noise.
    The instrument to be simulated is either described in the dictionary simPAZ
    or if simPAZ is False by the corner frequency ``cornFreq''. Response
    correction is done in place and original data is overwritten.
    
    The input stream ``st'' should be demeaned and tapered.
    
    :type st: obspy.core.stream.Stream
    :param st: data stream to be corrected
    :type removeResp: dict
    :param removeResp: Response information to be removed
    :type removePAZ: dict
    :param removePAZ: Response information to be removed
    :type simPAZ: dict
    :param simPAZ: Response information to be simulated
    :type cornFreq: float
    :param cornFreq: corner frequency of instrument to be simulated
    :type pre_filt: list
    :param pre_filt: 4 corners of the filter
    """

    for tr in st:
        starttime = tr.stats['starttime']
        endtime = tr.stats['endtime']
        network = tr.stats['network']
        station = tr.stats['station']
        channel = tr.stats['channel']
        location = tr.stats['location']
        length = tr.stats['npts']
        sampling_rate = tr.stats['sampling_rate']
        np2l = nextpow2(2. * length)

        if not simPAZ:
            simPAZ = cornFreq2Paz(cornFreq, damp=0.70716)
        simresp, freqs = np.conj(
            pazToFreqResp(
                simPAZ['poles'],
                simPAZ['zeros'],
                scale_fac=simPAZ['gain'] * simPAZ['sensitivity'],
                t_samp=1. / sampling_rate,
                nfft=np2l,
                freq=True))  #see Doc of pazToFreqResp for reason of conj()

        if removeResp:
            freqresp, freqs = evalresp(1. / sampling_rate,
                                       np2l,
                                       removeResp['respfile'],
                                       starttime,
                                       network=network,
                                       station=station,
                                       channel=channel,
                                       locid=location,
                                       start_stage=removeResp['start_stage'],
                                       stop_stage=removeResp['stop_stage'],
                                       units=removeResp['units'],
                                       freq=True)
        else:
            freqresp, freqs = np.conj(
                pazToFreqResp(
                    removePAZ['poles'],
                    removePAZ['zeros'],
                    scale_fac=removePAZ['gain'] * removePAZ['sensitivity'],
                    t_samp=1. / sampling_rate,
                    nfft=np2l,
                    freq=True))  #see Doc of pazToFreqResp for reason of conj()

        ftr = np.fft.rfft(tr.data, n=np2l)
        ftr /= freqresp
        ftr[0] = 0.j  # correct the NaN in the DC component
        ftr *= simresp

        if pre_filt:
            ftr *= c_sac_taper(freqs, flimit=pre_filt)

        tr.data = np.fft.irfft(ftr)
        tr.trim(starttime, endtime)

    return