Source code for mth5.io.nims.response_filters

# -*- coding: utf-8 -*-
"""
Created on Fri Sep  2 13:50:51 2022

@author: jpeacock
"""

# =============================================================================
# Imports
# =============================================================================
from mt_metadata.timeseries.filters import (
    PoleZeroFilter,
    TimeDelayFilter,
    CoefficientFilter,
    ChannelResponseFilter,
)

# =============================================================================


[docs]class ResponseError(Exception): pass
[docs]class Response(object): """ Common NIMS response filters for electric and magnetic channels """ def __init__(self, system_id=None, **kwargs): self.system_id = system_id self.hardware = "PC" self.instrument_type = "backbone" self.sample_rate = 1 self.e_conversion_factor = 409600000.0 self.h_conversion_factor = 100 self.time_delays_dict = { "hp200": { "hx": -0.0055, "hy": -0.0145, "hz": -0.0235, "ex": -0.1525, "ey": -0.0275, }, 1: { "hx": -0.1920, "hy": -0.2010, "hz": -0.2100, "ex": -0.2850, "ey": -0.2850, }, 8: { "hx": -0.2455, "hy": -0.2365, "hz": -0.2275, "ex": -0.1525, "ey": -0.1525, }, } for key, value in kwargs.items(): setattr(self, key, value) @property def magnetic_low_pass(self): """ Low pass 3 pole filter :return: DESCRIPTION :rtype: TYPE """ return PoleZeroFilter( name="nims_3_pole_butterworth", zeros=[], poles=[ complex(-6.283185, 10.882477), complex(-6.283185, -10.882477), complex(-12.566371, 0), ], units_out="volts", units_in="nanotesla", normalization_factor=2002.26936395594, ) @property def magnetic_conversion(self): """ :return: DESCRIPTION :rtype: TYPE """ return CoefficientFilter( name="h_analog_to_digital", gain=self.h_conversion_factor, units_in="volts", units_out="digital counts", ) @property def electric_low_pass(self): """ 5 pole electric low pass filter :return: DESCRIPTION :rtype: TYPE """ return PoleZeroFilter( name="nims_5_pole_butterworth", zeros=[], poles=[ complex(-3.88301, 11.9519), complex(-3.88301, -11.9519), complex(-10.1662, 7.38651), complex(-10.1662, -7.38651), complex(-12.5664, 0.0), ], units_in="volts", units_out="volts", normalization_factor=313383.493219835, ) @property def electric_high_pass_pc(self): """ 1-pole low pass filter for 8 hz instruments :return: DESCRIPTION :rtype: TYPE """ return PoleZeroFilter( name="nims_1_pole_butterworth", zeros=[complex(0.0, 0.0)], poles=[complex(-3.333333e-05, 0.0)], normalization_factor=1, units_in="volts", units_out="volts", ) @property def electric_high_pass_hp(self): """ 1-pole low pass for 1 hz instuments :return: DESCRIPTION :rtype: TYPE """ return PoleZeroFilter( name="nims_1_pole_butterworth", zeros=[complex(0.0, 0.0)], poles=[complex(-1.66667e-04, 0.0)], normalization_factor=1, units_in="volts", units_out="volts", ) @property def electric_conversion(self): """ electric channel conversion from counts to volts :return: DESCRIPTION :rtype: TYPE """ return CoefficientFilter( name="e_analog_to_digital", gain=self.e_conversion_factor, units_in="volts", units_out="digital counts", ) @property def electric_physical_units(self): """ :return: DESCRIPTION :rtype: TYPE """ return CoefficientFilter( name="to_mt_units", gain=1e-6, units_in="millivolts per kilometer", units_out="volts per meter", )
[docs] def get_electric_high_pass(self, hardware="pc"): """ get the electric high pass filter based on the hardware """ self.hardware = hardware if "pc" in hardware.lower(): return self.electric_high_pass_pc elif "hp" in hardware.lower(): return self.electric_high_pass_hp else: raise ResponseError(f"Hardware value {hardware} not understood")
def _get_dt_filter(self, channel, sample_rate): """ get the DT filter based on channel ans sampling rate """ dt_filter = TimeDelayFilter( name=f"{channel}_time_offset", delay=self.time_delays_dict[sample_rate][channel], units_in="digital counts", units_out="digital counts", ) return dt_filter
[docs] def dipole_filter(self, length): """ Make a dipole filter :param length: dipole length in meters :type length: TYPE :return: DESCRIPTION :rtype: TYPE """ return CoefficientFilter( name=f"dipole_{length:.2f}", gain=length, units_in="volts per meter", units_out="volts", )
def _get_magnetic_filter(self, channel): """ get mag filter, seems to be the same no matter what """ return [ self.magnetic_low_pass, self.magnetic_conversion, self._get_dt_filter(channel, self.sample_rate), ] def _get_electric_filter(self, channel, dipole_length): """ Get electric filter """ filter_list = [] filter_list.append(self.electric_physical_units) filter_list.append(self.dipole_filter(dipole_length)) filter_list.append(self.electric_low_pass) if self.instrument_type in ["backbone"]: filter_list.append(self.get_electric_high_pass(self.hardware)) filter_list.append(self.electric_conversion) filter_list.append(self._get_dt_filter(channel, self.sample_rate)) return filter_list
[docs] def get_channel_response(self, channel, dipole_length=1): """ Get the full channel response filter :param channel: DESCRIPTION :type channel: TYPE :param dipole_length: DESCRIPTION, defaults to 1 :type dipole_length: TYPE, optional :return: DESCRIPTION :rtype: TYPE """ if channel[0] in ["e"]: return ChannelResponseFilter( filters_list=self._get_electric_filter(channel, dipole_length) ) elif channel[0] in ["b", "h"]: return ChannelResponseFilter( filters_list=self._get_magnetic_filter(channel) ) else: raise ValueError(f"Channel {channel} not supported.")