Beispiel #1
0
def _calc_resp(calfile, nfft, sampfreq):
    """
    Calculate transfer function of known system.

    :type calfile: str
    :param calfile: file containing poles, zeros and scale factor for known
        system or a dictionary with poles and zeros information (with keys
        ``'poles'``, ``'zeros'`` and ``'sensitivity'``).
    :returns: complex transfer function, array of frequencies
    """
    # test if calfile is a paz dict
    if isinstance(calfile, dict):
        paz = calfile
    # or read paz file if a filename is specified
    else:
        paz = dict()
        paz['poles'], paz['zeros'], paz['sensitivity'] = read_paz(calfile)
    # calculate transfer function
    h, f = paz_to_freq_resp(paz['poles'],
                            paz['zeros'],
                            paz['sensitivity'],
                            1.0 / sampfreq,
                            nfft,
                            freq=True)
    return h, f
Beispiel #2
0
def computeresp(resp, delta, lenfft):
    respval = paz_to_freq_resp(resp['poles'],
                               resp['zeros'],
                               resp['sensitivity'] * resp['gain'],
                               t_samp=delta,
                               nfft=lenfft,
                               freq=False)
    respval = np.absolute(respval * np.conjugate(respval))
    respval = respval[1:]
    return respval
Beispiel #3
0
def _calc_resp(calfile, nfft, sampfreq):
    """
    Calculate transfer function of known system.

    :type calfile: str
    :param calfile: file containing poles, zeros and scale factor for known
        system
    :returns: complex transfer function, array of frequencies
    """
    # calculate transfer function
    poles, zeros, scale_fac = read_paz(calfile)
    h, f = paz_to_freq_resp(poles, zeros, scale_fac, 1.0 / sampfreq, nfft, freq=True)
    return h, f
Beispiel #4
0
def computeresp(resp, delta, lenfft):
    respval, freq = paz_to_freq_resp(resp['poles'],
                                     resp['zeros'],
                                     resp['sensitivity'] * resp['gain'],
                                     t_samp=delta,
                                     nfft=lenfft,
                                     freq=True)
    idx = np.argmin(np.abs(freq - .1))

    respval = np.absolute(respval * np.conjugate(respval))
    respval *= 1. / respval[idx]
    respval = respval[1:] * resp['sensitivity']**2
    respval = respval.real
    return respval
Beispiel #5
0
def _calc_resp(calfile, nfft, sampfreq):
    """
    Calculate transfer function of known system.

    :type calfile: str
    :param calfile: file containing poles, zeros and scale factor for known
        system
    :returns: complex transfer function, array of frequencies
    """
    # calculate transfer function
    poles, zeros, scale_fac = read_paz(calfile)
    h, f = paz_to_freq_resp(poles, zeros, scale_fac, 1.0 / sampfreq,
                            nfft, freq=True)
    return h, f
Beispiel #6
0
def _calc_resp(calfile, nfft, sampfreq):
    """
    Calculate transfer function of known system.

    :type calfile: str
    :param calfile: file containing poles, zeros and scale factor for known
        system or a dictionary with poles and zeros information (with keys
        ``'poles'``, ``'zeros'`` and ``'sensitivity'``).
    :returns: complex transfer function, array of frequencies
    """
    # test if calfile is a paz dict
    if isinstance(calfile, dict):
        paz = calfile
    # or read paz file if a filename is specified
    else:
        paz = dict()
        paz['poles'], paz['zeros'], paz['sensitivity'] = read_paz(calfile)
    # calculate transfer function
    h, f = paz_to_freq_resp(paz['poles'], paz['zeros'], paz['sensitivity'],
                            1.0 / sampfreq, nfft, freq=True)
    return h, f
