def plot_psd_noise(psd1, n11, psd2, n22, psd3, n33, per, st_chan): fig = plt.figure(1, figsize=(9, 9)) plt.semilogx(per, psd1, label='PSD ' + (st_chan[0].id).replace('.', ' ')) plt.semilogx(per, n11, label='Noise ' + (st_chan[0].id).replace('.', ' ')) plt.semilogx(per, psd2, label='PSD ' + (st_chan[1].id).replace('.', ' ')) plt.semilogx(per, n22, label='Noise ' + (st_chan[1].id).replace('.', ' ')) plt.semilogx(per, psd3, label='PSD ' + (st_chan[2].id).replace('.', ' ')) plt.semilogx(per, n33, label='Noise ' + (st_chan[2].id).replace('.', ' ')) per2, nlnm = get_nlnm() per2, nhnm = get_nhnm() plt.semilogx(per2, nlnm, color='k', linewidth=2) plt.semilogx(per2, nhnm, color='k', linewidth=2, label='NLNM/NHNM') plt.xlabel('Period (s)') plt.ylabel('PSD (dB rel. 1 $(m/s^2)^2/Hz$)', fontsize=16) plt.legend(ncol=2) plt.xlim((1. / 20., 300.)) #plt.title('PSD '+ str(st_chan[0].stats.starttime.julday).zfill(3) + ' ' + # str(st_chan[0].stats.starttime.hour).zfill(2) + ':' + # str(st_chan[0].stats.starttime.minute).zfill(2) + ' ' + st_chan[0].stats.component) plt.savefig('PSD_' + str(st_chan[0].stats.starttime.julday).zfill(3) + '_' + str(st_chan[0].stats.starttime.hour).zfill(2) + '_' + st_chan[0].stats.channel + '.png') plt.clf() return
def get_petterson_bounds(periods): """`get_petterson_bounds([p1, ...pN])` -> [lowbound1, ... lowboundN], [highbound1, ..., highboundN] `get_petterson_bounds(p)` -> lowbound, highbound """ l_periods, l_psd = get_nlnm() h_periods, h_psd = get_nhnm() periodz = np.log10(periods) return np.interp(periodz, np.log10(l_periods[::-1]), l_psd[::-1]), \ np.interp(periodz, np.log10(h_periods[::-1]), h_psd[::-1])
def nlnm_noise(npts=1024,dt=1.0): p, power = get_nlnm() # returns period and power of acceleration PSD f_in = 1. / p power_in = 10**(power/10.0) f_interp = interp1d(f_in,power_in,bounds_error=None,fill_value='extrapolate') freqs = np.abs(np.fft.fftfreq(npts, dt)) f = f_interp(freqs) return make_some_noise(f, npts, dt)
def spectra(segment, config): """ Computes the signal and noise spectra, as dict of strings mapped to tuples (x0, dx, y). Does not modify the segment's stream or traces in-place :return: a dict with two keys, 'Signal' and 'Noise', mapped respectively to the tuples (f0, df, frequencies) :raise: an Exception if `segment.stream()` is empty or has more than one trace (possible gaps/overlaps) """ from obspy.signal.spectral_estimation import get_nlnm, get_nhnm o_trace = segment.stream()[0] trace = o_trace # divide_sensitivity(o_trace, segment.inventory()) psd_periods = np.linspace(*config['psd_periods_gui'], endpoint=True) # compute psd values for both noise and signal: psd_s_y1 = psd(trace, segment.inventory(), psd_periods, obspy=True) psd_s_y2 = psd(trace, segment.inventory(), psd_periods) nlnm_x, nlnm_y = get_nlnm() nlnm_x, nlnm_y = nlnm_x[::-1], nlnm_y[::-1] nhnm_x, nhnm_y = get_nhnm() nhnm_x, nhnm_y = nhnm_x[::-1], nhnm_y[::-1] # sample at equally spaced periods. First get bounds: # period_min = 2.0 / trace.stats.sampling_rate # period_max = min(psd_n_x[-1] - psd_n_x[0], psd_s_x[-1] - psd_s_x[0]) # # n_pts = config['num_psd_periods'] # 1024 # periods = np.linspace(period_min, period_max, n_pts, endpoint=True) # psd_n_y = np.interp(np.log10(periods), np.log10(psd_n_x), psd_n_y) # psd_s_y = np.interp(np.log10(periods), np.log10(psd_s_x), psd_s_y) # nlnm_y = np.interp(np.log10(periods), np.log10(nlnm_x), nlnm_y) # nhnm_y = np.interp(np.log10(periods), np.log10(nhnm_x), nhnm_y) # x0, dx = psd_periods[0], psd_periods[1] - psd_periods[0] # replace NaNs with Nones: # psd_s_y1_nan = np.isnan(psd_s_y1) # if psd_s_y1_nan.any(): # psd_s_y1 = np.where(psd_s_y1_nan, None, psd_s_y1) # psd_s_y2_nan = np.isnan(psd_s_y2) # if psd_s_y2_nan.any(): # psd_s_y2 = np.where(psd_s_y2_nan, None, psd_s_y2) return { 'PSD_obpsy': (x0, dx, psd_s_y1), 'PSD_sdaas': (x0, dx, psd_s_y2), 'nlnm': (x0, dx, np.interp(psd_periods, nlnm_x, nlnm_y)), 'nhnm': (x0, dx, np.interp(psd_periods, nhnm_x, nhnm_y)) }
def signal_noise_spectra(segment, config): """ Computes the signal and noise spectra, as dict of strings mapped to tuples (x0, dx, y). Does not modify the segment's stream or traces in-place :return: a dict with two keys, 'Signal' and 'Noise', mapped respectively to the tuples (f0, df, frequencies) :raise: an Exception if `segment.stream()` is empty or has more than one trace (possible gaps/overlaps) """ o_trace = segment.stream()[0] trace = o_trace # divide_sensitivity(o_trace, segment.inventory()) # get sn windows: PLEASE NOTE!! sn_windows might calculate the cumulative of segment.stream(), # thus the latter should have been preprocessed (e.g. remove response, bandpass): arrival_time = UTCDateTime( segment.arrival_time) + config['sn_windows']['arrival_time_shift'] signal_trace, noise_trace = sn_split( trace, # assumes stream has only one trace arrival_time, config['sn_windows']['signal_window']) # compute psd values for both noise and signal: psd_n_x, psd_n_y = psd(noise_trace, segment.inventory()) psd_s_x, psd_s_y = psd(signal_trace, segment.inventory()) nlnm_x, nlnm_y = get_nlnm() nlnm_x, nlnm_y = nlnm_x[::-1], nlnm_y[::-1] nhnm_x, nhnm_y = get_nhnm() nhnm_x, nhnm_y = nhnm_x[::-1], nhnm_y[::-1] # sample at equally spaced periods. First get bounds: period_min = 2.0 / trace.stats.sampling_rate period_max = min(psd_n_x[-1] - psd_n_x[0], psd_s_x[-1] - psd_s_x[0]) n_pts = config['num_psd_periods'] # 1024 periods = np.linspace(period_min, period_max, n_pts, endpoint=True) psd_n_y = np.interp(np.log10(periods), np.log10(psd_n_x), psd_n_y) psd_s_y = np.interp(np.log10(periods), np.log10(psd_s_x), psd_s_y) nlnm_y = np.interp(np.log10(periods), np.log10(nlnm_x), nlnm_y) nhnm_y = np.interp(np.log10(periods), np.log10(nhnm_x), nhnm_y) x0, dx = periods[0], periods[1] - periods[0] return { 'Signal': (x0, dx, psd_s_y), 'Noise': (x0, dx, psd_n_y), 'nlnm': (x0, dx, nlnm_y), 'nhnm': (x0, dx, nhnm_y) }
def peterson_noise_model(unit='um/sec/sec'): ''' Return spectral density of the new seismic model of Peterson using Obspy package. This function just converts spectral density as a function of frequencies from a function of period and also changes unit of the spectral acording to given option. Parameters ---------- unit : `str`, optional default is um. Returns ------- val : list of `list` return the low noise model and the high noise model. ''' from obspy.signal.spectral_estimation import get_nhnm, get_nlnm lt, ldb = get_nlnm() ht, hdb = get_nhnm() lfreq, lacc = 1. / lt, 10**(ldb / 20) * 1e6 hfreq, hacc = 1. / ht, 10**(hdb / 20) * 1e6 if unit == 'um/sec/sec': lfreq, lvel = lfreq, lacc hfreq, hvel = hfreq, hacc return [[lfreq, lvel], [hfreq, hvel]] elif unit == 'm/sec/sec': lfreq, lvel = lfreq, lacc * 1e-6 hfreq, hvel = hfreq, hacc * 1e-6 return [[lfreq, lvel], [hfreq, hvel]] elif unit == 'um/sec': lfreq, lvel = lfreq, lacc / (2.0 * np.pi * lfreq) hfreq, hvel = hfreq, hacc / (2.0 * np.pi * hfreq) return [[lfreq, lvel], [hfreq, hvel]] elif unit == 'um': lfreq, ldisp = lfreq, lacc / (2.0 * np.pi * lfreq)**2 hfreq, hdisp = hfreq, hacc / (2.0 * np.pi * hfreq)**2 return [[lfreq, ldisp], [hfreq, hdisp]] elif unit == 'm': lfreq, ldisp = lfreq, lacc / (2.0 * np.pi * lfreq)**2 * 1e-6 hfreq, hdisp = hfreq, hacc / (2.0 * np.pi * hfreq)**2 * 1e-6 return [[lfreq, ldisp], [hfreq, hdisp]] else: raise ValueError(unit)
def get_spectrum(model): fnams = external_models() if fnams[model]: if model == 'NHNM': p, power = get_nhnm() f_in = 1. / p power_in = 10**(power / 10) elif model == 'NLNM': p, power = get_nlnm() f_in = 1. / p power_in = 10**(power / 10) else: spec = np.loadtxt(fnams[model]) f_in = spec[:, 0] power_in = spec[:, 1]**2 return f_in, power_in
def below_noise_model(station, data, inv, save_plot=False): tr = df_to_trace(station, data) ppsd = PPSD(tr.stats, metadata=inv) ppsd.add(tr) fig = ppsd.plot(show=False) if save_plot: julday = format_date_to_str(tr.stats.starttime.julday, 3) fig.savefig( f"plot_data/psd/{station}/{tr.stats.starttime.year}.{julday}.png", dpi=300) nlnm_t, nlnm_db = get_nlnm() trace_t = ppsd.period_bin_centers.tolist() interp_func = interpolate.interp1d(nlnm_t, nlnm_db, bounds_error=False) interp_db = interp_func(trace_t) traces_db = ppsd.psd_values min_t = closest_index_of_list(trace_t, 2.5) max_t = closest_index_of_list(trace_t, 10) for t, trace_db in enumerate(traces_db): diff = np.substract(trace_db[min_t:max_t + 1], interp_db[min_t, max_t + 1]) for i, element in enumerate(diff): if element < 0: time_processed = ppsd.times_processed[t] year = format_date_to_str(time_processed.year, 4) month = format_date_to_str(time_processed.month, 2) day = format_date_to_str(time_processed.day, 2) hour = format_date_to_str(time_processed.hour, 2) minute = format_date_to_str(time_processed.minute, 2) second = format_date_to_str(time_processed.second, 2) datetime = f'D{year}{month}{day}T{hour}{minute}{second}' _id = station + '.' + datetime + '.1' return datetime, f'{str(element)}dB', _id, 1, 'Below Low Noise Model', station return None, f'OK. BelowLowNoiseModel of {station}', None, 0, None, None
def peterson_noise_model(unit='um/sec'): ''' Return ''' lt, ldb = get_nlnm() ht, hdb = get_nhnm() lfreq, lacc = 1. / lt, 10**(ldb / 20) * 1e6 hfreq, hacc = 1. / ht, 10**(hdb / 20) * 1e6 if unit == 'um/sec': lfreq, lvel = lfreq, lacc / (2.0 * np.pi * lfreq) hfreq, hvel = hfreq, hacc / (2.0 * np.pi * hfreq) return [[lfreq, lvel], [hfreq, hvel]] elif unit == 'um': lfreq, ldisp = lfreq, lacc / (2.0 * np.pi * lfreq)**2 hfreq, hdisp = hfreq, hacc / (2.0 * np.pi * hfreq)**2 return [[lfreq, ldisp], [hfreq, hdisp]] else: raise ValueError(unit)
def prime_plot(): """set up plot objects """ f = plt.figure(figsize=(9,5),dpi=200) ax = f.add_subplot(111) pretty_grids(ax) # plot lines for noise models and microseisms nlnm_x,nlnm_y = get_nlnm() nhnm_x,nhnm_y = get_nhnm() plt.plot(nhnm_x,nhnm_y,'gray',alpha=0.1,linewidth=1) plt.plot(nlnm_x,nlnm_y,'gray',alpha=0.1,linewidth=1) ax.fill_between(nhnm_x,nlnm_y,nhnm_y,facecolor='gray',alpha=0.1) # set common plotting parameters plt.xlim([0.2,100]) plt.ylim([nlnm_y.min(),-90]) plt.xscale("log") plt.xlabel("Period [s]") plt.ylabel("Amplitude [m^2/s^4/Hz][dB]") return f, ax
def plot_ppsd(fmatch): files = glob.glob(fmatch) print(files) plt.figure() title = '' for file in files: fv = file.split('/') date = fv[1] + '-' + fv[2] + ' ' j, t = fv[-1].split('_') ch = t.split('.npz') d = np.load(file) f = d['arr_0'][0] a = d['arr_0'][1] plt.semilogx(f, a, label=date + ch[0]) f, a = get_nlnm() plt.semilogx(f, a, '-k', label='NLNM') f, a = get_nhnm() plt.semilogx(f, a, '-k', label='NHNM') plt.xlabel('Period (s)') plt.ylabel('Amplitude (dB)') plt.legend() plt.show()
tr.stats.channel, 'date': stime, 'units': 'ACC' } #tr.detrend('constant') #tr.simulate(paz_remove=None, seedresp=seedresp) #tr.filter('bandpass',freqmin=1., freqmax =5.) #tr.taper(0.05) lenfft = 2 * 512 #fig = plt.figure(1, figsize=(12,8)) plt.subplot(3, 1, 3) per, NLNM = get_nlnm() per, NHNM = get_nhnm() for tr in st: power, freq = csd(tr.data, tr.data, NFFT=lenfft, noverlap=int(lenfft * .5), Fs=1. / tr.stats.delta, scale_by_freq=True) power = np.abs(power[1:]) freq = freq[1:] resp = evalresp(t_samp=tr.stats.delta, nfft=lenfft, filename='/APPS/metadata/RESPS/RESP.' + tr.stats.network + '.' + tr.stats.station + '.' + tr.stats.location + '.' + tr.stats.channel,
label='PSD ' + (tr.id).replace('.', ' '), alpha=.7) plt.semilogx(1. / fre1, n[str(idx)], linestyle=':', linewidth=3, label='Self-Noise ' + (tr.id).replace('.', ' '), alpha=.7) nm /= np.abs(resp[1:])**2 nm = np.abs(nm) #N= 5 #nm = np.convolve(nm, np.ones((N,))/N, mode='same') #nm2 = konno_ohmachi_smoothing(nm, fre1) #plt.semilogx(1./fre1, 10.*np.log10(nm), label='Self-Noise Mean') per_nlnm, pow_nlnm = get_nlnm() plt.semilogx(per_nlnm, pow_nlnm, linewidth=2, color='k') per_nhnm, pow_nhnm = get_nhnm() plt.semilogx(per_nhnm, pow_nhnm, linewidth=2, color='k', label='NLNM/NHNM') #plt.semilogx(1./fre1, 10.*np.log10(nm2), label='Self-Noise Mean') plt.xlabel('Period (s)') plt.ylabel('Power (dB rel. 1 $(m/s^2)^2/Hz$)') #plt.title('Start Time: ' + str(stgood[0].stats.starttime.format_seed())) plt.legend(loc=9, ncol=4) plt.ylim((-225, -30)) plt.xlim((2., 500000)) plt.text(0.5, -30., '(a)', fontsize=28) #plt.savefig('SELFNOISE_TUC.jpg',format='JPEG', dpi= 400) #plt.show() plt.subplot(2, 1, 2)
power = power[1:] power = np.absolute(power) resppath += tr.id resp = evalresp(t_samp=tr.stats.delta, nfft=nfft, filename=resppath, date=tr.stats.starttime, station=tr.stats.station, channel=tr.stats.channel, locid=tr.stats.location, network=tr.stats.network, units='ACC') resp = resp[1:] powerR = 10. * np.log10(power / np.abs(resp)**2) pernlnm, nlnm = get_nlnm() pernhnm, nhnm = get_nhnm() # Plotting data on either the low or high wind subplot if idx2 == 0: plt.subplot(211) plt.semilogx(1. / freq, powerR, label=tr.id, color=colors[idx], linewidth=0.7) else: plt.subplot(212) plt.semilogx(1. / freq, powerR, label=tr.id,
for idx, tr in enumerate(st): amp, f = tr.stats.response.get_evalresp_response(tr.stats.delta, 2**24, output='VEL') amp = amp[1:] f = f[1:] if idx == 0: label = 'Trillium Compact' else: label = 'EpiSensor' plt.semilogx(f, 20. * np.log10(np.abs(amp)), linewidth=2, label=label) plt.legend(loc=8) plt.xlabel('Frequency (Hz)') plt.ylabel('Amplitude (dB rel. 1 $(m/s)^2$)') plt.xlim((1. / (24 * 60 * 60), 200.)) per, nlnm = get_nlnm() per, nhnm = get_nhnm() nlnm = np.sqrt(10**(nlnm / 10.) * (2.**0.25 - 2.**(-0.25)) / per) nlnm = 20. * np.log10(nlnm) nhnm = np.sqrt(10**(nhnm / 10.) * (2.**0.25 - 2.**(-0.25)) / per) nhnm = 20. * np.log10(nhnm) plt.text(1. / (280 * 60 * 60), 180, '(a)', fontsize=26) plt.subplot(2, 1, 2) plt.semilogx(1. / per, nlnm, color='k', linewidth=2) plt.semilogx(1. / per, nhnm, color='k', linewidth=2, label='NLNM/NHNM') plt.xlabel('Frequency (Hz)') plt.ylabel('Amplitude 1/2-Octave (dB rel. 1 $(m/s^2)^2$ )') plt.xlim((1. / (24 * 60 * 60), 200.)) NFFT = 4096 for idx, tr in enumerate(st): if idx == 0:
for mode in modetypes: with open('modes_' + mode + '.eigen', 'r') as f: next(f) modes[mode] = [] for line in f: line = ' '.join(line.split()) if int(line.split(' ')[0]) == 0: line = line.split(' ')[4] modes[mode].append(1. / float(line)) #print(modes['T']) print('Here are the number of spectra:' + str(len(specsN[chan][1, :]))) if True: pers, nlnm = get_nlnm() fig = plt.figure(1, figsize=(14, 9)) plt.subplots_adjust(hspace=0.001) for idx, chan in enumerate(chans): ax1 = fig.add_subplot(len(chans), 1, idx + 1) for pidx in range(len(specsN[chan][1, :])): ax1.semilogx(freq, specsN[chan][:, pidx], color='C0', alpha=.01) #if chan == 'LHZ': percent = 10. minsp = np.percentile(specsN[chan][:, :], percent, axis=1) #minsp = np.average(specsN[chan][:,:], axis=1) #for idx2, mode in enumerate(modes['S']): #mode *= 1000. #if idx2 == 0:
def plot_statistics(self, axis, ppsd): if self.checkBox.isChecked(): mean = ppsd.get_mean() axis.plot(mean[0], mean[1], color='black', linewidth=1, linestyle='--', label="Mean") if self.checkBox_2.isChecked(): mode = ppsd.get_mode() axis.plot(mode[0], mode[1], color='green', linewidth=1, linestyle='--', label="Mode") if self.checkBox_3.isChecked(): nhnm = osse.get_nhnm() axis.plot(nhnm[0], nhnm[1], color='gray', linewidth=2, linestyle='-', label="NHNM (Peterson et al., 2003)") if self.checkBox_4.isChecked(): nlnm = osse.get_nlnm() axis.plot(nlnm[0], nlnm[1], color='gray', linewidth=2, linestyle='-', label="NLNM (Peterson et al., 2003)") if self.groupBox_2.isChecked(): min_mag, max_mag, min_dist, max_dist = ( self.doubleSpinBox.value(), self.doubleSpinBox_2.value(), self.doubleSpinBox_3.value(), self.doubleSpinBox_4.value()) for key, data in earthquake_models.items(): magnitude, distance = key frequencies, accelerations = data accelerations = np.array(accelerations) frequencies = np.array(frequencies) periods = 1.0 / frequencies # Eq.1 from Clinton and Cauzzi (2013) converts # power to density ydata = accelerations / (periods**(-.5)) ydata = 20 * np.log10(ydata / 2) if not (min_mag <= magnitude <= max_mag and min_dist <= distance <= max_dist and min(ydata) < ppsd.db_bin_edges[-1]): continue xdata = periods axis.plot(xdata, ydata, linewidth=2, color="black") leftpoint = np.argsort(xdata)[0] if not ydata[leftpoint] < ppsd.db_bin_edges[-1]: continue axis.text( xdata[leftpoint], ydata[leftpoint], 'M%.1f\n%dkm' % (magnitude, distance), ha='right', va='top', color='w', weight='bold', fontsize='x-small', path_effects=[withStroke(linewidth=3, foreground='0.4')])
'gain': 60077000.0, 'poles': [ -0.037004 + 0.037016j, -0.037004 - 0.037016j, -251.33 + 0j, -131.04 - 467.29j, -131.04 + 467.29j ], 'sensitivity': 2516778400.0, 'zeros': [0j, 0j] } ppsd = PPSD(tr.stats, paz) print(ppsd.id) print(ppsd.times_processed) ppsd.add(st) print(ppsd.times_processed) ppsd.plot() ppsd.save_npz("myfile.npz") ppsd = PPSD.load_npz("myfile.npz") #%% Try getting the NHNM and NLNM nhnm = spec.get_nhnm() plt.semilogx(nhnm[0], nhnm[1]) nlnm = spec.get_nlnm() plt.semilogx(nlnm[0], nlnm[1])
from gwpy.spectrogram import Spectrogram from miyopy.utils.trillium import Trillium from obspy.signal.spectral_estimation import get_nhnm, get_nlnm from gwpy.types.array2d import Array2D from gwpy.timeseries import TimeSeries import astropy.units as u amp = 10**(30.0/20.0) c2v = 20.0/2**15 tr120 = Trillium('120QA') v2vel = tr120.v2vel lt, ldb = get_nlnm() ht, hdb = get_nhnm() lfreq, lacc = 1./lt, 10**(ldb/20)*1e6 hfreq, hacc = 1./ht, 10**(hdb/20)*1e6 lfreq, lvel = lfreq, lacc/(2.0*np.pi*lfreq) hfreq, hvel = hfreq, hacc/(2.0*np.pi*hfreq) lfreq, ldisp = lfreq, lvel/(2.0*np.pi*lfreq) hfreq, hdisp = hfreq, hvel/(2.0*np.pi*hfreq) def _plot_band_histgram(blrms,blrms2,blrms3,scale=0.9,loc=0): blrms.override_unit('m/s') blrms = blrms/amp*c2v/1000*1e6 blrms2 = blrms2/amp*c2v/1000*1e6 blrms3 = blrms3/amp*c2v/1000*1e6 #
def make_dataset(flights, carrier_list, range_start, range_end, bin_width, output='Latencies', plottype='Cum'): data = { 'proportion': [], 'center': [], 'name': [], 'fullname': [], 'color': [] } names = [] #range_extent = int((range_end - range_start) / bin_width) range_extent = np.logspace(np.log10(max([0.01, range_start])), np.log10(range_end), bin_width, endpoint=True) if range_start < -0.009: range_extent = np.append( np.sort(-1 * np.logspace( np.log10(0.009), # 0.01 creates a point at 0, do not do that np.log10(range_start * -1), bin_width, endpoint=True)), range_extent) if output == 'PSD': names += ['N(H,L)NM'] data['fullname'] += ['NLNM'] data['fullname'] += ['NHNM'] for d in [get_nlnm(), get_nhnm()]: data['proportion'] += [ d[1][(d[0] >= range_start) & (d[0] <= range_end)] ] data['center'] += [ d[0][(d[0] >= range_start) & (d[0] <= range_end)] ] data['name'] += ['N(H,L)M'] data['color'] += ['black'] for i, carrier_name in enumerate(carrier_list): subset = flights[1][flights[1]['name'] == carrier_name] d = [] for i, row in subset.iterrows(): psd = row['PSD'][(row['PSD_periods'] >= range_start) & (row['PSD_periods'] <= range_end)] psd_periods = row['PSD_periods'][ (row['PSD_periods'] >= range_start) & (row['PSD_periods'] <= range_end)] d += [list(psd)] if len(d): data['proportion'] += [np.percentile(d, 83, axis=0)] data['center'] += [psd_periods] # Assign the carrier for labels data['fullname'] += [carrier_name] seedid = carrier_name.split('.') seedid[1] = '*' seedid[2] = '*' data['name'] += ['.'.join(seedid)] # Color each carrier differently if data['name'][-1] not in names: names += [data['name'][-1]] data['color'] += [Category20_16[names.index(data['name'][-1])]] return ColumnDataSource(data=data) data = { 'proportion': [], 'steproportion': [], 'left': [], 'right': [], 'center': [], 'leftright': [], 'f_interval': [], 'step_interval': [], 'f_proportion': [], 'step_proportion': [], 'name': [], 'fullname': [], 'color': [] } # Iterate through all the carriers for i, carrier_name in enumerate(carrier_list): # Subset to the carrier subset = flights[0][flights[0]['name'] == carrier_name] subset = subset[output] subset = subset[subset >= range_start] subset = subset[subset <= range_end] # Create a histogram with 5 minute bins arr_hist, edges = np.histogram(subset, bins=range_extent, range=[range_start, range_end]) # Divide the counts by the total to get a proportion if not np.nansum(arr_hist) > 0: continue data['proportion'] += [ arr_hist / np.nansum(arr_hist) * np.sign(edges[:-1]) ] data['left'] += [edges[:-1]] data['right'] += [edges[1:]] data['center'] += [np.abs((edges[:-1] + edges[1:]) / 2)] if 'Cum' in plottype: data['proportion'][-1] = np.nancumsum(data['proportion'][-1]) # Format the proportion data['f_proportion'] += [[ '%0.5f' % proportion for proportion in data['proportion'][-1] ]] # Format the interval data['f_interval'] += [[ '%.3f to %.3f sec' % (left, right) for left, right in zip(data['left'][-1], data['right'][-1]) ]] # Step data data['steproportion'] += [ list( itertools.chain.from_iterable( zip(data['proportion'][-1], data['proportion'][-1]))) ] data['leftright'] += [ list( itertools.chain.from_iterable( zip(data['left'][-1], data['right'][-1]))) ] data['step_proportion'] += [ list( itertools.chain.from_iterable( zip(data['f_proportion'][-1], data['f_proportion'][-1]))) ] data['step_interval'] += [ list( itertools.chain.from_iterable( zip(data['f_interval'][-1], data['f_interval'][-1]))) ] # Assign the carrier for labels data['fullname'] += [carrier_name] seedid = carrier_name.split('.') seedid[1] = '*' seedid[2] = '*' data['name'] += ['.'.join(seedid)] # Color each carrier differently if data['name'][-1] not in names: names += [data['name'][-1]] data['color'] += [Category20_16[names.index(data['name'][-1])]] # Overall dataframe #by_carrier = by_carrier.sort_values(['name', 'left']) return ColumnDataSource(data=data)
skip_on_gaps=True, period_limits=(0.02, 100.0), db_bins=(-200, -50, 1.)) ppsdMHc.add(stMHc_sel) (cMHpd, cMHpsd) = ppsdMHc.get_mode() stEHc = read(cEHdata) invEHc = read_inventory(cEHmeta) stEHc_sel = stEHc.select(channel='EHW') trc = stEHc_sel[0] ppsdEHc = PPSD(trc.stats, metadata=invEHc, ppsd_length=200.0, skip_on_gaps=True, period_limits=(0.02, 100.0), db_bins=(-200, -50, 1.)) ppsdEHc.add(stEHc_sel) (cEHpd, cEHpsd) = ppsdEHc.get_mode() # For reference, earth low and high noise models (nlnmpd, nlnmpsd) = get_nlnm() (nhnmpd, nhnmpsd) = get_nhnm() # channels = ['EHU', 'EHV', 'EHW'] # channels = ['EHU'] # channels = ['SHU', 'MHV', 'MHW'] st = read(ondeckdatafile) inv = read_inventory(ondeckmetadata) # On deck SP data print("Working on on-deck data") chn = 'EHU' tr = st.select(channel=chn)[1] #first one may have metadata problem ppsd = PPSD(tr.stats, metadata=inv, ppsd_length=600.0, skip_on_gaps=True, period_limits=(0.02, 100.0), db_bins=(-200,-50, 1.))
def plot(self, cmap, filename=None, starttime=T1, endtime=T2, show_percentiles=False, percentiles=[10, 50, 90], show_class_models=True, grid=True, title_comment=False): """ Plot the QC resume figure If a filename is specified the plot is saved to this file, otherwise a plot window is shown. :type filename: str (optional) :param filename: Name of output file :type show_percentiles: bool (optional) :param show_percentiles: Enable/disable plotting of approximated percentiles. These are calculated from the binned histogram and are not the exact percentiles. :type percentiles: list of ints :param percentiles: percentiles to show if plotting of percentiles is selected. :type show_class_models: bool (optional) :param show_class_models: Enable/disable plotting of class models. :type grid: bool (optional) :param grid: Enable/disable grid in histogram plot. :type cmap: cmap :param cmap: Colormap for PPSD. """ # COMMON PARAMETERS psd_db_limits = (-180, -110) psdh_db_limits = (-200, -90) f_limits = (5e-3, 20) per_left = (10, 1, .1) per_right = (100, 10, 1) # ----------------- # Select Time window # ----------- times_used = array(self.times_used) starttime = max(min(times_used), starttime) endtime = min(max(times_used), endtime) bool_times_select = (times_used > starttime) & (times_used < endtime) times_used = times_used[bool_times_select] psd = self.psd[bool_times_select, :] spikes = self.spikes[bool_times_select] hist_stack = self._QC__get_ppsd(time_lim=(starttime, endtime)) Hour = arange(0, 23, 1) HourUsed = array([t.hour for t in times_used]) Day_span = (endtime - starttime) / 86400. # ----------- # FIGURE and AXES fig = plt.figure(figsize=(9.62, 13.60), facecolor='w', edgecolor='k') ax_ppsd = fig.add_axes([0.1, 0.68, 0.9, 0.28]) ax_coverage = fig.add_axes([0.1, 0.56, 0.64, 0.04]) ax_spectrogram = fig.add_axes([0.1, 0.31, 0.64, 0.24]) ax_spectrogramhour = fig.add_axes([0.76, 0.31, 0.20, 0.24]) ax_freqpsd = fig.add_axes([0.1, 0.18, 0.64, 0.12]) ax_freqpsdhour = fig.add_axes([0.76, 0.18, 0.20, 0.12]) ax_spikes = fig.add_axes([0.1, 0.05, 0.64, 0.12]) ax_spikeshour = fig.add_axes([0.76, 0.05, 0.20, 0.12]) ax_col_spectrogram = fig.add_axes([0.76, 0.588, 0.20, 0.014]) ax_col_spectrogramhour = fig.add_axes([0.76, 0.57, 0.20, 0.014]) ########################### COVERAGE ax_coverage.xaxis_date() ax_coverage.set_yticks([]) # plot data coverage starts = date2num([a.datetime for a in times_used]) ends = date2num([a.datetime for a in times_used + PPSD_LENGTH]) for start, end in zip(starts, ends): ax_coverage.axvspan(start, end, 0, 0.7, alpha=0.5, lw=0) # plot data really available aa = [(start, end) for start, end in self.times_data if ( (end - start) > PPSD_LENGTH)] # avoid very small gaps otherwise very long to plot for start, end in aa: start = date2num(start.datetime) end = date2num(end.datetime) ax_coverage.axvspan(start, end, 0.7, 1, facecolor="g", lw=0) # plot gaps aa = [(start, end) for start, end in self.times_gaps if ( (end - start) > PPSD_LENGTH)] # avoid very small gaps otherwise very long to plot for start, end in aa: start = date2num(start.datetime) end = date2num(end.datetime) ax_coverage.axvspan(start, end, 0.7, 1, facecolor="r", lw=0) # Compute uncovered periods starts_uncov = ends[:-1] ends_uncov = starts[1:] # Keep only major uncovered periods ga = (ends_uncov - starts_uncov) > (PPSD_LENGTH) / 86400 starts_uncov = starts_uncov[ga] ends_uncov = ends_uncov[ga] ax_coverage.set_xlim(starttime.datetime, endtime.datetime) # labels ax_coverage.xaxis.set_ticks_position('top') ax_coverage.tick_params(direction='out') ax_coverage.xaxis.set_major_locator(mdates.AutoDateLocator()) if Day_span > 5: ax_coverage.xaxis.set_major_formatter(DateFormatter('%D')) else: ax_coverage.xaxis.set_major_formatter(DateFormatter('%D-%Hh')) for label in ax_coverage.get_xticklabels(): label.set_fontsize(10) for label in ax_coverage.get_xticklabels(): label.set_ha("right") label.set_rotation(-25) ########################### SPECTROGRAM ax_spectrogram.xaxis_date() t = date2num([a.datetime for a in times_used]) f = 1. / self.per_octaves T, F = np.meshgrid(t, f) spectro = ax_spectrogram.pcolormesh( T, F, transpose(psd), cmap=spectro_cmap) spectro.set_clim(*psd_db_limits) spectrogram_colorbar = colorbar(spectro, cax=ax_col_spectrogram, orientation='horizontal', ticks=linspace(psd_db_limits[0], psd_db_limits[1], 5), format='%i') spectrogram_colorbar.set_label("dB") spectrogram_colorbar.set_clim(*psd_db_limits) spectrogram_colorbar.ax.xaxis.set_ticks_position('top') spectrogram_colorbar.ax.xaxis.label.set_position((1.1, .2)) spectrogram_colorbar.ax.yaxis.label.set_horizontalalignment('left') spectrogram_colorbar.ax.yaxis.label.set_verticalalignment('bottom') ax_spectrogram.grid(which="major") ax_spectrogram.semilogy() ax_spectrogram.set_ylim(f_limits) ax_spectrogram.set_xlim(starttime.datetime, endtime.datetime) ax_spectrogram.set_xticks(ax_coverage.get_xticks()) setp(ax_spectrogram.get_xticklabels(), visible=False) ax_spectrogram.yaxis.set_major_formatter(FormatStrFormatter("%.2f")) ax_spectrogram.set_ylabel('Frequency [Hz]') ax_spectrogram.yaxis.set_label_coords(-0.08, 0.5) ########################### SPECTROGRAM PER HOUR #psdH=array([array(psd[HourUsed==h,:]).mean(axis=0) for h in Hour]) psdH = zeros((size(Hour), size(self.per_octaves))) for i, h in enumerate(Hour): a = array(psd[HourUsed == h, :]) A = ma.masked_array( a, mask=~((a > psdh_db_limits[0]) & (a < psdh_db_limits[1]))) psdH[i, :] = ma.getdata(A.mean(axis=0)) psdH = array([psdH[:, i] - psdH[:, i].mean() for i in arange(0, psdH.shape[1])]) H24, F = np.meshgrid(Hour, f) spectroh = ax_spectrogramhour.pcolormesh(H24, F, psdH, cmap=cm.RdBu_r) spectroh.set_clim(-8, 8) spectrogram_per_hour_colorbar = colorbar(spectroh, cax=ax_col_spectrogramhour, orientation='horizontal', ticks=linspace(-8, 8, 5), format='%i') spectrogram_per_hour_colorbar.set_clim(-8, 8) ax_spectrogramhour.semilogy() ax_spectrogramhour.set_xlim((0, 23)) ax_spectrogramhour.set_ylim(f_limits) ax_spectrogramhour.set_xticks(arange(0, 23, 4)) ax_spectrogramhour.set_xticklabels(arange(0, 23, 4), visible=False) ax_spectrogramhour.yaxis.set_ticks_position('right') ax_spectrogramhour.yaxis.set_label_position('right') ax_spectrogramhour.yaxis.grid(True) ax_spectrogramhour.xaxis.grid(False) ########################### PSD BY PERIOD RANGE t = date2num([a.datetime for a in times_used]) ax_freqpsd.xaxis_date() for pp in zip(per_left, per_right): mpsd = self._QC__get_psd(time_lim=(starttime, endtime), per_lim=pp) mpsdH = zeros(size(Hour)) + NaN for i, h in enumerate(Hour): a = array(mpsd[HourUsed == h]) A = ma.masked_array( a, mask=~((a > psdh_db_limits[0]) & (a < psdh_db_limits[1]))) mpsdH[i] = ma.getdata(A.mean()) ax_freqpsd.plot(t, mpsd) ax_freqpsdhour.plot(Hour, mpsdH - mpsdH.mean()) ax_freqpsd.set_ylim(psd_db_limits) ax_freqpsd.set_xlim(starttime.datetime, endtime.datetime) ax_freqpsd.set_xticks(ax_coverage.get_xticks()) setp(ax_freqpsd.get_xticklabels(), visible=False) ax_freqpsd.set_ylabel('Amplitude [dB]') ax_freqpsd.yaxis.set_label_coords(-0.08, 0.5) ax_freqpsd.yaxis.grid(False) ax_freqpsd.xaxis.grid(True) ########################### PSD BY PERIOD RANGE PER HOUR ax_freqpsdhour.set_xlim((0, 23)) ax_freqpsdhour.set_ylim((-8, 8)) ax_freqpsdhour.set_yticks(arange(-6, 7, 2)) ax_freqpsdhour.set_xticks(arange(0, 23, 4)) ax_freqpsdhour.set_xticklabels(arange(0, 23, 4), visible=False) ax_freqpsdhour.yaxis.set_ticks_position('right') ax_freqpsdhour.yaxis.set_label_position('right') ########################### SPIKES ax_spikes.xaxis_date() ax_spikes.bar(t, spikes, width=1. / 24) ax_spikes.set_ylim((0, 50)) ax_spikes.set_xlim(starttime.datetime, endtime.datetime) ax_spikes.set_yticks(arange(10, 45, 10)) ax_spikes.set_xticks(ax_coverage.get_xticks()) #setp(ax_spikes.get_xticklabels(), visible=False) ax_spikes.set_ylabel("Detections [#/hour]") ax_spikes.yaxis.set_label_coords(-0.08, 0.5) ax_spikes.yaxis.grid(False) ax_spikes.xaxis.grid(True) # labels ax_spikes.xaxis.set_ticks_position('bottom') ax_spikes.tick_params(direction='out') ax_spikes.xaxis.set_major_locator(mdates.AutoDateLocator()) if Day_span > 5: ax_spikes.xaxis.set_major_formatter(DateFormatter('%D')) else: ax_spikes.xaxis.set_major_formatter(DateFormatter('%D-%Hh')) for label in ax_spikes.get_xticklabels(): label.set_fontsize(10) for label in ax_spikes.get_xticklabels(): label.set_ha("right") label.set_rotation(25) ########################### SPIKES PER HOUR mspikesH = array([array(spikes[[HourUsed == h]]).mean() for h in Hour]) ax_spikeshour.bar(Hour, mspikesH - mspikesH.mean(), width=1.) ax_spikeshour.set_xlim((0, 23)) ax_spikeshour.set_ylim((-8, 8)) ax_spikeshour.set_xticks(arange(0, 23, 4)) ax_spikeshour.set_yticks(arange(-6, 7, 2)) ax_spikeshour.set_ylabel("Daily variation") ax_spikeshour.set_xlabel("Hour [UTC]") ax_spikeshour.yaxis.set_ticks_position('right') ax_spikeshour.yaxis.set_label_position('right') ax_spikeshour.yaxis.set_label_coords(1.3, 1) ########################### plot gaps for start, end in zip(starts_uncov, ends_uncov): ax_spectrogram.axvspan( start, end, 0, 1, facecolor="w", lw=0, zorder=100) ax_freqpsd.axvspan( start, end, 0, 1, facecolor="w", lw=0, zorder=100) ax_spikes.axvspan(start, end, 0, 1, facecolor="w", lw=0, zorder=100) # LEGEND leg = [str(xx) + '-' + str(yy) + ' s' for xx, yy in zip(per_left, per_right)] hleg = ax_freqpsd.legend( leg, loc=3, bbox_to_anchor=(-0.015, 0.75), ncol=size(leg)) for txt in hleg.get_texts(): txt.set_fontsize(8) # PPSD X, Y = np.meshgrid(self.xedges, self.yedges) ppsd = ax_ppsd.pcolormesh(X, Y, hist_stack.T, cmap=cmap) ppsd_colorbar = plt.colorbar(ppsd, ax=ax_ppsd) ppsd_colorbar.set_label("PPSD [%]") color_limits = (0, 30) ppsd.set_clim(*color_limits) ppsd_colorbar.set_clim(*color_limits) ax_ppsd.grid(b=grid, which="major") if show_percentiles: hist_cum = self.__get_normalized_cumulative_histogram( time_lim=(starttime, endtime)) # for every period look up the approximate place of the percentiles for percentile in percentiles: periods, percentile_values = self.get_percentile( percentile=percentile, hist_cum=hist_cum, time_lim=(starttime, endtime)) ax_ppsd.plot(periods, percentile_values, color="black") # Noise models model_periods, high_noise = get_nhnm() ax_ppsd.plot(model_periods, high_noise, '0.4', linewidth=2) model_periods, low_noise = get_nlnm() ax_ppsd.plot(model_periods, low_noise, '0.4', linewidth=2) if show_class_models: classA_periods, classA_noise, classB_periods, classB_noise = get_class() ax_ppsd.plot(classA_periods, classA_noise, 'r--', linewidth=3) ax_ppsd.plot(classB_periods, classB_noise, 'g--', linewidth=3) ax_ppsd.semilogx() ax_ppsd.set_xlim(1. / f_limits[1], 1. / f_limits[0]) ax_ppsd.set_ylim((-200, -80)) ax_ppsd.set_xlabel('Period [s]') ax_ppsd.get_xaxis().set_label_coords(0.5, -0.05) ax_ppsd.set_ylabel('Amplitude [dB]') ax_ppsd.xaxis.set_major_formatter(FormatStrFormatter("%.2f")) # TITLE title = "%s %s -- %s (%i segments)" title = title % (self.id, starttime.date, endtime.date, len(times_used)) if title_comment: fig.text(0.82, 0.978, title_comment, bbox=dict( facecolor='red', alpha=0.5), fontsize=15) ax_ppsd.set_title(title) # a=str(UTCDateTime().format_iris_web_service()) plt.draw() if filename is not None: plt.savefig(filename) plt.close() else: plt.show()
day_ref_mean_pd.append(meanpd) day_ref_mean_psd.append(meanpsd) night_ppsd_ref = PPSD(night_ref_comp_sts[0][0].stats, TrillC, ppsd_length=600.0) for st in night_ref_comp_sts: night_ppsd_ref.add(st) # plotfile = 'night_ref_ppsd_' + component + '.png' # night_ppsd_ref.plot(plotfile, show_coverage=False) (meanpd, meanpsd) = night_ppsd_ref.get_mean() night_ref_mean_pd.append(meanpd) night_ref_mean_psd.append(meanpsd) # Plot up Earth noise models and mean psd values nlnm_pd, nlnm = get_nlnm() nhnm_pd, nhnm = get_nhnm() fig = plt.figure(figsize=(6, 9)) # First the vertical component ax = plt.subplot2grid((2, 8), (0, 1), colspan=7) ax.semilogx(nhnm_pd, nhnm, linewidth=2, color='darkgrey', label='Earth noise') ax.semilogx(nlnm_pd, nlnm, linewidth=2, color='darkgrey') ax.semilogx(day_ref_mean_pd[0], day_ref_mean_psd[0], color='red') ax.semilogx(day_deck_mean_pd[0], day_deck_mean_psd[0], color='red', ls='--') ax.semilogx(night_ref_mean_pd[0], night_ref_mean_psd[0], color='green') ax.semilogx(night_deck_mean_pd[0], night_deck_mean_psd[0],
vpr = 1.45 * 1000. # At receiver vps = 6.8 * 1000. # At source vss = 3.9 * 1000. # At source # Quality Factor from Shearer L = (4. / 3.) * (vpr / vss)**2 Qinv = L * (1. / Qmu) + (1. - L) * (1. / Qk) Q = 1. / Qinv # Seismic Moment M0 = 10.**((Mw + 10.7) * (3. / 2.)) # N-m M0 = (M0 / (10**5)) * .01 perNLNM, NLNM = get_nlnm() perNHNM, NHNM = get_nhnm() # Make a vector of frequency sampling_rate = 1000. lenfft = 1000 freq = np.fft.rfftfreq(lenfft, d=1. / sampling_rate) freq = freq[1:] # Source radiation F = 1. # Page 149 of Nolet's book AE = F / (4. * np.pi * Rrs * (rhos * vpr * vps**5)**.5) # Add attenuation AE = AE * np.exp(-2. * np.pi * freq * Rrs / (Q * (vpr * vps)**.5))
print( "Corner f %f" % (np.pi * 2 * corner_frequency(mw2moment(mw), stressdrop, alpha * 1.e3, phase='P'))) As = ass_snes(f, mw, alpha, phase='P', rho=rho, stressdrop=stressdrop, n=2, gamma=2.) Ae = attenuation(f, 600., delta, depth, alpha, phase='P') plt.figure() per1, nlnm = get_nlnm() per2, nhnm = get_nhnm() plt.semilogx(per1, nlnm, label='NLNM/NHNM', color='.7') plt.semilogx(per2, nhnm, color='.7') plt.semilogx(1. / f, 10 * np.log10((As**2) / f), label='SNES') # plt.semilogx(1./f,10*np.log10((Ae**2)/f),label='Attenuate') plt.semilogx(1. / f, 10 * np.log10(((As * Ae)**2) / f), label="Mw %.1f @ %.1f,z=%.1fkm" % (mw, delta, depth)) plt.xlabel('Period (s)') plt.ylabel('Acceleration (db)') plt.legend() # Check to see if we go backwards fine f = np.array([4, 6, 8]) As = ass_snes(f,
(p13, fre1) = cp(st[0], st[2], length, overlap, delta) (p23, fre1) = cp(st[1], st[2], length, overlap, delta) n11 = ((2 * pi * fre1)**2) * (p11 - p21 * p13 / p23) / instresp n22 = ((2 * pi * fre1)**2) * ( p22 - np.conjugate(p23) * p21 / np.conjugate(p13)) / instresp n33 = ((2 * pi * fre1)** 2) * (p33 - p23 * np.conjugate(p13) / p21) / instresp psd1 = 10 * np.log10(((2 * pi * fre1)**2) * p11 / instresp) psd2 = 10 * np.log10(((2 * pi * fre1)**2) * p22 / instresp) psd3 = 10 * np.log10(((2 * pi * fre1)**2) * p33 / instresp) per = 1 / fre1 NLNMper, NLNMpower = get_nlnm() NHNMper, NHNMpower = get_nhnm() titlelegend = st[0].stats.channel + ' Self-Noise Start Time: ' + str(st[0].stats.starttime.year) + ' ' + str(st[0].stats.starttime.julday) + ' ' + \ str(st[0].stats.starttime.hour) + ':' + str(st[0].stats.starttime.minute) + ':' + str(st[0].stats.starttime.second) + \ ' Duration: ' + str(int(st[0].stats.npts*delta/(60*60))) + ' Hours' noiseplot = figure(1) subplot(1, 1, 1) title(titlelegend, fontsize=12) plot(1/fre1,psd1,'r',label='PSD ' + st[0].stats.station + ' ' + \ st[0].stats.location, linewidth=1.5) plot(1/fre1,psd2,'b',label='PSD ' + st[1].stats.station + ' ' + \ st[1].stats.location, linewidth=1.5) plot(1/fre1,psd3,'g',label='PSD ' + st[2].stats.station + ' ' + \ st[2].stats.location, linewidth=1.5)
msg_lib.info('POWER: ' + str(len(power)) + '\n') fig = plt.figure() fig.subplots_adjust(hspace=.2) fig.subplots_adjust(wspace=.2) fig.set_facecolor('w') ax311 = plt.subplot(111) ax311.set_xscale('log') plabel_x, plabel_y = shared.production_label_position ax311.text(plabel_x, plabel_y, production_label, horizontalalignment='left', fontsize=5, verticalalignment='top', transform=ax311.transAxes) if do_plot_nnm: nlnm_x, nlnm_y = get_nlnm() nhnm_x, nhnm_y = get_nhnm() if xtype != 'period': nlnm_x = 1.0 / nlnm_x nhnm_x = 1.0 / nhnm_x plt.plot(nlnm_x, nlnm_y, lw=1, ls=':', c='k', label='NLNM, NHNM') plt.plot(nhnm_x, nhnm_y, lw=1, ls=':', c='k') # Period for the x-axis. if xtype == 'period': if utils_lib.param(param, 'plotSpectra').plotSpectra: plt.plot(period, power, utils_lib.param(param, 'colorSpectra').colorSpectra, label=csd_label) if utils_lib.param(param, 'plotSmooth').plotSmooth: plt.plot(smooth_x, smooth_psd, color=utils_lib.param(param, 'colorSmooth').colorSmooth, label=smoothing_label)