def __init__(self, *args, **kwargs):
        """
        This double-differencer is a cascade of two differencers:

                |-------------------------------------------|
                |                                           |
                |   ----------------   ----------------     |
            --->|---|   diffr M1   |---|   diffr M1   |-----|---->  double difference
                |   ----------------   ----------------     |
                |                                           |
                |-------------------------------------------|

        This cascade halves the bandwidth of either differencer. When used in conjuction with a
        single differencer, the M1 value here must be 1/2 the M1 value of the single differencer.
        Specifically:

                single differencer: M1 = (tau_+ + tau_-) / 2
                double differencer: M1 = (tau_+ + tau_-) / 4

        With these conditions, the delay of the single- and double-differencer is nearly the same.


        kwarg keys:
            name
            weight
            arm_ratio
            order
        """

        # the differencer has a name
        ScalarFilterBase.__init__(self, *args, **kwargs)

        # instantiate an underlying poly-ema pair
        this_order      = kwargs.get('order', 1)
        name_1st_fltr   = "%s-1st" % kwargs.get('name', 'f')
        name_2nd_fltr   = "%s-2nd" % kwargs.get('name', 'f')

        # a note on weights: the filter output is the cascade of these two filters. The total filter
        # output weight needs to be 1/2

        self._1st_fltr  = ScalarHomogeneousDifferencer(name=name_1st_fltr, order=this_order, weight=1.0)
        self._2nd_fltr  = ScalarHomogeneousDifferencer(name=name_2nd_fltr, order=this_order, weight=0.5)

        #--------------------------------------------------------------------
        # in this pythonic environ need to have more explicit assurance that the filter is made

        self._is_made   = False
    def __init__(self, *args, **kwargs):
        """
        kwarg keys:
            name
            weight
            arm_ratio
            order
        """

        # this filter bank has a name
        ScalarFilterBase.__init__(self, *args, **kwargs)

        """
        This filter bank looks like this:

                |---------------------------------------------|
                |                                             |
                |                --------------               |
                |   ----------- |  diffr M1   |---------------|---->  slope
                | /              --------------               |
        px  --->|-                                            |
                | \                                           |
                |  \          --------------------            |
                |   \---------|  dbl-diffr M1/2  |------------|---->  curvature
                |             --------------------            |
                |                                             |
                |---------------------------------------------|

        """

        # aux
        this_order     = kwargs.get('order', 1)
        name_slope_arm = "%s-slope"  % kwargs.get('name', 'scf')
        name_curv_arm  = "%s-curv"   % kwargs.get('name', 'scf')


        # the slope filter
        self._slope_filter = ScalarHomogeneousDifferencer(name=name_slope_arm, order=this_order, weight=1.0)

        # the curvature filter. This filter is a chain of two half-M1 differencers
        self._curv_filter  = ScalarHomogeneousDoubleDifferencer(name=name_curv_arm, order=this_order, weight=1.0)

        self._meta_data_queue = deque()

        #--------------------------------------------------------------------
        # in this pythonic environ need to have more explicit assurance that the filter is made

        self._is_made = False
class SlopeCurvatureFilterBank(ScalarFilterBase):

    def __init__(self, *args, **kwargs):
        """
        kwarg keys:
            name
            weight
            arm_ratio
            order
        """

        # this filter bank has a name
        ScalarFilterBase.__init__(self, *args, **kwargs)

        """
        This filter bank looks like this:

                |---------------------------------------------|
                |                                             |
                |                --------------               |
                |   ----------- |  diffr M1   |---------------|---->  slope
                | /              --------------               |
        px  --->|-                                            |
                | \                                           |
                |  \          --------------------            |
                |   \---------|  dbl-diffr M1/2  |------------|---->  curvature
                |             --------------------            |
                |                                             |
                |---------------------------------------------|

        """

        # aux
        this_order     = kwargs.get('order', 1)
        name_slope_arm = "%s-slope"  % kwargs.get('name', 'scf')
        name_curv_arm  = "%s-curv"   % kwargs.get('name', 'scf')


        # the slope filter
        self._slope_filter = ScalarHomogeneousDifferencer(name=name_slope_arm, order=this_order, weight=1.0)

        # the curvature filter. This filter is a chain of two half-M1 differencers
        self._curv_filter  = ScalarHomogeneousDoubleDifferencer(name=name_curv_arm, order=this_order, weight=1.0)

        self._meta_data_queue = deque()

        #--------------------------------------------------------------------
        # in this pythonic environ need to have more explicit assurance that the filter is made

        self._is_made = False


    #--------------------------------------------------------------------
    # main interface

    # make the differencer, which makes the two underlying filters
    def make(self, slope_M1):

        # simply make the slope and curvature filters, use M1/2 for the curvature filter.
        self._slope_filter.make(slope_M1)
        self._curv_filter.make(slope_M1/2.0)
        self._meta_data_queue = deque(maxlen=slope_M1)

        # set
        self._is_made = True

    def reset(self):
        self._slope_filter.reset()
        self._curv_filter.reset()

    def relevel(self, v):
        self._slope_filter.relevel(v)
        self._curv_filter.relevel(v)

    def update(self, v, meta_data=None):
        self._slope_filter.update(v)
        self._curv_filter.update(v)
        if meta_data:
            self._meta_data_queue.append(meta_data)

    def value(self):

        # return a tuple (slope, curvature)
        return [self._slope_filter.value(), self._curv_filter.value()]

    def getMetaDataQueue(self):
        return self._meta_data_queue

    def isReady(self):

        return self._slope_filter.isReady() and self._curv_filter.isReady()

    def isMade(self):

        return self._is_made

    #--------------------------------------------------------------------
    # getters

    def getProperties(self):

        prop = {}
        prop['order']     = self._slope_filter.getOrder()
        prop['name']      = self._name
        prop['weight']    = self._weight

        return prop

    def getArms(self):

        return {'slope': self._slope_filter, 'curve': self._curv_filter}
