# Source code for obspy.core.inventory.channel

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
    Provides the Channel class.

    :copyright:
        Lion Krischer (krischer@geophysik.uni-muenchen.de), 2013
    :license:
        GNU Lesser General Public License, Version 3
        (https://www.gnu.org/copyleft/lesser.html)
    """
    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    from future.builtins import *  # NOQA
    from future.utils import python_2_unicode_compatible

    from obspy.core.util.obspy_types import FloatWithUncertainties
    from . import BaseNode
    from .util import Azimuth, ClockDrift, Dip, Distance, Latitude, Longitude

    @python_2_unicode_compatible
    class Channel(BaseNode):
        """
        From the StationXML definition:
            Equivalent to SEED blockette 52 and parent element for the related
            response blockettes.
        """
        def __init__(self, code, location_code, latitude, longitude,
                     elevation, depth, azimuth=None, dip=None, types=None,
                     external_references=None, sample_rate=None,
                     sample_rate_ratio_number_samples=None,
                     sample_rate_ratio_number_seconds=None, storage_format=None,
                     clock_drift_in_seconds_per_sample=None,
                     calibration_units=None, calibration_units_description=None,
                     sensor=None, pre_amplifier=None, data_logger=None,
                     equipment=None, response=None, description=None,
                     comments=None, start_date=None, end_date=None,
                     restricted_status=None, alternate_code=None,
                     historical_code=None, data_availability=None):
            """
            :type code: str
            :param code: The SEED channel code for this channel
            :type location_code: str
            :param location_code: The SEED location code for this channel
            :type latitude: :class:`~obspy.core.inventory.util.Latitude`
            :param latitude: Latitude coordinate of this channel's sensor.
            :type longitude: :class:`~obspy.core.inventory.util.Longitude`
            :param longitude: Longitude coordinate of this channel's sensor.
            :type elevation: float
            :param elevation: Elevation of the sensor.
            :type depth: float
            :param depth: The local depth or overburden of the instrument's
                location. For downhole instruments, the depth of the instrument
                under the surface ground level. For underground vaults, the
                distance from the instrument to the local ground level above.
            :type azimuth: float
            :param azimuth: Azimuth of the sensor in degrees from North, clockwise.
            :type dip: float
            :param dip: Dip of the instrument in degrees, down from horizontal.
            :type types: list of str
            :param types: The type of data this channel collects. Corresponds to
                channel flags in SEED blockette 52. The SEED volume producer could
                use the first letter of an Output value as the SEED channel flag.
                Possible values: TRIGGERED, CONTINUOUS, HEALTH, GEOPHYSICAL,
                WEATHER, FLAG, SYNTHESIZED, INPUT, EXPERIMENTAL, MAINTENANCE, BEAM
            :type external_references: list of
                :class:`~obspy.core.inventory.util.ExternalReference`
            :param external_references: URI of any type of external report, such as
                data quality reports.
            :type sample_rate: float
            :param sample_rate: This is a group of elements that represent sample
                rate. If this group is included, then SampleRate, which is the
                sample rate in samples per second, is required. SampleRateRatio,
                which is expressed as a ratio of number of samples in a number of
                seconds, is optional. If both are included, SampleRate should be
                considered more definitive.
            :type sample_rate_ratio_number_samples: int
            :param sample_rate_ratio_number_samples: The sample rate expressed as
                number of samples in a number of seconds. This is the number of
                samples.
            :type sample_rate_ratio_number_seconds: int
            :param sample_rate_ratio_number_seconds: The sample rate expressed as
                number of samples in a number of seconds. This is the number of
                seconds.
            :type storage_format: str
            :param storage_format: The storage format of the recorded data (e.g.
                SEED)
            :type clock_drift_in_seconds_per_sample: float
            :param clock_drift_in_seconds_per_sample: A tolerance value, measured
                in seconds per sample, used as a threshold for time error detection
                in data from the channel.
            :type calibration_units: str
            :param calibration_units: Name of units , e.g. "M/S", "M", ...
            :type calibration_units_description: str
            :param calibration_units_description: Description of units, e.g.
                "Velocity in meters per second", ...
            :type sensor: :class:`~obspy.core.inventory.util.Equipment`
            :param sensor: The sensor
            :type pre_amplifier: :class:`~obspy.core.inventory.util.Equipment`
            :param pre_amplifier: The pre-amplifier
            :type data_logger: :class:`~obspy.core.inventory.util.Equipment`
            :param data_logger: The data-logger
            :type equipment: :class:`~obspy.core.inventory.util.Equipment`
            :param equipment: Other station equipment
            :type response: :class:`~obspy.core.inventory.response.Response`
            :param response: The response of the channel
            :type description: str
            :param description: A description of the resource
            :type comments: list of :class:`~obspy.core.inventory.util.Comment`
            :param comments: An arbitrary number of comments to the resource
            :type start_date: :class:`~obspy.core.utcdatetime.UTCDateTime`
            :param start_date: The start date of the resource
            :type end_date: :class:`~obspy.core.utcdatetime.UTCDateTime`
            :param end_date: The end date of the resource
            :type restricted_status: str
            :param restricted_status: The restriction status
            :type alternate_code: str
            :param alternate_code: A code used for display or association,
                alternate to the SEED-compliant code.
            :type historical_code: str
            :param historical_code: A previously used code if different from the
                current code.
            :type data_availability:
                :class:`~obspy.core.inventor.util.DataAvailability`
            :param data_availability: Information about time series availability
                for the channel.
            """
            self.location_code = location_code
            self.latitude = latitude
            self.longitude = longitude
            self.elevation = elevation
            self.depth = depth
            self.azimuth = azimuth
            self.dip = dip
            self.types = types or []
            self.external_references = external_references or []
            self.sample_rate = sample_rate
            self.sample_rate_ratio_number_samples = \
                sample_rate_ratio_number_samples
            self.sample_rate_ratio_number_seconds = \
                sample_rate_ratio_number_seconds
            self.storage_format = storage_format
            self.clock_drift_in_seconds_per_sample = \
                clock_drift_in_seconds_per_sample
            self.calibration_units = calibration_units
            self.calibration_units_description = calibration_units_description
            self.sensor = sensor
            self.pre_amplifier = pre_amplifier
            self.data_logger = data_logger
            self.equipment = equipment
            self.response = response
            super(Channel, self).__init__(
                code=code, description=description, comments=comments,
                start_date=start_date, end_date=end_date,
                restricted_status=restricted_status, alternate_code=alternate_code,
                historical_code=historical_code,
                data_availability=data_availability)

        def __str__(self):
            ret = (
                "Channel '{id}', Location '{location}' {description}\n"
                "{availability}"
                "\tTime range: {start_date} - {end_date}\n"
                "\tLatitude: {latitude:.2f}, Longitude: {longitude:.2f}, "
                "Elevation: {elevation:.1f} m, Local Depth: {depth:.1f} m\n"
                "{azimuth}"
                "{dip}"
                "{channel_types}"
                "{sampling_rate}"
                "{sensor}"
                "{response}")\
                .format(
                    id=self.code, location=self.location_code,
                    latitude=self.latitude, longitude=self.longitude,
                    elevation=self.elevation, depth=self.depth,
                    availability=("\t%s\n" % str(self.data_availability)
                                  if self.data_availability else ""),
                    description=("(%s)" % self.description
                                 if self.description else ""),
                    start_date=str(self.start_date) if self.start_date else "--",
                    end_date=str(self.end_date) if self.end_date else "--",
                    azimuth=("\tAzimuth: %.2f degrees from north, clockwise\n" %
                             self.azimuth if self.azimuth is not None else ""),
                    dip=("\tDip: %.2f degrees down from horizontal\n" %
                         self.dip if self.dip is not None else ""),
                    channel_types=("\tChannel types: %s\n" % ", ".join(self.types)
                                   if self.types else ""),
                    sampling_rate=("\tSampling Rate: %.2f Hz\n" %
                                   self.sample_rate if self.sample_rate else ""),
                    sensor=("\tSensor (Description): %s (%s)\n" % (
                            self.sensor.type, self.sensor.description)
                            if self.sensor else ""),
                    response=("\tResponse information available"
                              if self.response else ""))
            return ret

        def _repr_pretty_(self, p, cycle):
            p.text(str(self))

        @property
        def location_code(self):
            return self._location_code

        @location_code.setter
        def location_code(self, value):
            self._location_code = value.strip()

        @property
        def longitude(self):
            return self._longitude

        @longitude.setter
        def longitude(self, value):
            if isinstance(value, Longitude):
                self._longitude = value
            else:
                self._longitude = Longitude(value)

        @property
        def latitude(self):
            return self._latitude

        @latitude.setter
        def latitude(self, value):
            if isinstance(value, Latitude):
                self._latitude = value
            else:
                self._latitude = Latitude(value)

        @property
        def elevation(self):
            return self._elevation

        @elevation.setter
        def elevation(self, value):
            if isinstance(value, Distance):
                self._elevation = value
            else:
                self._elevation = Distance(value)

        @property
        def depth(self):
            return self._depth

        @depth.setter
        def depth(self, value):
            if isinstance(value, Distance):
                self._depth = value
            else:
                self._depth = Distance(value)

        @property
        def azimuth(self):
            return self._azimuth

        @azimuth.setter
        def azimuth(self, value):
            if value is None:
                self._azimuth = None
            elif isinstance(value, Azimuth):
                self._azimuth = value
            else:
                self._azimuth = Azimuth(value)

        @property
        def dip(self):
            return self._dip

        @dip.setter
        def dip(self, value):
            if value is None:
                self._dip = None
            elif isinstance(value, Dip):
                self._dip = value
            else:
                self._dip = Dip(value)

        @property
        def sample_rate(self):
            return self._sample_rate

        @sample_rate.setter
        def sample_rate(self, value):
            if value is None:
                self._sample_rate = None
            elif isinstance(value, FloatWithUncertainties):
                self._sample_rate = value
            else:
                self._sample_rate = FloatWithUncertainties(value)

        @property
        def clock_drift_in_seconds_per_sample(self):
            return self._clock_drift_in_seconds_per_sample

        @clock_drift_in_seconds_per_sample.setter
        def clock_drift_in_seconds_per_sample(self, value):
            if value is None:
                self._clock_drift_in_seconds_per_sample = None
            elif isinstance(value, ClockDrift):
                self._clock_drift_in_seconds_per_sample = value
            else:
                self._clock_drift_in_seconds_per_sample = ClockDrift(value)

        def plot(self, min_freq, output="VEL", start_stage=None, end_stage=None,
                 label=None, axes=None, unwrap_phase=False, plot_degrees=False,
                 show=True, outfile=None):
            """
            Show bode plot of the channel's instrument response.

            :type min_freq: float
            :param min_freq: Lowest frequency to plot.
            :type output: str
            :param output: Output units. One of:

                ``"DISP"``
                    displacement, output unit is meters
                ``"VEL"``
                    velocity, output unit is meters/second
                ``"ACC"``
                    acceleration, output unit is meters/second**2

            :type start_stage: int
            :param start_stage: Sequence number of first stage that will be used
                (disregarding all earlier stages).
            :type end_stage: int
            :param end_stage: Sequence number of last stage that will be used
                (disregarding all later stages).
            :type label: str
            :param label: Label string for legend.
            :type axes: list of 2 :class:`matplotlib.axes.Axes`
            :param axes: List/tuple of two axes instances on which to plot the
                amplitude/phase spectrum. If not specified, a new figure is opened.
            :type unwrap_phase: bool
            :param unwrap_phase: Set optional phase unwrapping using NumPy.
            :type plot_degrees: bool
            :param plot_degrees: if ``True`` plot bode in degrees
            :type show: bool
            :param show: Whether to show the figure after plotting or not. Can be
                used to do further customization of the plot before showing it.
            :type outfile: str
            :param outfile: Output file path to directly save the resulting image
                (e.g. ``"/tmp/image.png"``). Overrides the ``show`` option; image
                will not be displayed interactively. The given path/file name is
                also used to automatically determine the output format. Supported
                file formats depend on your matplotlib backend.  Most backends
                support png, pdf, ps, eps and svg. Defaults to ``None``.

            .. rubric:: Basic Usage

            >>> from obspy import read_inventory
            >>> cha = read_inventory()[0][0][0]
            >>> cha.plot(0.001, output="VEL")  # doctest: +SKIP

            .. plot::

                from obspy import read_inventory
                cha = read_inventory()[0][0][0]
                cha.plot(0.001, output="VEL")
            """
            return self.response.plot(
                min_freq=min_freq, output=output,
                start_stage=start_stage, end_stage=end_stage, label=label,
                axes=axes, sampling_rate=self.sample_rate,
                unwrap_phase=unwrap_phase, plot_degrees=plot_degrees, show=show,
                outfile=outfile)

    if __name__ == '__main__':
        import doctest
        doctest.testmod(exclude_empty=True)

### Thank you!

We would like to thank our contributors, whose efforts make this software what it is. These people have helped by writing code and documentation, and by testing. They have created and maintained this product, its associated libraries and applications, our build tools and our web sites.

#### Contributors

- Ackerley, Nick
- Allgeyer, Sebastien
- Ammon, Charles J.
- Antunes, Emanuel
- Arnarsson, Ólafur St.
- Bank, Markus
- Barsch, Robert
- Behr, Yannik
- Bernardi, Fabrizio
- Bernauer, Felix
- Bes de Berc, Maxime
- Beyreuther, Moritz
- Boltz, Shawn
- Bonaimé, Sébastien
- Carothers, Lloyd
- Chamberlain, Calum
- Chambers, Derrick
- Chen, Zhao
- Clark, Adam
- Danecek, Peter
- Egdorf, Sven
- Engels, Fabian
- Ermert, Laura
- Eulenfeld, Tom

- Fabbri, Tommaso
- Falco, Nicholas
- Fee, Jeremy
- Grellier, Clément
- Grunberg, Marc
- Hammer, Conny
- Heimann, Sebastian
- Heiniger, Lukas
- Hope, Gaute
- Igel, Heiner
- Inza, Adolfo
- Isken, Marius
- Ketchum, David
- Koymans, Mathijs
- Kremers, Simon
- Kress, Victor
- Krieger, Lars
- Krischer, Lion
- Kula, Damian
- Käufl, Paul
- Köhler, Andreas
- Lecocq, Thomas
- Leeman, John
- Legovini, Paride

- Lesage, Philippe
- Li, Yulin
- Lomax, Anthony
- Lopes, Rui L.
- MacCarthy, Jonathan
- Maggi, Alessia
- Martin, Henri
- Medlin, Andrew
- Megies, Tobias
- Meschede, Matthias
- Michelini, Alberto
- Miller, Nathaniel C.
- Morgenstern, Bernhard
- Nof, Ran Novitsky
- Panning, Mark P.
- Parker, Tom
- Pestourie, Romain
- Rapagnani, Giovanni
- Reyes, Celso
- Ringler, Adam
- Rothenhäusler, Nicolas
- Russo, Emiliano
- Sales de Andrade, Elliott

- Satriano, Claudio
- Saul, Joachim
- Scheingraber, Chris
- Schneider, Simon
- Sippl, Christian
- Snoke, Arthur
- Stange, Stefan
- Stähler, Simon C.
- Sullivan, Benjamin
- Tian, Dongdong
- Trabant, Chad
- Trani, Luca
- Uieda, Leonardo
- Walker, Andrew
- Walther, Marcus
- Wassermann, Joachim
- Williams, Mark C.
- Winkelman, Andrew
- Zaccarelli, Riccardo
- Zad, Seyed Kasra Hosseini
- Zhu, Lijun
- van Driel, Martin
- van Wijk, Kasper

#### Funds

ObsPy was partially funded by the

- German Science Foundation (DFG) via grant DFG IG 16/9-1
- German Ministry for Education and Research (BMBF), GEOTECHNOLOGIEN grant 03G0646H.
- NERA project (Network of European Research Infrastructures for Earthquake Risk Assessment and Mitigation) under the European Community's Seventh Framework Programme (FP7/2007-2013) grant agreement n° 262330
- Leibniz Institute for Applied Geophysics (LIAG)
- VERCE EU-FP7 project (no. 283543)