Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ timeseries \ filters \ obspy_stages.py: 72%
81 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-10 00:11 -0800
1"""
2Idea here is to add logic to interrogate stage filters received from StationXML
4"""
6# =============================================================================
7# Imports
8# =============================================================================
9import numpy as np
12try:
13 import obspy
14except ImportError:
15 raise ImportError("obspy_stages requires obspy to be installed.")
16from loguru import logger
18from mt_metadata.timeseries.filters import (
19 CoefficientFilter,
20 FIRFilter,
21 FrequencyResponseTableFilter,
22 PoleZeroFilter,
23 TimeDelayFilter,
24)
27# =============================================================================
30def create_time_delay_filter_from_stage(stage):
31 time_delay_filter = TimeDelayFilter()
32 time_delay_filter = time_delay_filter.from_obspy_stage(stage)
33 return time_delay_filter
36def create_coefficent_filter_from_stage(stage):
37 coeff_filter = CoefficientFilter()
38 coeff_filter = coeff_filter.from_obspy_stage(stage)
39 return coeff_filter
42def create_pole_zero_filter_from_stage(stage):
43 pz_filter = PoleZeroFilter()
44 pz_filter = pz_filter.from_obspy_stage(stage)
45 return pz_filter
48def create_fir_filter_from_stage(stage):
49 fir_filter = FIRFilter()
50 fir_filter = fir_filter.from_obspy_stage(stage)
51 return fir_filter
54def create_frequency_response_table_filter_from_stage(stage):
55 """
56 Notes: Issue here is that the stage has a list of response_list_elements, it does not actually
57 have attrs frequencies, amplitudes, phases... will try assigning them on the fly here
59 Parameters
60 ----------
61 stage
63 Returns
64 -------
66 """
67 n_freq = len(stage.response_list_elements)
68 frequencies = np.full(n_freq, np.nan)
69 amplitudes = np.full(n_freq, np.nan)
70 phases = np.full(n_freq, np.nan)
71 for i, response_list_element in enumerate(stage.response_list_elements):
72 frequencies[i] = response_list_element.frequency
73 amplitudes[i] = response_list_element.amplitude
74 phases[i] = response_list_element.phase
75 stage.frequencies = frequencies
76 stage.amplitudes = amplitudes
77 stage.phases = phases
79 fap_filter = FrequencyResponseTableFilter()
80 fap_filter = fap_filter.from_obspy_stage(stage)
81 return fap_filter
84def check_if_coefficient_filter_is_delay_only(stage):
85 """
86 stage: obspy_stage type in obspy.core.inventory.response
87 This function may wind up being a method of the CoefficientFilter class, but leaving it
88 separate for now.
89 Conditions to check:
90 1. Gain is unity
91 2. Decimation Factor is 1
92 3. delay is non-zero
93 4. delay has not been corrected on the data-center side.
94 If all four of these are true we assume this is a pathological CoefficienFilter
95 and would actually be a TimeDelay() filter instance if one existed in StationXML.
96 Returns
97 -------
99 """
100 cond1 = stage.stage_gain == 1.0
101 cond2 = stage.decimation_factor == 1
102 cond3 = stage.decimation_delay != 0.0
103 cond4 = stage.decimation_correction == 0.0
105 if cond1 & cond2 & cond3 & cond4:
106 return True
107 else:
108 return False
111def create_filter_from_stage(stage):
112 """
113 This works on a single stage, we need a catalog of stage classes
114 obspy.core.inventory.response.CoefficientsTypeResponseStage
115 obspy.core.inventory.response.FIRResponseStage
116 obspy.core.inventory.response.PolesZerosResponseStage
118 CoefficientsTypeResponseStage: cases include
119 -numerator=[],denominator=[]
121 Sometimes filter stages in obspy are used to kluge-represent filters of other types
122 # Encountered Cases This Far:
123 # CoefficientTypeResponseStage Used to package a time-delay filter
125 Parameters
126 ----------
127 stage
129 Returns
130 -------
132 """
134 if isinstance(stage, obspy.core.inventory.response.PolesZerosResponseStage):
135 if stage.poles == [] and stage.zeros == []:
136 if (
137 "counts" not in stage.input_units.lower()
138 and "counts" not in stage.output_units.lower()
139 ):
140 logger.info(
141 f"Converting PoleZerosResponseStage {stage.name} to a "
142 "CoefficientFilter."
143 )
144 return create_coefficent_filter_from_stage(stage)
146 return create_pole_zero_filter_from_stage(stage)
148 elif isinstance(stage, obspy.core.inventory.response.CoefficientsTypeResponseStage):
149 is_a_delay_filter = check_if_coefficient_filter_is_delay_only(stage)
150 if is_a_delay_filter:
151 obspy_filter = create_time_delay_filter_from_stage(stage)
152 else:
153 obspy_filter = create_coefficent_filter_from_stage(stage)
154 return obspy_filter
156 elif isinstance(stage, obspy.core.inventory.response.FIRResponseStage):
157 try:
158 if isinstance(stage.coefficients, list):
159 pass
160 else:
161 msg = f"Expected list of coefficients, got {type(stage.coefficients)}"
162 logger.error(msg)
163 raise TypeError(msg)
164 except TypeError:
165 msg = "Something seems off with this FIR"
166 logger.info(msg)
167 raise ValueError(msg)
168 obspy_filter = create_fir_filter_from_stage(stage)
169 return obspy_filter
171 elif isinstance(stage, obspy.core.inventory.response.ResponseListResponseStage):
172 obspy_filter = create_frequency_response_table_filter_from_stage(stage)
173 return obspy_filter
175 elif isinstance(stage, obspy.core.inventory.response.ResponseStage):
176 obspy_filter = create_coefficent_filter_from_stage(stage)
177 return obspy_filter
179 else:
180 msg = "Filter Stage of type {type(stage)} not known, or supported"
181 logger.info(msg)
182 raise TypeError(msg)