class ScalarHomogeneousDoubleDifferencer(ScalarFilterBase):

    def __init__(self, *args, **kwargs):
        """
        This double-differencer is a cascade of two differencers:

                |-------------------------------------------|
                |                                           |
                |   ----------------   ----------------     |
            --->|---|   diffr M1   |---|   diffr M1   |-----|---->  double difference
                |   ----------------   ----------------     |
                |                                           |
                |-------------------------------------------|

        This cascade halves the bandwidth of either differencer. When used in conjuction with a
        single differencer, the M1 value here must be 1/2 the M1 value of the single differencer.
        Specifically:

                single differencer: M1 = (tau_+ + tau_-) / 2
                double differencer: M1 = (tau_+ + tau_-) / 4

        With these conditions, the delay of the single- and double-differencer is nearly the same.


        kwarg keys:
            name
            weight
            arm_ratio
            order
        """

        # the differencer has a name
        ScalarFilterBase.__init__(self, *args, **kwargs)

        # instantiate an underlying poly-ema pair
        this_order      = kwargs.get('order', 1)
        name_1st_fltr   = "%s-1st" % kwargs.get('name', 'f')
        name_2nd_fltr   = "%s-2nd" % kwargs.get('name', 'f')

        # a note on weights: the filter output is the cascade of these two filters. The total filter
        # output weight needs to be 1/2

        self._1st_fltr  = ScalarHomogeneousDifferencer(name=name_1st_fltr, order=this_order, weight=1.0)
        self._2nd_fltr  = ScalarHomogeneousDifferencer(name=name_2nd_fltr, order=this_order, weight=0.5)

        #--------------------------------------------------------------------
        # in this pythonic environ need to have more explicit assurance that the filter is made

        self._is_made   = False


    #--------------------------------------------------------------------
    # main interface

    # make the differencer, which makes the two underlying filters
    def make(self, wireframe_M1p_Mpm_avg):

        self._1st_fltr.make(wireframe_M1p_Mpm_avg)
        self._2nd_fltr.make(wireframe_M1p_Mpm_avg)

        self._is_made = True

    def reset(self):

        self._1st_fltr.reset()
        self._2nd_fltr.reset()

    def relevel(self, v):

        # the double-differencer is a cascade
        self._1st_fltr.relevel(v)
        self._2nd_fltr.relevel( self._1st_fltr.value() )

    def update(self, v):

        # the double-differencer is a cascade
        self._1st_fltr.update(v)
        self._2nd_fltr.update( self._1st_fltr.value() )

    def value(self):

        # The double-differencer value is that output of the second diff-r
        return self._2nd_fltr.value()

    def isReady(self):

        return self._is_made and (self._1st_fltr.isReady() and self._2nd_fltr.isReady())

    def isMade(self):

        return self._is_made

    #--------------------------------------------------------------------
    # getters

    def getProperties(self):

        prop = {}
        prop['order']     = self._1st_fltr.getOrder()  # Hack
        prop['arm-ratio'] = self._1st_fltr._arm_ratio  # Hack
        prop['name']      = self._name
        prop['weight']    = self._weight

        return prop