def test_simple_response():
    import matplotlib.pyplot as plt
    try:
        from obspy.signal.invsim import paz_to_freq_resp
    except:
        from obspy.signal.invsim import pazToFreqResp as paz_to_freq_resp
    try:
        from obspy.signal.invsim import paz_2_amplitude_value_of_freq_resp
    except:
        from obspy.signal.invsim import paz2AmpValueOfFreqResp as paz_2_amplitude_value_of_freq_resp

    #{'zeros': [(-31.617+0j), 0j, 0j], 'poles': [(-0.1486-0.1486j), (-0.1486+0.1486j), (-336.766-136.656j), (-336.766+136.656j), (-47.0636+0j), (-2469.36+0j)], 'gain': 491884000.0}

    N = 1024
    sample_rate = 100.
    normalization_frequency = 1.0
    normalization_factor = 1.6
    poles = [(-5.026548 + 3.769911j), (-5.026548 - 3.769911j)]
    zeros = [complex(0.), complex(0.)]
    amplitude, frequency = paz_to_freq_resp(poles,
                                            zeros,
                                            1.0,
                                            1.0 / sample_rate,
                                            2 * N,
                                            freq=True)
    print len(amplitude)
    print np.max(amplitude)
    plt.loglog(frequency, abs(amplitude), basex=10, basey=10)
    plt.show()
    paz = {"poles": poles, "zeros": zeros, "gain": normalization_factor}
    calculated_A0 = paz_2_amplitude_value_of_freq_resp(
        paz, normalization_frequency)
    if abs(calculated_A0 - 1.0) > 1e-06:
        print "Discrepancy, calculated normalized amplitude: {}, \
               normalization factor {} at normalization frequency {}\
               does not normalize the frequency spectrum."                                                          .\
               format(calculated_A0, normalization_factor, normalization_frequency)
inst1 = Response(desc=instName, units='Radians')
inst1.zeros = zer1
inst1.poles = pol1
#norm_freq=0.02
norm_freq = 1.0
n1, f1 = inst1.check_normalization(freq=norm_freq, nfft=2**26, t_sample=0.001)
scale_fac = 1.0 / n1
print('The A0 norm factor is: ' + str(scale_fac) + ' for f=' + str(norm_freq))
#check the value
inst1.a0 = 1.0 / n1
A01 = inst1.a0
n, f = inst1.check_normalization(freq=norm_freq, nfft=2**26, t_sample=0.001)
print('This should be close to 1: ' + str(1.0 / n))
h1, f1 = paz_to_freq_resp(inst1.poles,
                          inst1.zeros,
                          scale_fac,
                          0.001,
                          2**26,
                          freq=True)
print(h1)

# and now for the second resp....
inst2 = Response(desc=instName, units='Radians')
inst2.zeros = zer2
inst2.poles = pol2
#norm_freq=0.02
norm_freq = 1.0
n2, f2 = inst2.check_normalization(freq=norm_freq, nfft=2**24, t_sample=0.001)
scale_fac = 1.0 / n2
print('The A0 norm factor is: ' + str(scale_fac) + ' for f=' + str(norm_freq))
#check the value
inst2.a0 = 1.0 / n2
Beispiel #9
0
inst.poles = pol
#norm_freq=0.05
#norm_freq=0.02
norm_freq = 1.0
n, f = inst.check_normalization(freq=norm_freq, nfft=2**26, t_sample=0.001)
scale_fac = 1.0 / n
print('The A0 norm factor is: ' + str(scale_fac) + ' for f=' + str(norm_freq))

#check the value
inst.a0 = 1.0 / n
n, f = inst.check_normalization(freq=norm_freq, nfft=2**26, t_sample=0.001)
print('This should be close to 1: ' + str(1.0 / n))

h, f = paz_to_freq_resp(inst.poles,
                        inst.zeros,
                        scale_fac,
                        0.001,
                        2**26,
                        freq=True)

plt.figure()
plt.subplot(121)
plt.semilogx(f, abs(h))
plt.xlabel('Frequency [Hz]')
plt.ylabel('Amplitude')
plt.grid(which='both', linestyle=':')
#plt.xlim([0.2,40])

