21
21
logger = logging .getLogger (__name__ .rsplit ('.' , maxsplit = 1 )[- 1 ])
22
22
23
23
24
+ def _interpolate_spectrum_to_new_freq_range (spec , new_freq ):
25
+ """
26
+ Interpolate spectrum to a new frequency range.
27
+
28
+ Parameters
29
+ ----------
30
+ spec : Spectrum
31
+ Spectrum to be interpolated.
32
+ new_freq : array_like
33
+ New frequency range.
34
+
35
+ Returns
36
+ -------
37
+ Spectrum
38
+ Interpolated spectrum.
39
+ """
40
+ spec_interp = spec .copy ()
41
+ spec_interp .freq = new_freq
42
+ # spec_interp.data must exist, so we create it with zeros
43
+ spec_interp .data = np .zeros_like (new_freq )
44
+ f = interp1d (
45
+ spec .freq , spec .data_mag , fill_value = 'extrapolate' )
46
+ spec_interp .data_mag = f (new_freq )
47
+ return spec_interp
48
+
49
+
24
50
def station_correction (spec_st , config ):
25
51
"""
26
52
Correct spectra using station-average residuals.
27
53
28
54
Residuals are obtained from a previous run.
55
+
56
+ Parameters
57
+ ----------
58
+ spec_st : SpectrumStream or list of Spectrum
59
+ List of spectra to be corrected.
60
+ config : Config
61
+ Configuration object containing the residuals file path.
62
+
63
+ Returns
64
+ -------
65
+ spec_st : SpectrumStream or list of Spectrum
29
66
"""
30
67
res_filepath = config .residuals_filepath
31
68
if res_filepath is None :
@@ -42,40 +79,32 @@ def station_correction(spec_st, config):
42
79
corr = residual .select (id = spec .id )[0 ]
43
80
except IndexError :
44
81
continue
45
- # both spectrum and residual need to be limited to same freq range
82
+ # Define a common frequency range for the correction and the spectrum
46
83
freq_min = max (spec .freq .min (), corr .freq .min ())
47
84
freq_max = min (spec .freq .max (), corr .freq .max ())
48
85
delta_f = spec .stats .delta
49
86
freq = np .arange (freq_min , freq_max , delta_f )
50
- corr_interp = corr .copy ()
51
- corr_interp .freq = freq
52
- # corr_interp.data must exist, so we create it with zeros
53
- corr_interp .data = np .zeros_like (freq )
54
- # interpolate the correction to the common frequency range
55
- f = interp1d (
56
- corr .freq , corr .data_mag , fill_value = 'extrapolate' )
57
- corr_interp .data_mag = f (freq )
58
- # interpolate original spectrum before correction
59
- spec_corr = spec .copy ()
60
- spec_corr .freq = freq
61
- spec_corr .data = np .zeros_like (freq )
62
- f = interp1d (
63
- spec .freq , spec .data_mag , fill_value = 'extrapolate' )
64
- spec_corr .data_mag = f (freq )
65
- # uncorrected spectrum will have component name 'h'
87
+ # Interpolate residual to the common frequency range
88
+ corr_interp = _interpolate_spectrum_to_new_freq_range (corr , freq )
89
+ # Interpolate original spectrum before correction
90
+ spec_corr = _interpolate_spectrum_to_new_freq_range (spec , freq )
91
+ # Uncorrected spectrum will have component name 'h',
92
+ # while corrected spectrum will have component name 'H'
66
93
spec .stats .channel = f'{ spec .stats .channel [:- 1 ]} h'
94
+ # Apply correction
67
95
try :
68
96
spec_corr .data_mag -= corr_interp .data_mag
69
97
except ValueError as msg :
70
98
logger .error (f'Cannot correct spectrum { spec .id } : { msg } ' )
71
99
continue
72
- # interpolate the corrected data_mag to logspaced frequencies
100
+ # Interpolate the corrected data_mag to logspaced frequencies
73
101
# Note that spec_corr.freq_logspaced must not change, otherwise
74
102
# it will be out of sync with the weight used in the inversion.
75
- # Instead, we set it to NaN outside the valid frequency range
103
+ # Instead, we set it to NaN outside the valid frequency range,
104
+ # through the parameter bounds_error=False.
76
105
f = interp1d (spec_corr .freq , spec_corr .data_mag , bounds_error = False )
77
106
spec_corr .data_mag_logspaced = f (spec_corr .freq_logspaced )
78
- # convert mag to moment
107
+ # Convert mag to moment
79
108
spec_corr .data = mag_to_moment (spec_corr .data_mag )
80
109
spec_corr .data_logspaced = mag_to_moment (spec_corr .data_mag_logspaced )
81
110
spec_st .append (spec_corr )
0 commit comments