plt.subplot(122)
# take negative of imaginary part
phase = np.unwrap(np.arctan2(h.imag, h.real))
plt.semilogx(f, phase)
import numpy as np
import matplotlib.pyplot as plt

from obspy.signal.invsim import paz_to_freq_resp


poles = [-4.440 + 4.440j, -4.440 - 4.440j, -1.083 + 0.0j]
zeros = [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j]
scale_fac = 0.4

h, f = paz_to_freq_resp(poles, zeros, scale_fac, 0.005, 16384, freq=True)

plt.figure()
plt.subplot(121)
plt.loglog(f, abs(h))
plt.xlabel('Frequency [Hz]')
plt.ylabel('Amplitude')

plt.subplot(122)
# 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 [radian]')
# title, centered above both subplots
plt.suptitle('Frequency Response of LE-3D/1s Seismometer')
# make more room in between subplots for the ylabel of right plot
plt.subplots_adjust(wspace=0.3)
plt.show()
Beispiel #11
0
def plot_Freq_Amp_Phase(pltfile, paz, sName, type):
    poles = paz['poles']
    zeros = paz['zeros']
    scale_fac = paz['gain'] * paz['seismometer_gain']

    if (1000 <= type and type < 2000):
        h, f = paz_to_freq_resp(poles, zeros, scale_fac, 0.005, 65536 * 8, freq=True)
    elif (2000 <= type):
        h, f = paz_to_freq_resp(poles, zeros, scale_fac, 0.001, 65536 * 8, freq=True)
    else:
        h, f = paz_to_freq_resp(poles, zeros, scale_fac, 0.001, 65536 * 8, freq=True)

    font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=12)
    fontTitle = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=18)
    plt.figure(figsize=(16, 12))
    # plt.xlim(0.001,  100)
    plt.subplot(211)
    plt.grid(linestyle=':')
    plt.loglog(f, abs(h))
    plt.xlabel('频率[Hz]', fontproperties=font)
    if 1000 <= type < 2000:
        plt.ylabel('增益[V/(m/s)]', fontproperties=font)
    elif 2000 <= type:
        plt.ylabel('增益[V/(m/s**2)]', fontproperties=font)
    else:
        plt.ylabel('增益', fontproperties=font)
    plt.subplot(212)
    plt.grid(linestyle=':')
    phase = np.unwrap(np.angle(h))
    fTt = 0
    for p0 in phase:
        fTt += p0
    fAver = fTt / len(phase)
    if (fAver <= -np.pi):
        phase += 2 * np.pi
    elif (fAver > np.pi):
        phase -= 2 * np.pi

    import datetime
    timestr = datetime.datetime.now().strftime('%Y-%m-%d')
    timestr = "Created by 泰德, " + timestr
    x0 = '                                                                   频率[Hz]                                         ' + timestr

    plt.semilogx(f, phase)
    # plt.xlabel('频率[Hz]',fontproperties=font)
    plt.xlabel(x0, fontproperties=font)
    plt.ylabel('相位[rad]', fontproperties=font)
    # ticks and tick labels at multiples of pi
    plt.yticks(
        [-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi],
        [r'$-\pi$', r'$-\frac{\pi}{2}$', '$0$', r'$\frac{\pi}{2}$', r'$\pi$'])
    plt.ylim(-0.2 - np.pi, np.pi + 0.2)
    # title, centered above both subplots
    if (1000 <= type and type < 2000):
        plt.suptitle('%s 地震计幅频相频响应' % (sName), fontproperties=fontTitle)
    elif (2000 <= type):
        plt.suptitle('%s 加速度计幅频相频响应' % (sName), fontproperties=fontTitle)
    else:
        plt.suptitle('仪器 %s 幅频相频响应' % (sName), fontproperties=fontTitle)

    # import datetime
    # timestr = datetime.datetime.now().strftime('%Y-%m-%d')
    # timestr = "Created by TAIDE, " + timestr
    # plt.text(10.6,-4.2,timestr,fontsize=12)

    # make more room in between subplots for the ylabel of right plot
    plt.subplots_adjust(wspace=0.1)
    plt.savefig(pltfile)
    plt.close('all')
Beispiel #12
0
# We can do the same thing for an STS-1 response
paz2 = {
    'gain':
    3948.58,
    'zeros': [0, 0],
    'poles': [
        -0.01234 - 0.01234j, -0.01234 + 0.01234j, -39.18 - 49.12j,
        -39.18 + 49.12j
    ],
    'sensitivity':
    3.3554432 * 10**9
}

respval = paz_to_freq_resp(paz2['poles'],
                           paz2['zeros'],
                           paz2['sensitivity'],
                           t_samp=1. / sampling_rate,
                           nfft=lenfft,
                           freq=False)
respval = np.absolute(respval * np.conjugate(respval))
respval = respval[1:]
respval = respval / respval[1]
AerrSTS1 = 10. * np.log10(((AS * AE * (respval))**2) / freq)

fig = plt.figure(1)

plt.subplot(2, 1, 1)
plt.semilogx(perNLNM, NLNM, label='NLNM/NHNM', color='.7', linewidth=2.)
plt.semilogx(perNHNM, NHNM, color='.7', linewidth=2.)
plt.semilogx(1. / freq,
             A,
             label='Brune Spectra Mw=' + str(Mw) + ' at ' + str(Rrs / 1000.) +
paz2['gain'] = 1. / paz_2_amplitude_value_of_freq_resp(paz2, .1)
# this is from sensor test suite
paz3 = {
    'zeros': [0.000000E+00 + 0.000000E+00j, 0.000000E+00 + 0.000000E+00j],
    'poles': [
        -1.263000E-02 + 1.265000E-02j, -1.263000E-02 + -1.265000E-02j,
        -3.620107E+01 + 6.850121E+01j, -3.620107E+01 + -6.850121E+01j
    ],
    'gain':
    1
}
paz3['gain'] = 1. / paz_2_amplitude_value_of_freq_resp(paz3, .1)

h1, f1 = paz_to_freq_resp(paz1['poles'],
                          paz1['zeros'],
                          paz1['gain'],
                          1. / 200.,
                          2**18,
                          freq=True)
h2, f2 = paz_to_freq_resp(paz2['poles'],
                          paz2['zeros'],
                          paz2['gain'],
                          1. / 200.,
                          2**18,
                          freq=True)
h3, f3 = paz_to_freq_resp(paz3['poles'],
                          paz3['zeros'],
                          paz3['gain'],
                          1. / 200.,
                          2**18,
                          freq=True)
#plotting....
Beispiel #14
0
 def _get_response_from_paz_dict(self, tr):
     paz = self.metadata
     resp = paz_to_freq_resp(paz['poles'], paz['zeros'],
                             paz['gain'] * paz['sensitivity'],
                             self.delta, nfft=self.nfft)
     return resp
norm_freq = 1.0

#define the poles and zeros.
#tr-120 NRL paz
pol = [-32.55, -142, -364 + 404j, -364 - 404j]
zer = [-31.63, -350]
instName = 'TR120 NRL high-f paz'
inst = Response(desc=instName, units='Radians')
inst.zeros = zer
inst.poles = pol
n, f = inst.check_normalization(freq=norm_freq, nfft=2**26, t_sample=0.001)
scale_fac = 1.0 / n
h1, f1 = paz_to_freq_resp(inst.poles,
                          inst.zeros,
                          scale_fac,
                          0.001,
                          2**26,
                          freq=True)

#tr-120 one high-f cal signal
pol = [-28.15385, -146.36053, -313.52396 - 429.04933j, -313.52396 + 429.04933j]
zer = [-27.63939, -467.15426]
instName = 'TR120 one high-f paz'
inst = Response(desc=instName, units='Radians')
inst.zeros = zer
inst.poles = pol
n, f = inst.check_normalization(freq=norm_freq, nfft=2**26, t_sample=0.001)
scale_fac = 1.0 / n
h2, f2 = paz_to_freq_resp(inst.poles,
                          inst.zeros,
                          scale_fac,
Beispiel #16
0
def simple_response(sample_rate, response):
    """ 
        Given the obspy ResponseStages, calculate the simple response.
        i.e. the natural frequency, damping factor, low corner, high corner, and overall gain
    """
    EPSILON = 5e-02  # tolerance for normalized amplitude of a pole-zero stage being off from 1.0
    NFREQ = 2048  # number of frequency points to calculate amplitude spectrum for.
    delta_t = 1.0 / sample_rate
    poles = []
    zeros = []

    # take the normalization frequency from the InstrumentSensitivity
    normalization_frequency = response.instrument_sensitivity.frequency
    signal_input_units = response.instrument_sensitivity.input_units

    # Gather all the poles and zeros, and the stage gains.
    total_gain = 1
    for stage in response.response_stages:
        if hasattr(stage, "stage_gain"):
            stage_gain = stage.stage_gain
            if hasattr(stage, "zeros"):
                zeros.extend(stage.zeros)
            if hasattr(stage, "poles"):
                poles.extend(stage.poles)
                # check if normalization factor is correct
                paz = {
                    "poles": stage.poles,
                    "zeros": stage.zeros,
                    "gain": stage.normalization_factor
                }
                calculated_amplitude = paz_2_amplitude_value_of_freq_resp(
                    paz, stage.normalization_frequency)
                if np.abs(calculated_amplitude - 1.0) > EPSILON:
                    logging.warning("Warning: normalized amplitude at normalization frequency  is {}, i.e. {:6.3f}% from 1,\
                           using calculated gain value {:5.2f} vs {:5.2f} instead"                                                                                  .\
                           format(calculated_amplitude, 100*(calculated_amplitude-1)/1,calculated_amplitude*stage.stage_gain, stage.stage_gain))
                    stage_gain = calculated_amplitude * stage.stage_gain
            total_gain = total_gain * stage_gain

    # log a warning if the total_gain is not similar to the reported instrument_sensitivity
    if np.abs((total_gain - response.instrument_sensitivity.value) /
              response.instrument_sensitivity.value) > EPSILON:
        logging.warning("Warning: Reported sensitivity: {:5.2f}, \
                        Calculated sensitivity: {:5.2f}"                                                        . \
              format(response.instrument_sensitivity.value, total_gain))

    #  calculate overall normalization factor at normalization frequency
    paz = {"poles": poles, "zeros": zeros, "gain": 1.0}
    calculated_amplitude = paz_2_amplitude_value_of_freq_resp(
        paz, normalization_frequency)
    normalization_factor = 1.0 / calculated_amplitude

    # calculate the normalized frequency spectrum at NFREQ frequency points
    amplitude, frequency = paz_to_freq_resp(poles,
                                            zeros,
                                            normalization_factor,
                                            delta_t,
                                            2 * NFREQ,
                                            freq=True)

    # determine the high and low frequency corners from the amplitude spectrum
    logging.debug("Determining frequency corners")
    f_hp, f_lp = compute_corners(amplitude, frequency)
    logging.debug(("f_hp: {}, f_lp: {}").format(f_hp, f_lp))

    # velocity transducer or acceleration?
    if signal_input_units == "M/S" or signal_input_units == "M":
        sensor_type = "VEL"
    else:
        sensor_type = "ACC"

    # try to determine natural frequency and damping factor from poles and corners
    logging.debug("Determining natural frequency and damping factor")
    natural_frequency, damping = natural_frequency_and_damping(
        poles, f_hp, f_lp, sensor_type=sensor_type)
    logging.debug(("fn: {}, damp: {}").format(natural_frequency, damping))

    # some sanity checks, limit f_lp to 40% of Nyquist, f_hp must be <= f_lp
    if f_lp > 0.4 * sample_rate:
        f_lp = 0.4 * sample_rate
    if f_hp > f_lp:
        f_hp = f_lp

    return natural_frequency, damping, f_hp, f_lp, total_gain
Beispiel #17
0
sens = []
for sta in stas:
    f = open('Results_Swept_Sine' + sta, 'r')
    for line in f:
        line = line.split(',')
        fs.append(float(line[4]))
        hs.append(float(line[5]))
        sens.append(float(line[6]))
        chans.append(line[0])
    f.close()

#####################################################Make mean

for triple in zip(fs, hs, sens):
    paz = corn_freq_2_paz(triple[0], triple[1])
    h, f = paz_to_freq_resp(paz['poles'], paz['zeros'], 1., 1. / 1000., 2**14,
                            True)
    h *= triple[2]
    if 'hmean' not in vars():
        hmean = h
    else:
        hmean += h

hmean *= 1. / 9.

fig = plt.figure(1, figsize=(12, 12))
ax = fig.add_subplot(111)
plt.subplots_adjust(hspace=0.001)
for idx, quad in enumerate(zip(chans, fs, hs, sens)):
    if quad[0] == 'HHZ':
        color = 'C0'
    elif quad[0] == 'HHN':
Beispiel #18
0
    f, p2 = signal.welch(tr.data,
                         fs=tr.stats.sampling_rate,
                         nperseg=NFFT,
                         noverlap=1024)
    f = f[1:]
    p2 = p2[1:]
    if 'p' in vars():
        p = np.vstack((p, p2))
    else:
        p = p2

p = np.mean(p, axis=0)
Tfnom, fnom = paz_to_freq_resp(sts6paz.poles,
                               sts6paz.zeros,
                               sts6paz.stage_gain *
                               sts6paz.normalization_factor,
                               1. / st[0].stats.sampling_rate,
                               NFFT,
                               freq=True)
Tfnom = Tfnom[1:] * (2**26) / 40.
plt.semilogx(1. / f,
             10. * np.log10(p / np.abs(Tfnom)**2),
             label='Q330HR Noise with STS-6 Response')
Tfnom, fnom = paz_to_freq_resp(sts2paz.poles,
                               sts2paz.zeros,
                               sts2paz.stage_gain *
                               sts2paz.normalization_factor,
                               1. / st[0].stats.sampling_rate,
                               NFFT,
                               freq=True)
Tfnom = Tfnom[1:] * (2**26) / 40.
Beispiel #19
0
# create list of stations
stationList = list(set([tr.stats.station for tr in st.traces]))

# define PAZ values for transfer function
# example with Lennartz 3D/5s instruments
LEpoles = [(-0.888 + 0.888j), (-0.888 - 0.888j), (-0.29 + 0j)]
LEzeros = [0j, 0j, 0j]
LEscale = 400.0
sampfreq = 100.
nfft = 4096
# maybe 4096 (adjust also in psd and csd) to get more long period spectrum

# calculate transfer function
T1 = paz_to_freq_resp(LEpoles,
                      LEzeros,
                      LEscale,
                      1.0 / sampfreq,
                      nfft,
                      freq=True)

# iterate over each station combination

for stat1 in stationList:
    for stat2 in stationList:
        if stat1 == stat2:
            continue

        # select traces
        st1 = st.select(station=stat1)
        st2 = st.select(station=stat2)

        # calculate power spectral density and cross-spectrum
Beispiel #20
0
 def _get_response_from_paz_dict(self, tr):
     paz = self.metadata
     resp = paz_to_freq_resp(paz['poles'], paz['zeros'],
                             paz['gain'] * paz['sensitivity'],
                             self.delta, nfft=self.nfft)
     return resp