Xsim = rk4(SIR_D, y0, time, args=(beta,gamma,))<EOL>Xsim = Xsim.transpose()<EOL>return Xsim<EOL>

Integrate SIR epidemic model

    Simulate a very basic deterministic SIR system.

    :param 2x1 numpy array y0: initial conditions
    :param Ntimestep length numpy array time: Vector of time points that \
    solution is returned at
    :param float beta: transmission rate
    :param float gamma: recovery rate

    :returns: (2)x(Ntimestep) numpy array Xsim: first row S(t), second row I(t)


def __init__(self, filename, damethod, date, ensize):

self.filename = filename<EOL>self.damethod = damethod<EOL>self.date = date<EOL>self.ensize = ensize<EOL>self.dafile = h5py.File(self.filename, "<STR_LIT:a>")<EOL>self.dafile.attrs['<STR_LIT>'] = self.damethod<EOL>self.dafile.attrs['<STR_LIT:date>'] = self.date<EOL>self.dafile.attrs['<STR_LIT>'] = self.ensize<EOL>self.dafile.create_group("<STR_LIT>")<EOL>self.dafile.create_group("<STR_LIT>")<EOL>self.dafile.create_group("<STR_LIT>")<EOL>self.dafile.create_group("<STR_LIT>")<EOL>self.dafile.create_group("<STR_LIT>")<EOL>self.dafile.create_group("<STR_LIT>")<EOL>

Initialize darun attributes

        Args:
            filename (str): Absolute path of file name as a string with `hdf5` extension
            damethod (str): Name of the assimilation method used, i.e. `enkf`.
            date (str): Date of the experiment `MM-DD-YYYY:HHHH`
            ensize (int): ensemble size


return (time.mktime(when.timetuple()) if sys.version_info < (<NUM_LIT:3>,) else<EOL>when.timestamp())<EOL>

Python 2 compatibility for `datetime.timestamp()`.


if isinstance(data, bytes):<EOL><INDENT>return data<EOL><DEDENT>elif isinstance(data, str):<EOL><INDENT>return data.encode('<STR_LIT:ascii>')  <EOL><DEDENT>else:<EOL><INDENT>raise TypeError(data)<EOL><DEDENT>


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return UserVoiceNode()<EOL>

UserVoice tracking template tag.

Renders Javascript code to track page visits.  You must supply
your UserVoice Widget Key in the ``USERVOICE_WIDGET_KEY``
setting or the ``uservoice_widget_key`` template context variable.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return KissInsightsNode()<EOL>

KISSinsights set-up template tag.

Renders Javascript code to set-up surveys.  You must supply
your account number and site code in the
``KISS_INSIGHTS_ACCOUNT_NUMBER`` and ``KISS_INSIGHTS_SITE_CODE``
settings.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return MatomoNode()<EOL>

Matomo tracking template tag.

Renders Javascript code to track page visits.  You must supply
your Matomo domain (plus optional URI path), and tracked site ID
in the ``MATOMO_DOMAIN_PATH`` and the ``MATOMO_SITE_ID`` setting.

Custom variables can be passed in the ``matomo_vars`` context
variable.  It is an iterable of custom variables as tuples like:
``(index, name, value[, scope])`` where scope may be ``'page'``
(default) or ``'visit'``.  Index should be an integer and the
other parameters should be strings.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return SpringMetricsNode()<EOL>

Spring Metrics tracking template tag.

Renders Javascript code to track page visits.  You must supply
your Spring Metrics Tracking ID in the
``SPRING_METRICS_TRACKING_ID`` setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return PerformableNode()<EOL>

Performable template tag.

Renders Javascript code to set-up Performable tracking.  You must
supply your Performable API key in the ``PERFORMABLE_API_KEY``
setting.


return mark_safe(EMBED_CODE % {<EOL>'<STR_LIT>': hostname,<EOL>'<STR_LIT>': page_id,<EOL>})<EOL>


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return RatingMailruNode()<EOL>

Rating@Mail.ru counter template tag.

Renders Javascript code to track page visits. You must supply
your website counter ID (as a string) in the
``RATING_MAILRU_COUNTER_ID`` setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return HubSpotNode()<EOL>

HubSpot tracking template tag.

Renders Javascript code to track page visits.  You must supply
your portal ID (as a string) in the ``HUBSPOT_PORTAL_ID`` setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return ChartbeatBottomNode()<EOL>

Bottom Chartbeat template tag.

Render the bottom Javascript code for Chartbeat.  You must supply
your Chartbeat User ID (as a string) in the ``CHARTBEAT_USER_ID``
setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return ChartbeatTopNode()<EOL>

Top Chartbeat template tag.

Render the top Javascript code for Chartbeat.


_validate_no_args(token)<EOL>return FacebookPixelHeadNode()<EOL>


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return GaugesNode()<EOL>

Gaug.es template tag.

Renders Javascript code to gaug.es testing.  You must supply
your Site ID account number in the ``GAUGES_SITE_ID``
setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return OlarkNode()<EOL>

Olark set-up template tag.

Renders Javascript code to set-up Olark chat.  You must supply
your site ID in the ``OLARK_SITE_ID`` setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return ClickyNode()<EOL>

Clicky tracking template tag.

Renders Javascript code to track page visits.  You must supply
your Clicky Site ID (as a string) in the ``CLICKY_SITE_ID``
setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return MixpanelNode()<EOL>

Mixpanel tracking template tag.

Renders Javascript code to track page visits.  You must supply
your Mixpanel token in the ``MIXPANEL_API_TOKEN`` setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return KissMetricsNode()<EOL>

KISSinsights tracking template tag.

Renders Javascript code to track page visits.  You must supply
your KISSmetrics API key in the ``KISS_METRICS_API_KEY``
setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return SnapEngageNode()<EOL>

SnapEngage set-up template tag.

Renders Javascript code to set-up SnapEngage chat.  You must supply
your widget ID in the ``SNAPENGAGE_WIDGET_ID`` setting.


bits = token.split_contents()<EOL>if len(bits) > <NUM_LIT:1>:<EOL><INDENT>raise TemplateSyntaxError("<STR_LIT>" % bits[<NUM_LIT:0>])<EOL><DEDENT>return GoSquaredNode()<EOL>

GoSquared tracking template tag.

Renders Javascript code to track page visits.  You must supply
your GoSquared site token in the ``GOSQUARED_SITE_TOKEN`` setting.


try:<EOL><INDENT>request = context['<STR_LIT>']<EOL>remote_ip = request.META.get('<STR_LIT>', '<STR_LIT>')<EOL>if not remote_ip:<EOL><INDENT>remote_ip = request.META.get('<STR_LIT>', '<STR_LIT>')<EOL><DEDENT>if not remote_ip:<EOL><INDENT>return False<EOL><DEDENT>internal_ips = None<EOL>if prefix is not None:<EOL><INDENT>internal_ips = getattr(settings, '<STR_LIT>' % prefix, None)<EOL><DEDENT>if internal_ips is None:<EOL><INDENT>internal_ips = getattr(settings, '<STR_LIT>', None)<EOL><DEDENT>if internal_ips is None:<EOL><INDENT>internal_ips = getattr(settings, '<STR_LIT>', None)<EOL><DEDENT>return remote_ip in (internal_ips or [])<EOL><DEDENT>except (KeyError, AttributeError):<EOL><INDENT>return False<EOL><DEDENT>

Return whether the visitor is coming from an internal IP address,
based on information from the template context.

The prefix is used to allow different analytics services to have
different notions of internal addresses.


def get_identity(context, prefix=None, identity_func=None, user=None):

if prefix is not None:<EOL><INDENT>try:<EOL><INDENT>return context['<STR_LIT>' % prefix]<EOL><DEDENT>except KeyError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>try:<EOL><INDENT>return context['<STR_LIT>']<EOL><DEDENT>except KeyError:<EOL><INDENT>pass<EOL><DEDENT>if getattr(settings, '<STR_LIT>', True):<EOL><INDENT>try:<EOL><INDENT>if user is None:<EOL><INDENT>user = get_user_from_context(context)<EOL><DEDENT>if get_user_is_authenticated(user):<EOL><INDENT>if identity_func is not None:<EOL><INDENT>return identity_func(user)<EOL><DEDENT>else:<EOL><INDENT>return user.get_username()<EOL><DEDENT><DEDENT><DEDENT>except (KeyError, AttributeError):<EOL><INDENT>pass<EOL><DEDENT><DEDENT>return None<EOL>

Get the identity of a logged in user from a template context.

The `prefix` argument is used to provide different identities to
different analytics services.  The `identity_func` argument is a
function that returns the identity of the user; by default the
identity is the username.


if callable(user.is_authenticated):<EOL><INDENT>return user.is_authenticated()<EOL><DEDENT>else:<EOL><INDENT>return user.is_authenticated<EOL><DEDENT>

Check if the user is authenticated.

    This is a compatibility function needed to support both Django 1.x and 2.x;
    Django 2.x turns the function into a proper boolean so function calls will
    fail.


return HTML_COMMENT % {'<STR_LIT:html>': html, '<STR_LIT>': service}<EOL>

Disable HTML code by commenting it out.

The `service` argument is used to display a friendly message.


self.ode_body.setForce(tuple(force))<EOL>

Set the force acting on this body.

        Parameters
        ----------
        force : 3-tuple of float
            The desired force acting on this body, in world coordinates.


return self.ode_obj.getFeedback()<EOL>

Feedback buffer (list of 3-tuples) for this ODE motor/joint.


self.frame_no += <NUM_LIT:1><EOL>dt = self.dt / substeps<EOL>for _ in range(substeps):<EOL><INDENT>self.ode_contactgroup.empty()<EOL>self.ode_space.collide(None, self.on_collision)<EOL>self.ode_world.step(dt)<EOL><DEDENT>

Step the world forward by one frame.

        Parameters
        ----------
        substeps : int, optional
            Split the step into this many sub-steps. This helps to prevent the
            time delta for an update from being too large.


return [np.array(self.ode_obj.getAxis1()),<EOL>np.array(self.ode_obj.getAxis2())]<EOL>

A list of axes of rotation for this joint.


return [self.ode_obj.getPositionRate(i) for i in range(self.LDOF)]<EOL>

List of position rates for linear degrees of freedom.


def _set_params(target, param, values, dof):

if not isinstance(values, (list, tuple, np.ndarray)):<EOL><INDENT>values = [values] * dof<EOL><DEDENT>assert dof == len(values)<EOL>for s, value in zip(['<STR_LIT>', '<STR_LIT:2>', '<STR_LIT:3>'][:dof], values):<EOL><INDENT>target.setParam(getattr(ode, '<STR_LIT>'.format(param, s)), value)<EOL><DEDENT>

Set the given param for each of the DOFs for a joint.


return [np.array(self.ode_obj.getAxis())]<EOL>


Add the given torques along this motor's axes.

        Parameters
        ----------
        torques : sequence of float
            A sequence of torque values to apply to this motor's axes.


return [self.ode_obj.getAngle1Rate(), self.ode_obj.getAngle2Rate()]<EOL>

A list of two angle rates for this joint's degrees of freedom.


return self._joints.get(key, None)<EOL>

Get a joint by key.

        Parameters
        ----------
        key : str
            The key for a joint to look up.

        Returns
        -------
        joint : :class:`Joint`
            The joint in the world with the given key, or None if there is no
            such joint.


return np.array(self.ode_body.getTorque())<EOL>

Current net torque acting on this body (in world coordinates).


return np.array(self.body_to_world(offset * self.dimensions / <NUM_LIT:2>))<EOL>

Convert a relative body offset to world coordinates.

        Parameters
        ----------
        offset : 3-tuple of float
            The offset of the desired point, given as a relative fraction of the
            size of this body. For example, offset (0, 0, 0) is the center of
            the body, while (0.5, -0.2, 0.1) describes a point halfway from the
            center towards the maximum x-extent of the body, 20% of the way from
            the center towards the minimum y-extent, and 10% of the way from the
            center towards the maximum z-extent.

        Returns
        -------
        position : 3-tuple of float
            A position in world coordinates of the given body offset.


return self._bodies.get(key, key)<EOL>

Get a body by key.

        Parameters
        ----------
        key : str, None, or :class:`Body`
            The key for looking up a body. If this is None or a :class:`Body`
            instance, the key itself will be returned.

        Returns
        -------
        body : :class:`Body`
            The body in the world with the given key.


return self.ode_world.getGravity()<EOL>


_set_params(self.ode_obj, '<STR_LIT>', lo_stops, self.ADOF + self.LDOF)<EOL>

Set the lo stop values for this object's degrees of freedom.

        Parameters
        ----------
        lo_stops : float or sequence of float
            A lo stop value to set on all degrees of freedom, or a list
            containing one such value for each degree of freedom. For rotational
            degrees of freedom, these values must be in radians.


assert self.ADOF == len(axes) or self.LDOF == len(axes)<EOL>for i, axis in enumerate(axes):<EOL><INDENT>if axis is not None:<EOL><INDENT>self.ode_obj.setAxis(i, <NUM_LIT:0>, axis)<EOL><DEDENT><DEDENT>

Set the axes for this object's degrees of freedom.

        Parameters
        ----------
        axes : list of axes specifications
            A list of axis values to set. This list must have the same number of
            elements as the degrees of freedom of the underlying ODE object.
            Each element can be

            (a) None, which has no effect on the corresponding axis, or
            (b) three floats specifying the axis to set.


return self.ode_obj.getNumAxes()<EOL>

Number of linear degrees of freedom for this motor.


self.amotor.axes = [axes[<NUM_LIT:0>]]<EOL>self.ode_obj.setAxis(tuple(axes[<NUM_LIT:0>]))<EOL>

Set the angular axis of rotation for this joint.

        Parameters
        ----------
        axes : list containing one 3-tuple of floats
            A list of the axes for this joint. For a hinge joint, which has one
            degree of freedom, this must contain one 3-tuple specifying the X,
            Y, and Z axis for the joint.


return self.ode_world.setCFM(cfm)<EOL>

Set the global CFM value.

        Parameters
        ----------
        cfm : float
            The desired global CFM value.


pass<EOL>


return self.ode_body.getMass()<EOL>


_set_params(self.ode_obj, '<STR_LIT>', max_forces, self.ADOF + self.LDOF)<EOL>

Set the maximum forces for this object's degrees of freedom.

        Parameters
        ----------
        max_forces : float or sequence of float
            A maximum force value to set on all degrees of freedom, or a list
            containing one such value for each degree of freedom.


return np.array(self.ode_body.getForce())<EOL>

Current net force acting on this body (in world coordinates).


return [b.state for b in self.bodies]<EOL>

Return the complete state of all bodies in the world.

        Returns
        -------
        states : list of state information tuples
            A list of body state information for each body in the world. See
            :func:`Body.state`.


return False<EOL>

Return True iff the world needs to be reset.


assert len(axes) == self.ADOF<EOL>for i, ax in enumerate(axes):<EOL><INDENT>if ax is None:<EOL><INDENT>continue<EOL><DEDENT>if not isinstance(ax, dict):<EOL><INDENT>ax = dict(axis=ax)<EOL><DEDENT>self.ode_obj.setAxis(i, ax.get('<STR_LIT>', <NUM_LIT:0>), ax['<STR_LIT>'])<EOL><DEDENT>

Set the axes for this object's degrees of freedom.

        Parameters
        ----------
        axes : list of axis parameters
            A list of axis values to set. This list must have the same number of
            elements as the degrees of freedom of the underlying ODE object.
            Each element can be

            (a) None, which has no effect on the corresponding axis, or
            (b) three floats specifying the axis to set, or
            (c) a dictionary with an "axis" key specifying the axis to set and
                an optional "rel" key (defaults to 0) specifying the relative
                body to set the axis on.


Axis of rotation and displacement for this joint.


def connect_to(self, joint, other_body, offset=(<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>), other_offset=(<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0>),<EOL>**kwargs):

anchor = self.world.move_next_to(self, other_body, offset, other_offset)<EOL>self.world.join(joint, self, other_body, anchor=anchor, **kwargs)<EOL>

Move another body next to this one and join them together.

        This method will move the ``other_body`` so that the anchor points for
        the joint coincide. It then creates a joint to fasten the two bodies
        together. See :func:`World.move_next_to` and :func:`World.join`.

        Parameters
        ----------
        joint : str
            The type of joint to use when connecting these bodies.
        other_body : :class:`Body` or str
            The other body to join with this one.
        offset : 3-tuple of float, optional
            The body-relative offset where the anchor for the joint should be
            placed. Defaults to (0, 0, 0). See :func:`World.move_next_to` for a
            description of how offsets are specified.
        other_offset : 3-tuple of float, optional
            The offset on the second body where the joint anchor should be
            placed. Defaults to (0, 0, 0). Like ``offset``, this is given as an
            offset relative to the size and shape of ``other_body``.


_set_params(self.ode_obj, '<STR_LIT>', velocities, self.ADOF + self.LDOF)<EOL>

Set the target velocities for this object's degrees of freedom.

        Parameters
        ----------
        velocities : float or sequence of float
            A target velocity value to set on all degrees of freedom, or a list
            containing one such value for each degree of freedom. For rotational
            degrees of freedom, these values must be in radians / second.


assert self.name == state.name,'<STR_LIT>'.format(state.name, self.name)<EOL>self.position = state.position<EOL>self.quaternion = state.quaternion<EOL>self.linear_velocity = state.linear_velocity<EOL>self.angular_velocity = state.angular_velocity<EOL>

Set the state of this body.

        Parameters
        ----------
        state : BodyState tuple
            The desired state of the body.


for k in sorted(self._joints):<EOL><INDENT>yield self._joints[k]<EOL><DEDENT>

Sequence of all joints in the world, sorted by name.


return self.ode_world.setERP(erp)<EOL>

Set the global ERP value.

        Parameters
        ----------
        erp : float
            The desired global ERP value.


return [self.ode_obj.getPosition()]<EOL>

List of positions for this joint's linear degrees of freedom.


return _get_params(self.ode_obj, '<STR_LIT>', self.ADOF + self.LDOF)<EOL>

List of lo stop values for this object's degrees of freedom.


for state in states:<EOL><INDENT>self.get_body(state.name).state = state<EOL><DEDENT>

Set the states of some bodies in the world.

        Parameters
        ----------
        states : sequence of states
            A complete state tuple for one or more bodies in the world. See
            :func:`get_body_states`.


return np.array(self.ode_body.getPosition())<EOL>

The (x, y, z) coordinates of the center of this body.


Add the given torques along this joint's axes.

        Parameters
        ----------
        torques : sequence of float
            A sequence of torque values to apply to this motor's axes.


return np.array(self.ode_body.getAngularVel())<EOL>

Current angular velocity of this body (in world coordinates).


_set_params(self.ode_obj, '<STR_LIT>', hi_stops, self.ADOF + self.LDOF)<EOL>

Set the hi stop values for this object's degrees of freedom.

        Parameters
        ----------
        hi_stops : float or sequence of float
            A hi stop value to set on all degrees of freedom, or a list
            containing one such value for each degree of freedom. For rotational
            degrees of freedom, these values must be in radians.


def on_key_press(self, key, modifiers, keymap):

if key == keymap.ENTER:<EOL><INDENT>self.reset()<EOL>return True<EOL><DEDENT>

Handle an otherwise unhandled keypress event (from a GUI).


def are_connected(self, body_a, body_b):

return bool(ode.areConnected(<EOL>self.get_body(body_a).ode_body,<EOL>self.get_body(body_b).ode_body))<EOL>

Determine whether the given bodies are currently connected.

        Parameters
        ----------
        body_a : str or :class:`Body`
            One body to test for connectedness. If this is a string, it is
            treated as the name of a body to look up.
        body_b : str or :class:`Body`
            One body to test for connectedness. If this is a string, it is
            treated as the name of a body to look up.

        Returns
        -------
        connected : bool
            Return True iff the two bodies are connected.


return self.ode_world.setGravity(gravity)<EOL>

Set the gravity vector in the world.

        Parameters
        ----------
        gravity : 3-tuple of float
            The vector where gravity should point.


return [np.array(self.ode_obj.getAxis(i))<EOL>for i in range(self.ADOF or self.LDOF)]<EOL>

List of axes for this object's degrees of freedom.


List of hi stop values for this object's degrees of freedom.


self.ode_body.setLinearVel(tuple(velocity))<EOL>

Set the linear velocity for this body.

        Parameters
        ----------
        velocity : 3-tuple of float
            The desired velocity for this body, in world coordinates.


self.ode_body.setAngularVel(tuple(velocity))<EOL>

Set the angular velocity for this body.

        Parameters
        ----------
        velocity : 3-tuple of float
            The desired angular velocity for this body, in world coordinates.


return np.array(self.ode_body.getQuaternion())<EOL>

The (w, x, y, z) rotation quaternion for this body.


return [self.ode_obj.getAngle(i) for i in range(self.ADOF)]<EOL>

List of angles for rotational degrees of freedom.


return [self.ode_obj.getAngleRate()]<EOL>

List of angle rates for this joint's degrees of freedom.


lines = <NUM_LIT:0><EOL>frames = <NUM_LIT:1><EOL>frame = {}<EOL>degrees = False<EOL>for line in source:<EOL><INDENT>lines += <NUM_LIT:1><EOL>line = line.split('<STR_LIT:#>')[<NUM_LIT:0>].strip()<EOL>if not line:<EOL><INDENT>continue<EOL><DEDENT>if line.startswith('<STR_LIT::>'):<EOL><INDENT>if line.lower().startswith('<STR_LIT>'):<EOL><INDENT>degrees = True<EOL><DEDENT>continue<EOL><DEDENT>if line.isdigit():<EOL><INDENT>if int(line) != frames:<EOL><INDENT>raise RuntimeError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(lines, frames, line))<EOL><DEDENT>yield frame<EOL>frames += <NUM_LIT:1><EOL>frame = {}<EOL>continue<EOL><DEDENT>fields = line.split()<EOL>frame[fields[<NUM_LIT:0>]] = list(map(float, fields[<NUM_LIT:1>:]))<EOL><DEDENT>

Parse an AMC motion capture data file.

    Parameters
    ----------
    source : file
        A file-like object that contains AMC motion capture text.

    Yields
    ------
    frame : dict
        Yields a series of motion capture frames. Each frame is a dictionary
        that maps a bone name to a list of the DOF configurations for that bone.


stack = ['<STR_LIT:root>']<EOL>while stack:<EOL><INDENT>parent = stack.pop()<EOL>for child in self.hierarchy.get(parent, ()):<EOL><INDENT>stack.append(child)<EOL><DEDENT>if parent not in self.bones:<EOL><INDENT>continue<EOL><DEDENT>bone = self.bones[parent]<EOL>body = [b for b in self.bodies if b.name == parent][<NUM_LIT:0>]<EOL>for child in self.hierarchy.get(parent, ()):<EOL><INDENT>child_bone = self.bones[child]<EOL>child_body = [b for b in self.bodies if b.name == child][<NUM_LIT:0>]<EOL>shape = ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>')[len(child_bone.dof)]<EOL>self.joints.append(self.world.join(shape, body, child_body))<EOL><DEDENT><DEDENT>

Traverse the bone hierarchy and create physics joints.


return [b.state for b in self.bodies]<EOL>

Return a list of the states of all bodies in the skeleton.


def pid(kp=<NUM_LIT:0.>, ki=<NUM_LIT:0.>, kd=<NUM_LIT:0.>, smooth=<NUM_LIT:0.1>):

state = dict(p=<NUM_LIT:0>, i=<NUM_LIT:0>, d=<NUM_LIT:0>)<EOL>def control(error, dt=<NUM_LIT:1>):<EOL><INDENT>state['<STR_LIT:d>'] = smooth * state['<STR_LIT:d>'] + (<NUM_LIT:1> - smooth) * (error - state['<STR_LIT:p>']) / dt<EOL>state['<STR_LIT:i>'] += error * dt<EOL>state['<STR_LIT:p>'] = error<EOL>return kp * state['<STR_LIT:p>'] + ki * state['<STR_LIT:i>'] + kd * state['<STR_LIT:d>']<EOL><DEDENT>return control<EOL>

r'''Create a callable that implements a PID controller.

    A PID controller returns a control signal :math:`u(t)` given a history of
    error measurements :math:`e(0) \dots e(t)`, using proportional (P), integral
    (I), and derivative (D) terms, according to:

    .. math::

       u(t) = kp * e(t) + ki * \int_{s=0}^t e(s) ds + kd * \frac{de(s)}{ds}(t)

    The proportional term is just the current error, the integral term is the
    sum of all error measurements, and the derivative term is the instantaneous
    derivative of the error measurement.

    Parameters
    ----------
    kp : float
        The weight associated with the proportional term of the PID controller.
    ki : float
        The weight associated with the integral term of the PID controller.
    kd : float
        The weight associated with the derivative term of the PID controller.
    smooth : float in [0, 1]
        Derivative values will be smoothed with this exponential average. A
        value of 1 never incorporates new derivative information, a value of 0.5
        uses the mean of the historic and new information, and a value of 0
        discards historic information (i.e., the derivative in this case will be
        unsmoothed). The default is 0.1.

    Returns
    -------
    controller : callable (float, float) -> float
        Returns a function that accepts an error measurement and a delta-time
        value since the previous measurement, and returns a control signal.


j = <NUM_LIT:0><EOL>for joint in self.joints:<EOL><INDENT>velocities = [<EOL>ctrl(tgt - cur, self.world.dt) for cur, tgt, ctrl in<EOL>zip(joint.angles, angles[j:j+joint.ADOF], joint.controllers)]<EOL>joint.velocities = velocities<EOL>j += joint.ADOF<EOL><DEDENT>

Move each joint toward a target angle.

        This method uses a PID controller to set a target angular velocity for
        each degree of freedom in the skeleton, based on the difference between
        the current and the target angle for the respective DOF.

        PID parameters are by default set to achieve a tiny bit less than
        complete convergence in one time step, using only the P term (i.e., the
        P coefficient is set to 1 - \delta, while I and D coefficients are set
        to 0). PID parameters can be updated by calling the `set_pid_params`
        method.

        Parameters
        ----------
        angles : list of float
            A list of the target angles for every joint in the skeleton.


def set_pid_params(self, *args, **kwargs):

for joint in self.joints:<EOL><INDENT>joint.target_angles = [None] * joint.ADOF<EOL>joint.controllers = [pid(*args, **kwargs) for i in range(joint.ADOF)]<EOL><DEDENT>

Set PID parameters for all joints in the skeleton.

        Parameters for this method are passed directly to the `pid` constructor.


for state in states:<EOL><INDENT>self.world.get_body(state.name).state = state<EOL><DEDENT>

Set the states of all bodies in the skeleton.


j = <NUM_LIT:0><EOL>for joint in self.joints:<EOL><INDENT>joint.add_torques(<EOL>list(torques[j:j+joint.ADOF]) + [<NUM_LIT:0>] * (<NUM_LIT:3> - joint.ADOF))<EOL>j += joint.ADOF<EOL><DEDENT>

Add torques for each degree of freedom in the skeleton.

        Parameters
        ----------
        torques : list of float
            A list of the torques to add to each degree of freedom in the
            skeleton.


Disable joint motors in this skeleton.

        This method sets to 0 the maximum force that joint motors are allowed to
        apply, in addition to disabling torque feedback.


arr = []<EOL>for x in iterables:<EOL><INDENT>arr.extend(x)<EOL><DEDENT>return np.array(arr)<EOL>

Given a sequence of sequences, return a flat numpy array.

    Parameters
    ----------
    iterables : sequence of sequence of number
        A sequence of tuples or lists containing numbers. Typically these come
        from something that represents each joint in a skeleton, like angle.

    Returns
    -------
    ndarray :
        An array of flattened data from each of the source iterables.


return as_flat_array(b.linear_velocity for b in self.bodies)<EOL>

Get a list of all current body velocities in the skeleton.


return as_flat_array(getattr(j, '<STR_LIT>', j).feedback[-<NUM_LIT:1>][:j.ADOF]<EOL>for j in self.joints)<EOL>

Get a list of all current joint torques in the skeleton.


for frame in self._frozen:<EOL><INDENT>for body in frame:<EOL><INDENT>self.draw_body(body)<EOL><DEDENT><DEDENT>for body in self.world.bodies:<EOL><INDENT>self.draw_body(body)<EOL><DEDENT>if hasattr(self.world, '<STR_LIT>'):<EOL><INDENT>window.glColor4f(<NUM_LIT>, <NUM_LIT:0.1>, <NUM_LIT:0.1>, <NUM_LIT>)<EOL>window.glLineWidth(<NUM_LIT:3>)<EOL>for j in self.world.markers.joints.values():<EOL><INDENT>window.glBegin(window.GL_LINES)<EOL>window.glVertex3f(*j.getAnchor())<EOL>window.glVertex3f(*j.getAnchor2())<EOL>window.glEnd()<EOL><DEDENT><DEDENT>


self.bodies = {}<EOL>for label in self.channels:<EOL><INDENT>body = self.world.create_body(<EOL>'<STR_LIT>', name='<STR_LIT>'.format(label), radius=<NUM_LIT>)<EOL>body.is_kinematic = True<EOL>body.color = <NUM_LIT>, <NUM_LIT:0.1>, <NUM_LIT:0.1>, <NUM_LIT:0.5><EOL>self.bodies[label] = body<EOL><DEDENT>

Create physics bodies corresponding to each marker in our data.


def follow_markers(self, start=<NUM_LIT:0>, end=<NUM_LIT>, states=None):

if states is not None:<EOL><INDENT>self.skeleton.set_body_states(states)<EOL><DEDENT>for frame_no, frame in enumerate(self.markers):<EOL><INDENT>if frame_no < start:<EOL><INDENT>continue<EOL><DEDENT>if frame_no >= end:<EOL><INDENT>break<EOL><DEDENT>for states in self._step_to_marker_frame(frame_no):<EOL><INDENT>yield states<EOL><DEDENT><DEDENT>

Iterate over a set of marker data, dragging its skeleton along.

        Parameters
        ----------
        start : int, optional
            Start following marker data after this frame. Defaults to 0.
        end : int, optional
            Stop following marker data after this frame. Defaults to the end of
            the marker data.
        states : list of body states, optional
            If given, set the states of the skeleton bodies to these values
            before starting to follow the marker data.


for label, j in self.channels.items():<EOL><INDENT>body = self.bodies[label]<EOL>body.position = self.positions[frame_no, j]<EOL>body.linear_velocity = self.velocities[frame_no, j]<EOL><DEDENT>

Reposition markers to a specific frame of data.

        Parameters
        ----------
        frame_no : int
            The frame of data where we should reposition marker bodies. Markers
            will be positioned in the appropriate places in world coordinates.
            In addition, linear velocities of the markers will be set according
            to the data as long as there are no dropouts in neighboring frames.


return self.data.shape[<NUM_LIT:0>]<EOL>

Return the number of frames of marker data.


self.jointgroup.empty()<EOL>self.joints = {}<EOL>

Detach all marker bodies from their associated skeleton bodies.


def inverse_dynamics(self, angles, start=<NUM_LIT:0>, end=<NUM_LIT>, states=None, max_force=<NUM_LIT:100>):

if states is not None:<EOL><INDENT>self.skeleton.set_body_states(states)<EOL><DEDENT>for frame_no, frame in enumerate(angles):<EOL><INDENT>if frame_no < start:<EOL><INDENT>continue<EOL><DEDENT>if frame_no >= end:<EOL><INDENT>break<EOL><DEDENT>self.ode_space.collide(None, self.on_collision)<EOL>states = self.skeleton.get_body_states()<EOL>self.skeleton.set_body_states(states)<EOL>self.skeleton.enable_motors(max_force)<EOL>self.skeleton.set_target_angles(angles[frame_no])<EOL>self.ode_world.step(self.dt)<EOL>torques = self.skeleton.joint_torques<EOL>self.skeleton.disable_motors()<EOL>self.skeleton.set_body_states(states)<EOL>self.skeleton.add_torques(torques)<EOL>yield torques<EOL>self.ode_world.step(self.dt)<EOL>self.ode_contactgroup.empty()<EOL><DEDENT>

Follow a set of angle data, yielding dynamic joint torques.

        Parameters
        ----------
        angles : ndarray (num-frames x num-dofs)
            Follow angle data provided by this array of angle values.
        start : int, optional
            Start following angle data after this frame. Defaults to the start
            of the angle data.
        end : int, optional
            Stop following angle data after this frame. Defaults to the end of
            the angle data.
        states : list of body states, optional
            If given, set the states of the skeleton bodies to these values
            before starting to follow the marker data.
        max_force : float, optional
            Allow each degree of freedom in the skeleton to exert at most this
            force when attempting to follow the given joint angles. Defaults to
            100N. Setting this value to be large results in more accurate
            following but can cause oscillations in the PID controllers,
            resulting in noisy torques.

        Returns
        -------
        torques : sequence of torque frames
            Returns a generator of joint torque data for the skeleton. One set
            of joint torques will be generated for each frame of angle data
            between `start` and `end`.


<EOL>self.frame_no += <NUM_LIT:1><EOL>try:<EOL><INDENT>next(self.follower)<EOL><DEDENT>except (AttributeError, StopIteration) as err:<EOL><INDENT>self.reset()<EOL><DEDENT>

Advance the physics world by one step.

        Typically this is called as part of a :class:`pagoda.viewer.Viewer`, but
        it can also be called manually (or some other stepping mechanism
        entirely can be used).


def load_attachments(self, source, skeleton):

self.targets = {}<EOL>self.offsets = {}<EOL>filename = source<EOL>if isinstance(source, str):<EOL><INDENT>source = open(source)<EOL><DEDENT>else:<EOL><INDENT>filename = '<STR_LIT>'.format(id(source))<EOL><DEDENT>for i, line in enumerate(source):<EOL><INDENT>tokens = line.split('<STR_LIT:#>')[<NUM_LIT:0>].strip().split()<EOL>if not tokens:<EOL><INDENT>continue<EOL><DEDENT>label = tokens.pop(<NUM_LIT:0>)<EOL>if label not in self.channels:<EOL><INDENT>logging.info('<STR_LIT>', filename, i, label)<EOL>continue<EOL><DEDENT>if not tokens:<EOL><INDENT>continue<EOL><DEDENT>name = tokens.pop(<NUM_LIT:0>)<EOL>bodies = [b for b in skeleton.bodies if b.name == name]<EOL>if len(bodies) != <NUM_LIT:1>:<EOL><INDENT>logging.info('<STR_LIT>',<EOL>filename, i, len(bodies), name)<EOL>continue<EOL><DEDENT>b = self.targets[label] = bodies[<NUM_LIT:0>]<EOL>o = self.offsets[label] =np.array(list(map(float, tokens))) * b.dimensions / <NUM_LIT:2><EOL>logging.info('<STR_LIT>', label, b.name, o)<EOL><DEDENT>

Load attachment configuration from the given text source.

        The attachment configuration file has a simple format. After discarding
        Unix-style comments (any part of a line that starts with the pound (#)
        character), each line in the file is then expected to have the following
        format::

            marker-name body-name X Y Z

        The marker name must correspond to an existing "channel" in our marker
        data. The body name must correspond to a rigid body in the skeleton. The
        X, Y, and Z coordinates specify the body-relative offsets where the
        marker should be attached: 0 corresponds to the center of the body along
        the given axis, while -1 and 1 correspond to the minimal (maximal,
        respectively) extent of the body's bounding box along the corresponding
        dimension.

        Parameters
        ----------
        source : str or file-like
            A filename or file-like object that we can use to obtain text
            configuration that describes how markers are attached to skeleton
            bodies.

        skeleton : :class:`pagoda.skeleton.Skeleton`
            The skeleton to attach our marker data to.


cfm = self.cfms[self._frame_no][:, None]<EOL>kp = self.erp / (cfm * self.world.dt)<EOL>kd = (<NUM_LIT:1> - self.erp) / cfm<EOL>dx = self.distances()<EOL>F = kp * dx<EOL>if dx_tm1 is not None:<EOL><INDENT>bad = np.isnan(dx) | np.isnan(dx_tm1)<EOL>F[~bad] += (kd * (dx - dx_tm1) / self.world.dt)[~bad]<EOL><DEDENT>return F<EOL>

Return an array of the forces exerted by marker springs.

        Notes
        -----

        The forces exerted by the marker springs can be approximated by::

          F = kp * dx

        where ``dx`` is the current array of marker distances. An even more
        accurate value is computed by approximating the velocity of the spring
        displacement::

          F = kp * dx + kd * (dx - dx_tm1) / dt

        where ``dx_tm1`` is an array of distances from the previous time step.

        Parameters
        ----------
        dx_tm1 : ndarray
            An array of distances from markers to their attachment targets,
            measured at the previous time step.

        Returns
        -------
        F : ndarray
            An array of forces that the markers are exerting on the skeleton.


distances = []<EOL>for label in self.labels:<EOL><INDENT>joint = self.joints.get(label)<EOL>distances.append([np.nan, np.nan, np.nan] if joint is None else<EOL>np.array(joint.getAnchor()) - joint.getAnchor2())<EOL><DEDENT>return np.array(distances)<EOL>

Get a list of the distances between markers and their attachments.

        Returns
        -------
        distances : ndarray of shape (num-markers, 3)
            Array of distances for each marker joint in our attachment setup. If
            a marker does not currently have an associated joint (e.g. because
            it is not currently visible) this will contain NaN for that row.


def load_c3d(self, filename, start_frame=<NUM_LIT:0>, max_frames=int(<NUM_LIT>)):

import c3d<EOL>with open(filename, '<STR_LIT:rb>') as handle:<EOL><INDENT>reader = c3d.Reader(handle)<EOL>logging.info('<STR_LIT>',<EOL><NUM_LIT:1> / self.world.dt, reader.point_rate)<EOL>self.channels = self._map_labels_to_channels([<EOL>s.strip() for s in reader.point_labels])<EOL>data = []<EOL>for i, (_, frame, _) in enumerate(reader.read_frames()):<EOL><INDENT>if i >= start_frame:<EOL><INDENT>data.append(frame[:, [<NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:2>, <NUM_LIT:4>]])<EOL><DEDENT>if len(data) > max_frames:<EOL><INDENT>break<EOL><DEDENT><DEDENT>self.data = np.array(data)<EOL>if reader.get('<STR_LIT>').string_value.strip().lower() == '<STR_LIT>':<EOL><INDENT>logging.info('<STR_LIT>')<EOL>self.data[:, :, :<NUM_LIT:3>] /= <NUM_LIT><EOL><DEDENT><DEDENT>logging.info('<STR_LIT>', filename, self.data.shape)<EOL>self.process_data()<EOL>self.create_bodies()<EOL>

Load marker data from a C3D file.

        The file will be imported using the c3d module, which must be installed
        to use this method. (``pip install c3d``)

        Parameters
        ----------
        filename : str
            Name of the C3D file to load.
        start_frame : int, optional
            Discard the first N frames. Defaults to 0.
        max_frames : int, optional
            Maximum number of frames to load. Defaults to loading all frames.


self.visibility = self.data[:, :, <NUM_LIT:3>]<EOL>self.positions = self.data[:, :, :<NUM_LIT:3>]<EOL>self.velocities = np.zeros_like(self.positions) + <NUM_LIT:1000><EOL>for frame_no in range(<NUM_LIT:1>, len(self.data) - <NUM_LIT:1>):<EOL><INDENT>prev = self.data[frame_no - <NUM_LIT:1>]<EOL>next = self.data[frame_no + <NUM_LIT:1>]<EOL>for c in range(self.num_markers):<EOL><INDENT>if -<NUM_LIT:1> < prev[c, <NUM_LIT:3>] < <NUM_LIT:100> and -<NUM_LIT:1> < next[c, <NUM_LIT:3>] < <NUM_LIT:100>:<EOL><INDENT>self.velocities[frame_no, c] = (<EOL>next[c, :<NUM_LIT:3>] - prev[c, :<NUM_LIT:3>]) / (<NUM_LIT:2> * self.world.dt)<EOL><DEDENT><DEDENT><DEDENT>self.cfms = np.zeros_like(self.visibility) + self.DEFAULT_CFM<EOL>

Process data to produce velocity and dropout information.


def _step_to_marker_frame(self, frame_no, dt=None):

<EOL>self.markers.detach()<EOL>self.markers.reposition(frame_no)<EOL>self.markers.attach(frame_no)<EOL>self.ode_space.collide(None, self.on_collision)<EOL>states = self.skeleton.get_body_states()<EOL>self.skeleton.set_body_states(states)<EOL>yield states<EOL>self.ode_world.step(dt or self.dt)<EOL>self.ode_contactgroup.empty()<EOL>

Update the simulator to a specific frame of marker data.

        This method returns a generator of body states for the skeleton! This
        generator must be exhausted (e.g., by consuming this call in a for loop)
        for the simulator to work properly.

        This process involves the following steps:

        - Move the markers to their new location:
          - Detach from the skeleton
          - Update marker locations
          - Reattach to the skeleton
        - Detect ODE collisions
        - Yield the states of the bodies in the skeleton
        - Advance the ODE world one step

        Parameters
        ----------
        frame_no : int
            Step to this frame of marker data.
        dt : float, optional
            Step with this time duration. Defaults to ``self.dt``.

        Returns
        -------
        states : sequence of state tuples
            A generator of a sequence of one body state for the skeleton. This
            generator must be exhausted for the simulation to work properly.


def inverse_kinematics(self, start=<NUM_LIT:0>, end=<NUM_LIT>, states=None, max_force=<NUM_LIT:20>):

zeros = None<EOL>if max_force > <NUM_LIT:0>:<EOL><INDENT>self.skeleton.enable_motors(max_force)<EOL>zeros = np.zeros(self.skeleton.num_dofs)<EOL><DEDENT>for _ in self.follow_markers(start, end, states):<EOL><INDENT>if zeros is not None:<EOL><INDENT>self.skeleton.set_target_angles(zeros)<EOL><DEDENT>yield self.skeleton.joint_angles<EOL><DEDENT>

Follow a set of marker data, yielding kinematic joint angles.

        Parameters
        ----------
        start : int, optional
            Start following marker data after this frame. Defaults to 0.
        end : int, optional
            Stop following marker data after this frame. Defaults to the end of
            the marker data.
        states : list of body states, optional
            If given, set the states of the skeleton bodies to these values
            before starting to follow the marker data.
        max_force : float, optional
            Allow each degree of freedom in the skeleton to exert at most this
            force when attempting to maintain its equilibrium position. This
            defaults to 20N. Set this value higher to simulate a stiff skeleton
            while following marker data.

        Returns
        -------
        angles : sequence of angle frames
            Returns a generator of joint angle data for the skeleton. One set of
            joint angles will be generated for each frame of marker data between
            `start` and `end`.


<EOL>rx_symb_d = np.zeros(int(np.fix(len(y)/Ns)))<EOL>track = np.zeros(int(np.fix(len(y)/Ns)))<EOL>bit_count = -<NUM_LIT:1><EOL>y_abs = np.zeros(len(y))<EOL>clk = np.zeros(len(y))<EOL>k = Ns+<NUM_LIT:1> <EOL>for i in range(len(y)):<EOL><INDENT>if i >= Ns: <EOL><INDENT>y_abs[i] = np.abs(np.sum(y[i-Ns+<NUM_LIT:1>:i+<NUM_LIT:1>]))<EOL>if (k == <NUM_LIT:0>):<EOL><INDENT>w_hat = y_abs[i-<NUM_LIT:2>:i+<NUM_LIT:1>]<EOL>bit_count += <NUM_LIT:1><EOL>if w_hat[<NUM_LIT:1>] != <NUM_LIT:0>:<EOL><INDENT>if w_hat[<NUM_LIT:0>] < w_hat[<NUM_LIT:2>]:<EOL><INDENT>k = Ns-<NUM_LIT:1><EOL>clk[i-<NUM_LIT:2>] = <NUM_LIT:1><EOL>rx_symb_d[bit_count] = y[i-<NUM_LIT:2>-int(np.round(Ns/<NUM_LIT:2>))-<NUM_LIT:1>]<EOL><DEDENT>elif w_hat[<NUM_LIT:0>] > w_hat[<NUM_LIT:2>]:<EOL><INDENT>k = Ns+<NUM_LIT:1><EOL>clk[i] = <NUM_LIT:1><EOL>rx_symb_d[bit_count] = y[i-int(np.round(Ns/<NUM_LIT:2>))-<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>k = Ns<EOL>clk[i-<NUM_LIT:1>] = <NUM_LIT:1><EOL>rx_symb_d[bit_count] = y[i-<NUM_LIT:1>-int(np.round(Ns/<NUM_LIT:2>))-<NUM_LIT:1>]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>k = Ns<EOL>clk[i-<NUM_LIT:1>] = <NUM_LIT:1><EOL>rx_symb_d[bit_count] = y[i-<NUM_LIT:1>-int(np.round(Ns/<NUM_LIT:2>))]<EOL><DEDENT>track[bit_count] = np.mod(i,Ns)<EOL><DEDENT><DEDENT>k -= <NUM_LIT:1><EOL><DEDENT>rx_symb_d = rx_symb_d[:bit_count]<EOL>return rx_symb_d, clk, track<EOL>

rx_symb_d,clk,track = sccs_bit_sync(y,Ns)

//////////////////////////////////////////////////////
 Symbol synchronization algorithm using SCCS
//////////////////////////////////////////////////////
     y = baseband NRZ data waveform
    Ns = nominal number of samples per symbol

Reworked from ECE 5675 Project
Translated from m-code version
Mark Wickert April 2014


fs, x_LR_cols = ss.from_wav(filename)<EOL>x = x_LR_cols[:,<NUM_LIT:0>] + <NUM_LIT>*x_LR_cols[:,<NUM_LIT:1>]<EOL>return fs,x<EOL>

Return a complex signal vector from a wav file that was used to store
the real (I) and imaginary (Q) values of a complex signal ndarray.
The rate is included as means of recalling the original signal sample
rate.

fs,x = wav2complex(filename)

Mark Wickert April 2014


x_wav = np.hstack((np.array([x.real]).T,np.array([x.imag]).T))<EOL>ss.to_wav(filename, rate, x_wav)<EOL>print('<STR_LIT>')<EOL>

Save a complex signal vector to a wav file for compact binary
storage of 16-bit signal samples. The wav left and right channels
are used to save real (I) and imaginary (Q) values. The rate is
just a convent way of documenting the original signal sample rate.

complex2wav(filename,rate,x)

Mark Wickert April 2014


Nbits = len(rx_data)<EOL>c = dc.m_seq(m)<EOL>if flip == <NUM_LIT:1>:<EOL><INDENT>c.shape = (<NUM_LIT:1>,len(c))<EOL>c = np.fliplr(c).flatten()<EOL><DEDENT>L = int(np.ceil(Nbits/float(len(c))))<EOL>tx_data = np.dot(c.reshape(len(c),<NUM_LIT:1>),np.ones((<NUM_LIT:1>,L)))<EOL>tx_data = tx_data.T.reshape((<NUM_LIT:1>,len(c)*L)).flatten()<EOL>tx_data = tx_data[:Nbits]<EOL>tx_data = <NUM_LIT:2>*tx_data - <NUM_LIT:1><EOL>Bit_count,Bit_errors = dc.BPSK_BEP(rx_data,tx_data)<EOL>print('<STR_LIT>' % (len(rx_data),len(tx_data)))<EOL>Pe = Bit_errors/float(Bit_count)<EOL>print('<STR_LIT>')<EOL>print('<STR_LIT>' % Bit_errors)<EOL>print('<STR_LIT>' % Bit_count)<EOL>print('<STR_LIT>' % Pe)<EOL>print('<STR_LIT>')<EOL>

fsk_BEP(rx_data,m,flip)

Estimate the BEP of the data bits recovered
by the RTL-SDR Based FSK Receiver.

The reference m-sequence generated in Python
was found to produce sequences running in the opposite
direction relative to the m-sequences generated by the
mbed. To allow error detection the reference m-sequence
is flipped.

Mark Wickert April 2014


<EOL>if(len(x) % self.k or len(x) < self.k):<EOL><INDENT>raise ValueError('<STR_LIT>' %self.k)<EOL><DEDENT>if(np.dtype(x[<NUM_LIT:0>]) != int):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>Num_blocks = int(len(x) / self.k)<EOL>codewords = np.zeros((Num_blocks,self.n),dtype=int)<EOL>x = np.reshape(x,(Num_blocks,self.k))<EOL>for p in range(Num_blocks):<EOL><INDENT>S = np.zeros(len(self.G))<EOL>codeword = np.zeros(self.n)<EOL>current_block = x[p,:]<EOL>for i in range(<NUM_LIT:0>,self.n):<EOL><INDENT>if(i < self.k):<EOL><INDENT>S[<NUM_LIT:0>] = current_block[i]<EOL>S0temp = <NUM_LIT:0><EOL>for m in range(<NUM_LIT:0>,len(self.G)):<EOL><INDENT>if(self.G[m] == '<STR_LIT:1>'):<EOL><INDENT>S0temp = S0temp + S[m]<EOL><DEDENT><DEDENT>S0temp = S0temp % <NUM_LIT:2><EOL>S = np.roll(S,<NUM_LIT:1>)<EOL>codeword[i] = current_block[i]<EOL>S[<NUM_LIT:1>] = S0temp<EOL><DEDENT>else:<EOL><INDENT>out = <NUM_LIT:0><EOL>for m in range(<NUM_LIT:1>,len(self.G)):<EOL><INDENT>if(self.G[m] == '<STR_LIT:1>'):<EOL><INDENT>out = out + S[m]<EOL><DEDENT><DEDENT>codeword[i] = out % <NUM_LIT:2><EOL>S = np.roll(S,<NUM_LIT:1>)<EOL>S[<NUM_LIT:1>] = <NUM_LIT:0><EOL><DEDENT><DEDENT>codewords[p,:] = codeword<EOL><DEDENT>codewords = np.reshape(codewords,np.size(codewords))<EOL>return codewords.astype(int)<EOL>

Encodes input bit array x using cyclic block code.

parameters
----------
x: vector of source bits to be encoded by block encoder. Numpy array
   of integers expected.

returns
-------
codewords: vector of code words generated from input vector

Andrew Smit November 2018


Pb = np.zeros_like(SNRdB)<EOL>Ps = np.zeros_like(SNRdB)<EOL>SNR = <NUM_LIT>**(SNRdB/<NUM_LIT>)<EOL>n = <NUM_LIT:2>**j-<NUM_LIT:1><EOL>k = n-j<EOL>for i,SNRn in enumerate(SNR):<EOL><INDENT>if coded: <EOL><INDENT>if M == <NUM_LIT:2>:<EOL><INDENT>Ps[i] = Q_fctn(np.sqrt(k*<NUM_LIT>*SNRn/n))<EOL><DEDENT>else:<EOL><INDENT>Ps[i] = <NUM_LIT>/np.log2(M)*(<NUM_LIT:1> - <NUM_LIT:1>/np.sqrt(M))*np.gaussQ(np.sqrt(<NUM_LIT:3>*np.log2(M)/(M-<NUM_LIT:1>)*SNRn))/k<EOL><DEDENT><DEDENT>else: <EOL><INDENT>if M == <NUM_LIT:2>:<EOL><INDENT>Pb[i] = Q_fctn(np.sqrt(<NUM_LIT>*SNRn))<EOL><DEDENT>else:<EOL><INDENT>Pb[i] = <NUM_LIT>/np.log2(M)*(<NUM_LIT:1> - <NUM_LIT:1>/np.sqrt(M))*np.gaussQ(np.sqrt(<NUM_LIT:3>*np.log2(M)/(M-<NUM_LIT:1>)*SNRn))<EOL><DEDENT><DEDENT><DEDENT>if coded:<EOL><INDENT>Pb = ser2ber(M,n,<NUM_LIT:3>,<NUM_LIT:1>,Ps)<EOL><DEDENT>return Pb<EOL>

Finds the bit error probability bounds according to Ziemer and Tranter
page 656.

parameters:
-----------
j: number of parity bits used in single error correction block code
SNRdB: Eb/N0 values in dB
coded: Select single error correction code (True) or uncoded (False)
M: modulation order

returns:
--------
Pb: bit error probability bound


if(j < <NUM_LIT:3>):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>n = <NUM_LIT:2>**j-<NUM_LIT:1><EOL>k = n-j<EOL>G = np.zeros((k,n),dtype=int)<EOL>H = np.zeros((j,n),dtype=int)<EOL>P = np.zeros((j,k),dtype=int)<EOL>R = np.zeros((k,n),dtype=int)<EOL>for i in range(<NUM_LIT:1>,n+<NUM_LIT:1>):<EOL><INDENT>b = list(binary(i,j))<EOL>for m in range(<NUM_LIT:0>,len(b)):<EOL><INDENT>b[m] = int(b[m])<EOL><DEDENT>H[:,i-<NUM_LIT:1>] = np.array(b)<EOL><DEDENT>H1 = np.zeros((<NUM_LIT:1>,j),dtype=int)<EOL>H2 = np.zeros((<NUM_LIT:1>,j),dtype=int)<EOL>for i in range(<NUM_LIT:0>,j):<EOL><INDENT>idx1 = <NUM_LIT:2>**i-<NUM_LIT:1><EOL>idx2 = n-i-<NUM_LIT:1><EOL>H1[<NUM_LIT:0>,:] = H[:,idx1]<EOL>H2[<NUM_LIT:0>,:] = H[:,idx2]<EOL>H[:,idx1] = H2<EOL>H[:,idx2] = H1<EOL><DEDENT>P = H[:,:k]<EOL>G[:,:k] = np.diag(np.ones(k))<EOL>G[:,k:] = P.T<EOL>R[:,:k] = np.diag(np.ones(k))<EOL>return G, H, R, n, k<EOL>

Generates parity check matrix (H) and generator
matrix (G).

Parameters
----------
j: Number of Hamming code parity bits with n = 2^j-1 and k = n-j

returns
-------
G: Systematic generator matrix with left-side identity matrix
H: Systematic parity-check matrix with right-side identity matrix
R: k x k identity matrix
n: number of total bits/block
k: number of source bits/block

Andrew Smit November 2018


k = int(k)<EOL>if M == <NUM_LIT:2>:<EOL><INDENT>p = Q_fctn(np.sqrt(<NUM_LIT>*R*SNR))<EOL><DEDENT>else:<EOL><INDENT>p = <NUM_LIT>/np.log2(M)*(<NUM_LIT:1> - <NUM_LIT:1.>/np.sqrt(M))*Q_fctn(np.sqrt(<NUM_LIT:3>*R*np.log2(M)/float(M-<NUM_LIT:1>)*SNR))<EOL><DEDENT>Pk = <NUM_LIT:0><EOL>if np.mod(k,<NUM_LIT:2>) == <NUM_LIT:0>:<EOL><INDENT>for e in range(int(k/<NUM_LIT:2>+<NUM_LIT:1>),int(k+<NUM_LIT:1>)):<EOL><INDENT>Pk += float(factorial(k))/(factorial(e)*factorial(k-e))*p**e*(<NUM_LIT:1>-p)**(k-e);<EOL><DEDENT>Pk += <NUM_LIT:1.>/<NUM_LIT:2>*float(factorial(k))/(factorial(int(k/<NUM_LIT:2>))*factorial(int(k-k/<NUM_LIT:2>)))*p**(k/<NUM_LIT:2>)*(<NUM_LIT:1>-p)**(k/<NUM_LIT:2>);<EOL><DEDENT>elif np.mod(k,<NUM_LIT:2>) == <NUM_LIT:1>:<EOL><INDENT>for e in range(int((k+<NUM_LIT:1>)//<NUM_LIT:2>),int(k+<NUM_LIT:1>)):<EOL><INDENT>Pk += factorial(k)/(factorial(e)*factorial(k-e))*p**e*(<NUM_LIT:1>-p)**(k-e);<EOL><DEDENT><DEDENT>return Pk<EOL>

Pk = hard_Pk(k,R,SNR)

Calculates Pk as found in Ziemer & Peterson eq. 7-12, p.505

Mark Wickert and Andrew Smit 2018


Pb = np.zeros_like(SNRdB)<EOL>SNR = <NUM_LIT>**(SNRdB/<NUM_LIT>)<EOL>for n,SNRn in enumerate(SNR):<EOL><INDENT>for k in range(dfree,len(Ck)+dfree):<EOL><INDENT>if hard_soft == <NUM_LIT:0>: <EOL><INDENT>Pb[n] += Ck[k-dfree]*hard_Pk(k,R,SNRn,M)<EOL><DEDENT>elif hard_soft == <NUM_LIT:1>: <EOL><INDENT>Pb[n] += Ck[k-dfree]*soft_Pk(k,R,SNRn,M)<EOL><DEDENT>else: <EOL><INDENT>if M == <NUM_LIT:2>:<EOL><INDENT>Pb[n] = Q_fctn(np.sqrt(<NUM_LIT>*SNRn))<EOL><DEDENT>else:<EOL><INDENT>Pb[n] = <NUM_LIT>/np.log2(M)*(<NUM_LIT:1> - <NUM_LIT:1>/np.sqrt(M))*np.gaussQ(np.sqrt(<NUM_LIT:3>*np.log2(M)/(M-<NUM_LIT:1>)*SNRn));<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return Pb<EOL>

Coded bit error probabilty

Convolution coding bit error probability upper bound
according to Ziemer & Peterson 7-16, p. 507

Mark Wickert November 2014

Parameters
----------
R: Code rate
dfree: Free distance of the code
Ck: Weight coefficient
SNRdB: Signal to noise ratio in dB
hard_soft: 0 hard, 1 soft, 2 uncoded
M: M-ary

Examples
--------
>>> import numpy as np
>>> from sk_dsp_comm import fec_conv as fec
>>> import matplotlib.pyplot as plt
>>> SNRdB = np.arange(2,12,.1)
>>> Pb = fec.conv_Pb_bound(1./2,10,[36, 0, 211, 0, 1404, 0, 11633],SNRdB,2)
>>> Pb_1_2 = fec.conv_Pb_bound(1./2,10,[36, 0, 211, 0, 1404, 0, 11633],SNRdB,1)
>>> Pb_3_4 = fec.conv_Pb_bound(3./4,4,[164, 0, 5200, 0, 151211, 0, 3988108],SNRdB,1)
>>> plt.semilogy(SNRdB,Pb)
>>> plt.semilogy(SNRdB,Pb_1_2)
>>> plt.semilogy(SNRdB,Pb_3_4)
>>> plt.axis([2,12,1e-7,1e0])
>>> plt.xlabel(r'$E_b/N_0$ (dB)')
>>> plt.ylabel(r'Symbol Error Probability')
>>> plt.legend(('Uncoded BPSK','R=1/2, K=7, Soft','R=3/4 (punc), K=7, Soft'),loc='best')
>>> plt.grid();
>>> plt.show()

Notes
-----
The code rate R is given by :math:`R_{s} = \\frac{k}{n}`.
Mark Wickert and Andrew Smit 2018


return format(num, '<STR_LIT>'.format(length))<EOL>

Format an integer to binary without the leading '0b'


output = []<EOL>if(self.rate == Fraction(<NUM_LIT:1>,<NUM_LIT:2>)):<EOL><INDENT>for n in range(len(input)):<EOL><INDENT>u1 = int(input[n])<EOL>u2 = int(input[n])<EOL>for m in range(<NUM_LIT:1>,self.constraint_length):<EOL><INDENT>if int(self.G_polys[<NUM_LIT:0>][m]) == <NUM_LIT:1>: <EOL><INDENT>u1 = u1 ^ int(state[m-<NUM_LIT:1>])<EOL><DEDENT>if int(self.G_polys[<NUM_LIT:1>][m]) == <NUM_LIT:1>: <EOL><INDENT>u2 = u2 ^ int(state[m-<NUM_LIT:1>])<EOL><DEDENT><DEDENT>output = np.hstack((output, [u1, u2]))<EOL>state = bin(int(input[n]))[-<NUM_LIT:1>] + state[:-<NUM_LIT:1>]<EOL><DEDENT><DEDENT>elif(self.rate == Fraction(<NUM_LIT:1>,<NUM_LIT:3>)):<EOL><INDENT>for n in range(len(input)):<EOL><INDENT>if(int(self.G_polys[<NUM_LIT:0>][<NUM_LIT:0>]) == <NUM_LIT:1>):<EOL><INDENT>u1 = int(input[n])<EOL><DEDENT>else:<EOL><INDENT>u1 = <NUM_LIT:0><EOL><DEDENT>if(int(self.G_polys[<NUM_LIT:1>][<NUM_LIT:0>]) == <NUM_LIT:1>):<EOL><INDENT>u2 = int(input[n])<EOL><DEDENT>else:<EOL><INDENT>u2 = <NUM_LIT:0><EOL><DEDENT>if(int(self.G_polys[<NUM_LIT:2>][<NUM_LIT:0>]) == <NUM_LIT:1>):<EOL><INDENT>u3 = int(input[n])<EOL><DEDENT>else:<EOL><INDENT>u3 = <NUM_LIT:0><EOL><DEDENT>for m in range(<NUM_LIT:1>,self.constraint_length):<EOL><INDENT>if int(self.G_polys[<NUM_LIT:0>][m]) == <NUM_LIT:1>: <EOL><INDENT>u1 = u1 ^ int(state[m-<NUM_LIT:1>])<EOL><DEDENT>if int(self.G_polys[<NUM_LIT:1>][m]) == <NUM_LIT:1>: <EOL><INDENT>u2 = u2 ^ int(state[m-<NUM_LIT:1>])<EOL><DEDENT>if int(self.G_polys[<NUM_LIT:2>][m]) == <NUM_LIT:1>: <EOL><INDENT>u3 = u3 ^ int(state[m-<NUM_LIT:1>])<EOL><DEDENT><DEDENT>output = np.hstack((output, [u1, u2, u3]))<EOL>state = bin(int(input[n]))[-<NUM_LIT:1>] + state[:-<NUM_LIT:1>]<EOL><DEDENT><DEDENT>return output, state<EOL>

output, state = conv_encoder(input,state)
We get the 1/2 or 1/3 rate from self.rate
Polys G1 and G2 are entered as binary strings, e.g,
G1 = '111' and G2 = '101' for K = 3
G1 = '1011011' and G2 = '1111001' for K = 7
G3 is also included for rate 1/3
Input state as a binary string of length K-1, e.g., '00' or '0000000'
e.g., state = '00' for K = 3
e.g., state = '000000' for K = 7
Mark Wickert and Andrew Smit 2018


def __init__(self,G = ('<STR_LIT>','<STR_LIT>'), Depth = <NUM_LIT:10>):

self.G_polys = G<EOL>self.constraint_length = len(self.G_polys[<NUM_LIT:0>]) <EOL>self.Nstates = <NUM_LIT:2>**(self.constraint_length-<NUM_LIT:1>) <EOL>self.decision_depth = Depth<EOL>self.input_zero = trellis_nodes(self.Nstates)<EOL>self.input_one = trellis_nodes(self.Nstates)<EOL>self.paths = trellis_paths(self.Nstates,self.decision_depth)<EOL>self.rate = Fraction(<NUM_LIT:1>,len(G))<EOL>if(len(G) == <NUM_LIT:2> or len(G) == <NUM_LIT:3>):<EOL><INDENT>print('<STR_LIT>' %(self.rate))<EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>')<EOL>raise ValueError('<STR_LIT>')<EOL>pass<EOL><DEDENT>for m in range(self.Nstates):<EOL><INDENT>self.input_zero.fn[m] = m<EOL>self.input_one.fn[m] = m<EOL>output0,state0 = self.conv_encoder([<NUM_LIT:0>],<EOL>binary(m,self.constraint_length-<NUM_LIT:1>))<EOL>output1,state1 = self.conv_encoder([<NUM_LIT:1>],<EOL>binary(m,self.constraint_length-<NUM_LIT:1>))<EOL>self.input_zero.tn[m] = int(state0,<NUM_LIT:2>)<EOL>self.input_one.tn[m] = int(state1,<NUM_LIT:2>)<EOL>if(self.rate == Fraction(<NUM_LIT:1>,<NUM_LIT:2>)):<EOL><INDENT>self.input_zero.out_bits[m] = <NUM_LIT:2>*output0[<NUM_LIT:0>] + output0[<NUM_LIT:1>]<EOL>self.input_one.out_bits[m] = <NUM_LIT:2>*output1[<NUM_LIT:0>] + output1[<NUM_LIT:1>]<EOL><DEDENT>elif(self.rate == Fraction(<NUM_LIT:1>,<NUM_LIT:3>)):<EOL><INDENT>self.input_zero.out_bits[m] = <NUM_LIT:4>*output0[<NUM_LIT:0>] + <NUM_LIT:2>*output0[<NUM_LIT:1>] + output0[<NUM_LIT:2>]<EOL>self.input_one.out_bits[m] = <NUM_LIT:4>*output1[<NUM_LIT:0>] + <NUM_LIT:2>*output1[<NUM_LIT:1>] + output1[<NUM_LIT:2>]<EOL><DEDENT><DEDENT>self.branches = trellis_branches(self.Nstates)<EOL>for m in range(self.Nstates):<EOL><INDENT>match_zero_idx = np.where(self.input_zero.tn == m)<EOL>match_one_idx = np.where(self.input_one.tn == m)<EOL>if len(match_zero_idx[<NUM_LIT:0>]) != <NUM_LIT:0>:<EOL><INDENT>self.branches.states1[m] = self.input_zero.fn[match_zero_idx[<NUM_LIT:0>][<NUM_LIT:0>]]<EOL>self.branches.states2[m] = self.input_zero.fn[match_zero_idx[<NUM_LIT:0>][<NUM_LIT:1>]]<EOL>self.branches.bits1[m] = self.input_zero.out_bits[match_zero_idx[<NUM_LIT:0>][<NUM_LIT:0>]]<EOL>self.branches.bits2[m] = self.input_zero.out_bits[match_zero_idx[<NUM_LIT:0>][<NUM_LIT:1>]]<EOL>self.branches.input1[m] = <NUM_LIT:0><EOL>self.branches.input2[m] = <NUM_LIT:0><EOL><DEDENT>elif len(match_one_idx[<NUM_LIT:0>]) != <NUM_LIT:0>:<EOL><INDENT>self.branches.states1[m] = self.input_one.fn[match_one_idx[<NUM_LIT:0>][<NUM_LIT:0>]]<EOL>self.branches.states2[m] = self.input_one.fn[match_one_idx[<NUM_LIT:0>][<NUM_LIT:1>]]<EOL>self.branches.bits1[m] = self.input_one.out_bits[match_one_idx[<NUM_LIT:0>][<NUM_LIT:0>]]<EOL>self.branches.bits2[m] = self.input_one.out_bits[match_one_idx[<NUM_LIT:0>][<NUM_LIT:1>]]<EOL>self.branches.input1[m] = <NUM_LIT:1><EOL>self.branches.input2[m] = <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>')<EOL>exit(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>

cc1 = fec_conv(G = ('111','101'), Depth = 10)
Instantiate a Rate 1/2 or Rate 1/3 convolutional
coder/decoder object. Polys G1 and G2 are entered
as binary strings, e.g,

Rate 1/2
G1 = '111' and G2 = '101' for K = 3 and
G1 = '1111001' and G2 = '1011011' for K = 7.

Rate 1/3
G1 = '111', G2 = '011' and G3 = '101' for K = 3 and
G1 = '1111001', G2 = '1100101' and G3 = '1011011'
for K= 7

The rate will automatically be selected by the number
of G polynomials (only rate 1/2 and 1/3 are available)

Viterbi decoding has a decision depth of Depth.

Data structures than manage the VA are created
upon instantiation via the __init__ method.

Other ideal polynomial considerations (taken from
"Introduction to Digital Communication" Second Edition
by Ziemer and Peterson:

Rate 1/2
K=3 ('111','101')
K=4 ('1111','1101')
K=5 ('11101','10011')
K=6 ('111101','101011')
K=7 ('1111001','1011011')
K=8 ('11111001','10100111')
K=9 ('111101011','101110001')

Rate 1/3
K=3 ('111','111','101')
K=4 ('1111','1101','1011')
K=5 ('11111','11011','10101')
K=6 ('111101','101011','100111')
K=7 ('1111001','1100101','1011011')
K=8 ('11110111','11011001','10010101')

Mark Wickert and Andrew Smit October 2018


devices = available_devices()<EOL>if not self.in_idx in devices:<EOL><INDENT>raise OSError("<STR_LIT>")<EOL><DEDENT>in_check = devices[self.in_idx]<EOL>if not self.out_idx in devices:<EOL><INDENT>raise OSError("<STR_LIT>")<EOL><DEDENT>out_check = devices[self.out_idx]<EOL>if((in_check['<STR_LIT>'] == <NUM_LIT:0>) and (out_check['<STR_LIT>']==<NUM_LIT:0>)):<EOL><INDENT>raise StandardError('<STR_LIT>')<EOL><DEDENT>elif(in_check['<STR_LIT>'] == <NUM_LIT:0>):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>elif(out_check['<STR_LIT>'] == <NUM_LIT:0>):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>return True<EOL>

Checks the input and output to see if they are valid


for i in range(<NUM_LIT:0>,self.frame_length*<NUM_LIT:2>):<EOL><INDENT>if i % <NUM_LIT:2>:<EOL><INDENT>self.out[i] = right_out[(int)(i/<NUM_LIT:2>)]<EOL><DEDENT>else:<EOL><INDENT>self.out[i] = left_out[(int)(i/<NUM_LIT:2>)]<EOL><DEDENT><DEDENT>return self.out<EOL>

Packs separate left and right channel data into one array to output
and returns the output.

Parameters
----------
left_out : left channel array of samples going to output
right_out : right channel array of samples going to output

Returns
-------
out : packed left and right channel array of samples


def thread_stream(self,Tsec = <NUM_LIT:2>,numChan = <NUM_LIT:1>):

def stream_thread(time,channel):<EOL><INDENT>self.stream(Tsec=time,numChan = channel)<EOL><DEDENT>t = Thread(target=stream_thread, args=(Tsec,numChan,))<EOL>t.start()<EOL>

Stream audio in a thread using callback. The stream is threaded, so widgets can be
used simultaneously during stream.

Parameters
----------

Tsec : stream time in seconds if Tsec > 0. If Tsec = 0, then stream goes to infinite
mode. When in infinite mode, Tsec.stop() can be used to stop the stream.

numChan : number of channels. Use 1 for mono and 2 for stereo.


devices = {}<EOL>pA = pyaudio.PyAudio()<EOL>device_string = str()<EOL>for k in range(pA.get_device_count()):<EOL><INDENT>dev = pA.get_device_info_by_index(k)<EOL>devices[k] = {'<STR_LIT:name>': dev['<STR_LIT:name>'], '<STR_LIT>': dev['<STR_LIT>'], '<STR_LIT>': dev['<STR_LIT>']}<EOL>device_string += '<STR_LIT>' %(k,dev['<STR_LIT:name>'],dev['<STR_LIT>'],dev['<STR_LIT>'])<EOL><DEDENT>logger.debug(device_string)<EOL>return devices<EOL>

Display available input and output audio devices along with their
port indices.

:return:  Dictionary whose keys are the device index, the number of inputs and outputs, and their names.
:rtype: dict


def __init__(self,x,start_offset = <NUM_LIT:0>):

self.n_chan = x.ndim<EOL>if self.n_chan == <NUM_LIT:2>:<EOL><INDENT>if x.shape[<NUM_LIT:1>] != <NUM_LIT:2>:<EOL><INDENT>x = x.T<EOL><DEDENT><DEDENT>self.x = x<EOL>self.x_len = x.shape[<NUM_LIT:0>]<EOL>self.loop_pointer = start_offset<EOL>

Create a 1D or 2D array for audio looping


for i in range(<NUM_LIT:0>,self.frame_length*<NUM_LIT:2>):<EOL><INDENT>if i % <NUM_LIT:2>:<EOL><INDENT>self.right_in[(int)(i/<NUM_LIT:2>)] = in_data[i]<EOL><DEDENT>else:<EOL><INDENT>self.left_in[(int)(i/<NUM_LIT:2>)] = in_data[i]<EOL><DEDENT><DEDENT>return self.left_in, self.right_in<EOL>

Splits incoming packed stereo data into separate left and right channels
and returns an array of left samples and an array of right samples

Parameters
----------
in_data : input data from the streaming object in the callback function.

Returns
-------
left_in : array of incoming left channel samples
right_in : array of incoming right channel samples


<EOL>k_min_idx = np.nonzero(np.ravel(np.array(self.DSP_tic)*<NUM_LIT:1000> < start_ms))[<NUM_LIT:0>]<EOL>if len(k_min_idx) < <NUM_LIT:1>:<EOL><INDENT>k_min = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>k_min = k_min_idx[-<NUM_LIT:1>]<EOL><DEDENT>k_max_idx = np.nonzero(np.ravel(np.array(self.DSP_tic)*<NUM_LIT:1000> > stop_ms))[<NUM_LIT:0>]<EOL>if len(k_min_idx) < <NUM_LIT:1>:<EOL><INDENT>k_max= len(self.DSP_tic)<EOL><DEDENT>else:<EOL><INDENT>k_max = k_max_idx[<NUM_LIT:0>]<EOL><DEDENT>for k in range(k_min,k_max):<EOL><INDENT>if k == <NUM_LIT:0>:<EOL><INDENT>plt.plot([<NUM_LIT:0>,self.DSP_tic[k]*<NUM_LIT:1000>,self.DSP_tic[k]*<NUM_LIT:1000>,<EOL>self.DSP_toc[k]*<NUM_LIT:1000>,self.DSP_toc[k]*<NUM_LIT:1000>],<EOL>[<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT:1>,<NUM_LIT:1>,<NUM_LIT:0>],'<STR_LIT:b>')<EOL><DEDENT>else:<EOL><INDENT>plt.plot([self.DSP_toc[k-<NUM_LIT:1>]*<NUM_LIT:1000>,self.DSP_tic[k]*<NUM_LIT:1000>,self.DSP_tic[k]*<NUM_LIT:1000>,<EOL>self.DSP_toc[k]*<NUM_LIT:1000>,self.DSP_toc[k]*<NUM_LIT:1000>],[<NUM_LIT:0>,<NUM_LIT:0>,<NUM_LIT:1>,<NUM_LIT:1>,<NUM_LIT:0>],'<STR_LIT:b>')<EOL><DEDENT><DEDENT>plt.plot([self.DSP_toc[k_max-<NUM_LIT:1>]*<NUM_LIT:1000>,stop_ms],[<NUM_LIT:0>,<NUM_LIT:0>],'<STR_LIT:b>')<EOL>plt.xlim([start_ms,stop_ms])<EOL>plt.title(r'<STR_LIT>')<EOL>plt.ylabel(r'<STR_LIT>')<EOL>plt.xlabel(r'<STR_LIT>')<EOL>plt.grid()<EOL>

Plot timing information of time spent in the callback. This is similar
to what a logic analyzer provides when probing an interrupt.

cb_active_plot( start_ms,stop_ms,line_color='b')


self.capture_sample_count += len(new_data)<EOL>if self.Tcapture > <NUM_LIT:0>:<EOL><INDENT>self.data_capture = np.hstack((self.data_capture,new_data))<EOL>if (self.Tcapture > <NUM_LIT:0>) and (len(self.data_capture) > self.Ncapture):<EOL><INDENT>self.data_capture = self.data_capture[-self.Ncapture:]<EOL><DEDENT><DEDENT>

Append new samples to the data_capture array and increment the sample counter
If length reaches Tcapture, then the newest samples will be kept. If Tcapture = 0
then new values are not appended to the data_capture array.


def interactive_stream(self,Tsec = <NUM_LIT:2>, numChan = <NUM_LIT:1>):

self.Tsec = Tsec<EOL>self.numChan = numChan<EOL>self.interactiveFG = <NUM_LIT:1><EOL>self.play = interactive(self.interaction,Stream = ToggleButtons(<EOL>options=['<STR_LIT>', '<STR_LIT>'],<EOL>description = '<STR_LIT:U+0020>',<EOL>value = '<STR_LIT>') )<EOL>display(self.play)<EOL>

Stream audio with start and stop radio buttons

Interactive stream is designed for streaming audio through this object using
a callback function. This stream is threaded, so it can be used with ipywidgets.
Click on the "Start Streaming" button to start streaming and click on "Stop Streaming"
button to stop streaming.

Parameters
----------

Tsec : stream time in seconds if Tsec > 0. If Tsec = 0, then stream goes to infinite
mode. When in infinite mode, the "Stop Streaming" radio button or Tsec.stop() can be
used to stop the stream.

numChan : number of channels. Use 1 for mono and 2 for stereo.


Tp = self.frame_length/float(self.fs)*<NUM_LIT:1000><EOL>print('<STR_LIT>'% (self.DSP_tic[<NUM_LIT:0>]*<NUM_LIT:1000>,))<EOL>print('<STR_LIT>' % Tp)<EOL>Tmp_mean = np.mean(np.diff(np.array(self.DSP_tic))[<NUM_LIT:1>:]*<NUM_LIT:1000>)<EOL>print('<STR_LIT>' % Tmp_mean)<EOL>Tprocess_mean = np.mean(np.array(self.DSP_toc)-np.array(self.DSP_tic))*<NUM_LIT:1000><EOL>print('<STR_LIT>' % Tprocess_mean)<EOL>

Display basic statistics of callback execution: ideal period
between callbacks, average measured period between callbacks,
and average time spent in the callback.


self.capture_sample_count = self.capture_sample_count + len(new_data_left) + len(new_data_right)<EOL>if self.Tcapture > <NUM_LIT:0>:<EOL><INDENT>self.data_capture_left = np.hstack((self.data_capture_left,new_data_left))<EOL>self.data_capture_right = np.hstack((self.data_capture_right,new_data_right))<EOL>if (len(self.data_capture_left) > self.Ncapture):<EOL><INDENT>self.data_capture_left = self.data_capture_left[-self.Ncapture:]<EOL><DEDENT>if (len(self.data_capture_right) > self.Ncapture):<EOL><INDENT>self.data_capture_right = self.data_capture_right[-self.Ncapture:]<EOL><DEDENT><DEDENT>

Append new samples to the data_capture_left array and the data_capture_right
array and increment the sample counter. If length reaches Tcapture, then the
newest samples will be kept. If Tcapture = 0 then new values are not appended
to the data_capture array.


dir_path = os.path.dirname(os.path.realpath(__file__))<EOL>ca = loadtxt(dir_path + '<STR_LIT>', dtype=int16, usecols=(Nca - <NUM_LIT:1>,), unpack=True)<EOL>M = <NUM_LIT>  <EOL>N = <NUM_LIT>  <EOL>Sca = '<STR_LIT>' + str(Nca)<EOL>f = open(fname_out, '<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>' % M)<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>');<EOL>f.write('<STR_LIT>'% Nca);<EOL>f.write('<STR_LIT>' % Nca)<EOL>kk = <NUM_LIT:0>;<EOL>for k in range(M):<EOL><INDENT>if (kk < N - <NUM_LIT:1>) and (k < M - <NUM_LIT:1>):<EOL><INDENT>f.write('<STR_LIT>' % ca[k])<EOL>kk += <NUM_LIT:1><EOL><DEDENT>elif (kk == N - <NUM_LIT:1>) & (k < M - <NUM_LIT:1>):<EOL><INDENT>f.write('<STR_LIT>' % ca[k])<EOL>if k < M:<EOL><INDENT>if Nca < <NUM_LIT:10>:<EOL><INDENT>f.write('<STR_LIT:U+0020>')<EOL><DEDENT>else:<EOL><INDENT>f.write('<STR_LIT:U+0020>')<EOL><DEDENT>kk = <NUM_LIT:0><EOL><DEDENT><DEDENT>else:<EOL><INDENT>f.write('<STR_LIT>' % ca[k])<EOL><DEDENT><DEDENT>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.close()<EOL>

Write 1023 bit CA (Gold) Code Header Files

Mark Wickert February 2015


def freqz_resp_list(b, a=np.array([<NUM_LIT:1>]), mode='<STR_LIT>', fs=<NUM_LIT:1.0>, Npts=<NUM_LIT>, fsize=(<NUM_LIT:6>, <NUM_LIT:4>)):

if type(b) == list:<EOL><INDENT>N_filt = len(b)<EOL><DEDENT>f = np.arange(<NUM_LIT:0>, Npts) / (<NUM_LIT> * Npts)<EOL>for n in range(N_filt):<EOL><INDENT>w, H = signal.freqz(b[n], a[n], <NUM_LIT:2> * np.pi * f)<EOL>if n == <NUM_LIT:0>:<EOL><INDENT>plt.figure(figsize=fsize)<EOL><DEDENT>if mode.lower() == '<STR_LIT>':<EOL><INDENT>plt.plot(f * fs, <NUM_LIT:20> * np.log10(np.abs(H)))<EOL>if n == N_filt - <NUM_LIT:1>:<EOL><INDENT>plt.xlabel('<STR_LIT>')<EOL>plt.ylabel('<STR_LIT>')<EOL>plt.title('<STR_LIT>')<EOL><DEDENT><DEDENT>elif mode.lower() == '<STR_LIT>':<EOL><INDENT>plt.plot(f * fs, np.angle(H))<EOL>if n == N_filt - <NUM_LIT:1>:<EOL><INDENT>plt.xlabel('<STR_LIT>')<EOL>plt.ylabel('<STR_LIT>')<EOL>plt.title('<STR_LIT>')<EOL><DEDENT><DEDENT>elif (mode.lower() == '<STR_LIT>') or (mode.lower() == '<STR_LIT>'):<EOL><INDENT>"""<STR_LIT>"""<EOL>theta = np.unwrap(np.angle(H))<EOL>theta2 = np.unwrap(<NUM_LIT:2> * theta) / <NUM_LIT><EOL>theta_dif = np.diff(theta2)<EOL>f_diff = np.diff(f)<EOL>Tg = -np.diff(theta2) / np.diff(w)<EOL>idx = pylab.find(<NUM_LIT:20> * np.log10(H[:-<NUM_LIT:1>]) < -<NUM_LIT>)<EOL>Tg[idx] = np.zeros(len(idx))<EOL>max_Tg = np.max(Tg)<EOL>if mode.lower() == '<STR_LIT>':<EOL><INDENT>max_Tg /= fs<EOL>plt.plot(f[:-<NUM_LIT:1>] * fs, Tg / fs)<EOL>plt.ylim([<NUM_LIT:0>, <NUM_LIT> * max_Tg])<EOL><DEDENT>else:<EOL><INDENT>plt.plot(f[:-<NUM_LIT:1>] * fs, Tg)<EOL>plt.ylim([<NUM_LIT:0>, <NUM_LIT> * max_Tg])<EOL><DEDENT>if n == N_filt - <NUM_LIT:1>:<EOL><INDENT>plt.xlabel('<STR_LIT>')<EOL>if mode.lower() == '<STR_LIT>':<EOL><INDENT>plt.ylabel('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>plt.ylabel('<STR_LIT>')<EOL><DEDENT>plt.title('<STR_LIT>')<EOL><DEDENT><DEDENT>else:<EOL><INDENT>s1 = '<STR_LIT>'<EOL>s2 = '<STR_LIT>'<EOL>print(s1 + s2)<EOL><DEDENT><DEDENT>

A method for displaying digital filter frequency response magnitude,
phase, and group delay. A plot is produced using matplotlib

freq_resp(self,mode = 'dB',Npts = 1024)

A method for displaying the filter frequency response magnitude,
phase, and group delay. A plot is produced using matplotlib

freqz_resp(b,a=[1],mode = 'dB',Npts = 1024,fsize=(6,4))

Parameters
----------
b : ndarray of numerator coefficients
a : ndarray of denominator coefficents
mode : display mode: 'dB' magnitude, 'phase' in radians, or
        'groupdelay_s' in samples and 'groupdelay_t' in sec,
        all versus frequency in Hz
Npts : number of points to plot; default is 1024
fsize : figure size; defult is (6,4) inches

Mark Wickert, January 2015


M = len(h)<EOL>hq = int16(rint(h * <NUM_LIT:2> ** <NUM_LIT:15>))<EOL>N = <NUM_LIT:8>  <EOL>f = open(fname_out, '<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>' % M)<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>');<EOL>f.write('<STR_LIT>');<EOL>f.write('<STR_LIT>')<EOL>kk = <NUM_LIT:0>;<EOL>for k in range(M):<EOL><INDENT>if (kk < N - <NUM_LIT:1>) and (k < M - <NUM_LIT:1>):<EOL><INDENT>f.write('<STR_LIT>' % hq[k])<EOL>kk += <NUM_LIT:1><EOL><DEDENT>elif (kk == N - <NUM_LIT:1>) & (k < M - <NUM_LIT:1>):<EOL><INDENT>f.write('<STR_LIT>' % hq[k])<EOL>if k < M:<EOL><INDENT>f.write('<STR_LIT:U+0020>')<EOL>kk = <NUM_LIT:0><EOL><DEDENT><DEDENT>else:<EOL><INDENT>f.write('<STR_LIT>' % hq[k])<EOL><DEDENT><DEDENT>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.close()<EOL>

Write FIR Fixed-Point Filter Header Files

Mark Wickert February 2015


Ns, Mcol = SOS_mat.shape<EOL>f = open(fname_out, '<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>' % Ns)<EOL>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>');<EOL>f.write('<STR_LIT>');<EOL>f.write('<STR_LIT>' % (<NUM_LIT:5> * Ns))<EOL>for k in range(Ns):<EOL><INDENT>if (k < Ns - <NUM_LIT:1>):<EOL><INDENT>f.write('<STR_LIT>' %(SOS_mat[k, <NUM_LIT:0>], SOS_mat[k, <NUM_LIT:1>], SOS_mat[k, <NUM_LIT:2>]))<EOL>f.write('<STR_LIT>' %(-SOS_mat[k, <NUM_LIT:4>], -SOS_mat[k, <NUM_LIT:5>]))<EOL><DEDENT>else:<EOL><INDENT>f.write('<STR_LIT>' %(SOS_mat[k, <NUM_LIT:0>], SOS_mat[k, <NUM_LIT:1>], SOS_mat[k, <NUM_LIT:2>]))<EOL>f.write('<STR_LIT>' %(-SOS_mat[k, <NUM_LIT:4>], -SOS_mat[k, <NUM_LIT:5>]))<EOL><DEDENT><DEDENT>f.write('<STR_LIT>')<EOL>f.write('<STR_LIT>')<EOL>f.close()<EOL>

Write IIR SOS Header Files
File format is compatible with CMSIS-DSP IIR
Directform II Filter Functions

Mark Wickert March 2015-October 2016


def IIR_lpf(f_pass, f_stop, Ripple_pass, Atten_stop, <EOL>fs = <NUM_LIT>, ftype = '<STR_LIT>'):

b,a = signal.iirdesign(<NUM_LIT:2>*float(f_pass)/fs, <NUM_LIT:2>*float(f_stop)/fs,<EOL>Ripple_pass, Atten_stop,<EOL>ftype = ftype, output='<STR_LIT>')<EOL>sos = signal.iirdesign(<NUM_LIT:2>*float(f_pass)/fs, <NUM_LIT:2>*float(f_stop)/fs,<EOL>Ripple_pass, Atten_stop,<EOL>ftype = ftype, output='<STR_LIT>')<EOL>tag = '<STR_LIT>' + ftype + '<STR_LIT>'<EOL>print('<STR_LIT>' % (tag,len(a)-<NUM_LIT:1>))<EOL>return b, a, sos<EOL>

Design an IIR lowpass filter using scipy.signal.iirdesign.
The filter order is determined based on
f_pass Hz, f_stop Hz, and the desired stopband attenuation
d_stop in dB, all relative to a sampling rate of fs Hz.

Parameters
----------
f_pass : Passband critical frequency in Hz
f_stop : Stopband critical frequency in Hz
Ripple_pass : Filter gain in dB at f_pass
Atten_stop : Filter attenuation in dB at f_stop
fs : Sampling rate in Hz
ftype : Analog prototype from 'butter' 'cheby1', 'cheby2',
        'ellip', and 'bessel'

Returns
-------
b : ndarray of the numerator coefficients
a : ndarray of the denominator coefficients
sos : 2D ndarray of second-order section coefficients

Notes
-----
Additionally a text string telling the user the filter order is
written to the console, e.g., IIR cheby1 order = 8.

Examples
--------
>>> fs = 48000
>>> f_pass = 5000
>>> f_stop = 8000
>>> b_but,a_but,sos_but = IIR_lpf(f_pass,f_stop,0.5,60,fs,'butter')
>>> b_cheb1,a_cheb1,sos_cheb1 = IIR_lpf(f_pass,f_stop,0.5,60,fs,'cheby1')
>>> b_cheb2,a_cheb2,sos_cheb2 = IIR_lpf(f_pass,f_stop,0.5,60,fs,'cheby2')
>>> b_elli,a_elli,sos_elli = IIR_lpf(f_pass,f_stop,0.5,60,fs,'ellip')

Mark Wickert October 2016


return np.vstack((sos1,sos2))<EOL>


def sos_zplane(sos,auto_scale=True,size=<NUM_LIT:2>,tol = <NUM_LIT>):

Ns,Mcol = sos.shape<EOL>N_roots = []<EOL>for k in range(Ns):<EOL><INDENT>N_roots_tmp = np.roots(sos[k,:<NUM_LIT:3>])<EOL>if N_roots_tmp[<NUM_LIT:1>] == <NUM_LIT:0.>:<EOL><INDENT>N_roots = np.hstack((N_roots,N_roots_tmp[<NUM_LIT:0>]))<EOL><DEDENT>else:<EOL><INDENT>N_roots = np.hstack((N_roots,N_roots_tmp))<EOL><DEDENT><DEDENT>D_roots = []<EOL>for k in range(Ns):<EOL><INDENT>D_roots_tmp = np.roots(sos[k,<NUM_LIT:3>:])<EOL>if D_roots_tmp[<NUM_LIT:1>] == <NUM_LIT:0.>:<EOL><INDENT>D_roots = np.hstack((D_roots,D_roots_tmp[<NUM_LIT:0>]))<EOL><DEDENT>else:<EOL><INDENT>D_roots = np.hstack((D_roots,D_roots_tmp))<EOL><DEDENT><DEDENT>x_scale = <NUM_LIT>*size<EOL>y_scale = <NUM_LIT>*size   <EOL>x_off = <NUM_LIT><EOL>y_off = <NUM_LIT><EOL>M = len(N_roots)<EOL>N = len(D_roots)<EOL>if auto_scale:<EOL><INDENT>if M > <NUM_LIT:0> and N > <NUM_LIT:0>:<EOL><INDENT>size = max(np.max(np.abs(N_roots)),np.max(np.abs(D_roots)))+<NUM_LIT><EOL><DEDENT>elif M > <NUM_LIT:0>:<EOL><INDENT>size = max(np.max(np.abs(N_roots)),<NUM_LIT:1.0>)+<NUM_LIT><EOL><DEDENT>elif N > <NUM_LIT:0>:<EOL><INDENT>size = max(<NUM_LIT:1.0>,np.max(np.abs(D_roots)))+<NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>size = <NUM_LIT><EOL><DEDENT><DEDENT>plt.figure(figsize=(<NUM_LIT:5>,<NUM_LIT:5>))<EOL>plt.axis('<STR_LIT>')<EOL>r = np.linspace(<NUM_LIT:0>,<NUM_LIT:2>*np.pi,<NUM_LIT:200>)<EOL>plt.plot(np.cos(r),np.sin(r),'<STR_LIT>')<EOL>plt.plot([-size,size],[<NUM_LIT:0>,<NUM_LIT:0>],'<STR_LIT>')<EOL>plt.plot([<NUM_LIT:0>,<NUM_LIT:0>],[-size,size],'<STR_LIT>')<EOL>if M > <NUM_LIT:0>:<EOL><INDENT>N_uniq, N_mult=unique_cpx_roots(N_roots,tol=tol)<EOL>plt.plot(np.real(N_uniq),np.imag(N_uniq),'<STR_LIT>',mfc='<STR_LIT:None>',ms=<NUM_LIT:8>)<EOL>idx_N_mult = np.nonzero(np.ravel(N_mult><NUM_LIT:1>))[<NUM_LIT:0>]<EOL>for k in range(len(idx_N_mult)):<EOL><INDENT>x_loc = np.real(N_uniq[idx_N_mult[k]]) + x_off*x_scale<EOL>y_loc =np.imag(N_uniq[idx_N_mult[k]]) + y_off*y_scale<EOL>plt.text(x_loc,y_loc,str(N_mult[idx_N_mult[k]]),<EOL>ha='<STR_LIT>',va='<STR_LIT>',fontsize=<NUM_LIT:10>)<EOL><DEDENT><DEDENT>if N > <NUM_LIT:0>:<EOL><INDENT>D_uniq, D_mult=unique_cpx_roots(D_roots,tol=tol)<EOL>plt.plot(np.real(D_uniq),np.imag(D_uniq),'<STR_LIT>',ms=<NUM_LIT:8>)<EOL>idx_D_mult = np.nonzero(np.ravel(D_mult><NUM_LIT:1>))[<NUM_LIT:0>]<EOL>for k in range(len(idx_D_mult)):<EOL><INDENT>x_loc = np.real(D_uniq[idx_D_mult[k]]) + x_off*x_scale<EOL>y_loc =np.imag(D_uniq[idx_D_mult[k]]) + y_off*y_scale<EOL>plt.text(x_loc,y_loc,str(D_mult[idx_D_mult[k]]),<EOL>ha='<STR_LIT>',va='<STR_LIT>',fontsize=<NUM_LIT:10>)            <EOL><DEDENT><DEDENT>if M - N < <NUM_LIT:0>:<EOL><INDENT>plt.plot(<NUM_LIT:0.0>,<NUM_LIT:0.0>,'<STR_LIT>',mfc='<STR_LIT:None>',ms=<NUM_LIT:8>)<EOL><DEDENT>elif M - N > <NUM_LIT:0>:<EOL><INDENT>plt.plot(<NUM_LIT:0.0>,<NUM_LIT:0.0>,'<STR_LIT>',ms=<NUM_LIT:8>)<EOL><DEDENT>if abs(M - N) > <NUM_LIT:1>:<EOL><INDENT>plt.text(x_off*x_scale,y_off*y_scale,str(abs(M-N)),<EOL>ha='<STR_LIT>',va='<STR_LIT>',fontsize=<NUM_LIT:10>)        <EOL><DEDENT>plt.xlabel('<STR_LIT>')<EOL>plt.ylabel('<STR_LIT>')<EOL>plt.title('<STR_LIT>')<EOL>plt.axis([-size,size,-size,size])<EOL>return M,N<EOL>

Create an z-plane pole-zero plot.

Create an z-plane pole-zero plot using the numerator
and denominator z-domain system function coefficient
ndarrays b and a respectively. Assume descending powers of z.

Parameters
----------
sos : ndarray of the sos coefficients
auto_scale : bool (default True)
size : plot radius maximum when scale = False

Returns
-------
(M,N) : tuple of zero and pole counts + plot window

Notes
-----
This function tries to identify repeated poles and zeros and will
place the multiplicity number above and to the right of the pole or zero.
The difficulty is setting the tolerance for this detection. Currently it
is set at 1e-3 via the function signal.unique_roots.

Examples
--------
>>> # Here the plot is generated using auto_scale
>>> sos_zplane(sos)
>>> # Here the plot is generated using manual scaling
>>> sos_zplane(sos,False,1.5)


def freqz_resp_cas_list(sos,mode = '<STR_LIT>',fs=<NUM_LIT:1.0>,Npts = <NUM_LIT>,fsize=(<NUM_LIT:6>,<NUM_LIT:4>)):

if type(sos) == list:<EOL><INDENT>N_filt = len(sos)<EOL><DEDENT>f = np.arange(<NUM_LIT:0>,Npts)/(<NUM_LIT>*Npts)<EOL>for n in range(N_filt):<EOL><INDENT>w,H = freqz_cas(sos[n],<NUM_LIT:2>*np.pi*f)<EOL>if n == <NUM_LIT:0>:<EOL><INDENT>plt.figure(figsize=fsize)<EOL><DEDENT>if mode.lower() == '<STR_LIT>':<EOL><INDENT>plt.plot(f*fs,<NUM_LIT:20>*np.log10(np.abs(H)))<EOL>if n == N_filt-<NUM_LIT:1>:<EOL><INDENT>plt.xlabel('<STR_LIT>')<EOL>plt.ylabel('<STR_LIT>')<EOL>plt.title('<STR_LIT>')<EOL><DEDENT><DEDENT>elif mode.lower() == '<STR_LIT>':<EOL><INDENT>plt.plot(f*fs,np.angle(H))<EOL>if n == N_filt-<NUM_LIT:1>:<EOL><INDENT>plt.xlabel('<STR_LIT>')<EOL>plt.ylabel('<STR_LIT>')<EOL>plt.title('<STR_LIT>')<EOL><DEDENT><DEDENT>elif (mode.lower() == '<STR_LIT>') or (mode.lower() == '<STR_LIT>'):<EOL><INDENT>"""<STR_LIT>"""<EOL>theta = np.unwrap(np.angle(H))<EOL>theta2 = np.unwrap(<NUM_LIT:2>*theta)/<NUM_LIT><EOL>theta_dif = np.diff(theta2)<EOL>f_diff = np.diff(f)<EOL>Tg = -np.diff(theta2)/np.diff(w)<EOL>idx = np.nonzero(np.ravel(<NUM_LIT:20>*np.log10(H[:-<NUM_LIT:1>]) < -<NUM_LIT>))[<NUM_LIT:0>]<EOL>Tg[idx] = np.zeros(len(idx))<EOL>max_Tg = np.max(Tg)<EOL>if mode.lower() == '<STR_LIT>':<EOL><INDENT>max_Tg /= fs<EOL>plt.plot(f[:-<NUM_LIT:1>]*fs,Tg/fs)<EOL>plt.ylim([<NUM_LIT:0>,<NUM_LIT>*max_Tg])<EOL><DEDENT>else:<EOL><INDENT>plt.plot(f[:-<NUM_LIT:1>]*fs,Tg)<EOL>plt.ylim([<NUM_LIT:0>,<NUM_LIT>*max_Tg])<EOL><DEDENT>if n == N_filt-<NUM_LIT:1>:<EOL><INDENT>plt.xlabel('<STR_LIT>')<EOL>if mode.lower() == '<STR_LIT>':<EOL><INDENT>plt.ylabel('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>plt.ylabel('<STR_LIT>')<EOL><DEDENT>plt.title('<STR_LIT>')<EOL><DEDENT><DEDENT>else:<EOL><INDENT>s1 = '<STR_LIT>'<EOL>s2 = '<STR_LIT>'<EOL>print(s1 + s2)<EOL><DEDENT><DEDENT>

A method for displaying cascade digital filter form frequency response
magnitude, phase, and group delay. A plot is produced using matplotlib

freq_resp(self,mode = 'dB',Npts = 1024)

A method for displaying the filter frequency response magnitude,
phase, and group delay. A plot is produced using matplotlib

freqz_resp(b,a=[1],mode = 'dB',Npts = 1024,fsize=(6,4))

    b = ndarray of numerator coefficients
    a = ndarray of denominator coefficents
 mode = display mode: 'dB' magnitude, 'phase' in radians, or
        'groupdelay_s' in samples and 'groupdelay_t' in sec,
        all versus frequency in Hz
 Npts = number of points to plot; default is 1024
fsize = figure size; defult is (6,4) inches

Mark Wickert, January 2015


def IIR_hpf(f_stop, f_pass, Ripple_pass, Atten_stop, <EOL>fs = <NUM_LIT>, ftype = '<STR_LIT>'):

b,a = signal.iirdesign(<NUM_LIT:2>*float(f_pass)/fs, <NUM_LIT:2>*float(f_stop)/fs,<EOL>Ripple_pass, Atten_stop,<EOL>ftype = ftype, output='<STR_LIT>')<EOL>sos = signal.iirdesign(<NUM_LIT:2>*float(f_pass)/fs, <NUM_LIT:2>*float(f_stop)/fs,<EOL>Ripple_pass, Atten_stop,<EOL>ftype =ftype, output='<STR_LIT>')<EOL>tag = '<STR_LIT>' + ftype + '<STR_LIT>'<EOL>print('<STR_LIT>' % (tag,len(a)-<NUM_LIT:1>))<EOL>return b, a, sos<EOL>

Design an IIR highpass filter using scipy.signal.iirdesign.
The filter order is determined based on
f_pass Hz, f_stop Hz, and the desired stopband attenuation
d_stop in dB, all relative to a sampling rate of fs Hz.

Parameters
----------
f_stop :
f_pass :
Ripple_pass :
Atten_stop :
fs : sampling rate in Hz
ftype : Analog prototype from 'butter' 'cheby1', 'cheby2',
        'ellip', and 'bessel'

Returns
-------
b : ndarray of the numerator coefficients
a : ndarray of the denominator coefficients
sos : 2D ndarray of second-order section coefficients

Examples
--------
>>> fs = 48000
>>> f_pass = 8000
>>> f_stop = 5000
>>> b_but,a_but,sos_but = IIR_hpf(f_stop,f_pass,0.5,60,fs,'butter')
>>> b_cheb1,a_cheb1,sos_cheb1 = IIR_hpf(f_stop,f_pass,0.5,60,fs,'cheby1')
>>> b_cheb2,a_cheb2,sos_cheb2 = IIR_hpf(f_stop,f_pass,0.5,60,fs,'cheby2')
>>> b_elli,a_elli,sos_elli = IIR_hpf(f_stop,f_pass,0.5,60,fs,'ellip')

Mark Wickert October 2016


T = <NUM_LIT:1>/float(fs)<EOL>Kv = <NUM_LIT:2>*np.pi*Kv <EOL>if loop_type == <NUM_LIT:1>:<EOL><INDENT>K = <NUM_LIT:2>*np.pi*fn <EOL><DEDENT>elif loop_type == <NUM_LIT:2>:<EOL><INDENT>K = <NUM_LIT:4> *np.pi*zeta*fn <EOL>tau2 = zeta/(np.pi*fn)<EOL><DEDENT>elif loop_type == <NUM_LIT:3>:<EOL><INDENT>K = Kv <EOL>tau1 = K/((<NUM_LIT:2>*np.pi*fn)^<NUM_LIT:2>);<EOL>tau2 = <NUM_LIT:2>*zeta/(<NUM_LIT:2>*np.pi*fn)*(<NUM_LIT:1> - <NUM_LIT:2>*np.pi*fn/K*<NUM_LIT:1>/(<NUM_LIT:2>*zeta))<EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>')<EOL><DEDENT>filt_in_last = <NUM_LIT:0>; filt_out_last = <NUM_LIT:0>;<EOL>vco_in_last = <NUM_LIT:0>; vco_out = <NUM_LIT:0>; vco_out_last = <NUM_LIT:0>;<EOL>vco_out_cbb = <NUM_LIT:0><EOL>n = np.arange(len(x))<EOL>theta_hat = np.zeros(len(x))<EOL>ev = np.zeros(len(x))<EOL>phi = np.zeros(len(x))<EOL>for k in  range(len(n)):<EOL><INDENT>phi[k] = np.imag(x[k] * np.conj(vco_out_cbb))<EOL>pd_out = phi[k]<EOL>gain_out = K/Kv*pd_out <EOL>if loop_type == <NUM_LIT:2>:<EOL><INDENT>filt_in = (<NUM_LIT:1>/tau2)*gain_out<EOL>filt_out = filt_out_last + T/<NUM_LIT:2>*(filt_in + filt_in_last)<EOL>filt_in_last = filt_in<EOL>filt_out_last = filt_out<EOL>filt_out = filt_out + gain_out<EOL><DEDENT>elif loop_type == <NUM_LIT:3>:<EOL><INDENT>filt_in = (tau2/tau1)*gain_out - (<NUM_LIT:1>/tau1)*filt_out_last<EOL>u3 = filt_in + (<NUM_LIT:1>/tau2)*filt_out_last<EOL>filt_out = filt_out_last + T/<NUM_LIT:2>*(filt_in + filt_in_last)<EOL>filt_in_last = filt_in<EOL>filt_out_last = filt_out<EOL><DEDENT>else:<EOL><INDENT>filt_out = gain_out;<EOL><DEDENT>vco_in = filt_out<EOL>if loop_type == <NUM_LIT:3>:<EOL><INDENT>vco_in = u3<EOL><DEDENT>vco_out = vco_out_last + T/<NUM_LIT:2>*(vco_in + vco_in_last)<EOL>vco_in_last = vco_in<EOL>vco_out_last = vco_out<EOL>vco_out = Kv*vco_out <EOL>vco_out_cbb = np.exp(<NUM_LIT>*vco_out)<EOL>ev[k] = vco_in<EOL>theta_hat[k] = vco_out<EOL><DEDENT>return theta_hat, ev, phi<EOL>

Baseband Analog PLL Simulation Model

:param x: input phase deviation in radians
:param fs: sampling rate in sample per second or Hz
:param loop_type: 1, first-order loop filter F(s)=K_LF; 2, integrator
            with lead compensation F(s) = (1 + s tau2)/(s tau1),
            i.e., a type II, or 3, lowpass with lead compensation
            F(s) = (1 + s tau2)/(1 + s tau1)
:param Kv: VCO gain in Hz/v; note presently assume Kp = 1v/rad
            and K_LF = 1; the user can easily change this
:param fn: Loop natural frequency (loops 2 & 3) or cutoff
            frequency (loop 1)
:param zeta: Damping factor for loops 2 & 3
:return: theta_hat = Output phase estimate of the input theta in radians,
         ev = VCO control voltage,
         phi = phase error = theta - theta_hat

Mark Wickert, April 2007 for ECE 5625/4625
Modified February 2008 and July 2014 for ECE 5675/4675
Python version August 2014


T = <NUM_LIT:1>/float(fs)<EOL>Kv = <NUM_LIT:2>*np.pi*Kv <EOL>if loop_type == <NUM_LIT:1>:<EOL><INDENT>K = <NUM_LIT:2>*np.pi*fn <EOL><DEDENT>elif loop_type == <NUM_LIT:2>:<EOL><INDENT>K = <NUM_LIT:4> *np.pi*zeta*fn <EOL>tau2 = zeta/(np.pi*fn)<EOL><DEDENT>elif loop_type == <NUM_LIT:3>:<EOL><INDENT>K = Kv <EOL>tau1 = K/((<NUM_LIT:2>*np.pi*fn)**<NUM_LIT:2>)<EOL>tau2 = <NUM_LIT:2>*zeta/(<NUM_LIT:2>*np.pi*fn)*(<NUM_LIT:1> - <NUM_LIT:2>*np.pi*fn/K*<NUM_LIT:1>/(<NUM_LIT:2>*zeta))<EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>')<EOL><DEDENT>filt_in_last = <NUM_LIT:0>; filt_out_last = <NUM_LIT:0>;<EOL>vco_in_last = <NUM_LIT:0>; vco_out = <NUM_LIT:0>; vco_out_last = <NUM_LIT:0>;<EOL>n = np.arange(len(theta))<EOL>theta_hat = np.zeros_like(theta)<EOL>ev = np.zeros_like(theta)<EOL>phi = np.zeros_like(theta)<EOL>for k in  range(len(n)):<EOL><INDENT>phi[k] = theta[k] - vco_out<EOL>if non_lin == <NUM_LIT:1>:<EOL><INDENT>pd_out = np.sin(phi[k])<EOL><DEDENT>else:<EOL><INDENT>pd_out = phi[k]<EOL><DEDENT>gain_out = K/Kv*pd_out <EOL>if loop_type == <NUM_LIT:2>:<EOL><INDENT>filt_in = (<NUM_LIT:1>/tau2)*gain_out<EOL>filt_out = filt_out_last + T/<NUM_LIT:2>*(filt_in + filt_in_last)<EOL>filt_in_last = filt_in<EOL>filt_out_last = filt_out<EOL>filt_out = filt_out + gain_out<EOL><DEDENT>elif loop_type == <NUM_LIT:3>:<EOL><INDENT>filt_in = (tau2/tau1)*gain_out - (<NUM_LIT:1>/tau1)*filt_out_last<EOL>u3 = filt_in + (<NUM_LIT:1>/tau2)*filt_out_last<EOL>filt_out = filt_out_last + T/<NUM_LIT:2>*(filt_in + filt_in_last)<EOL>filt_in_last = filt_in<EOL>filt_out_last = filt_out<EOL><DEDENT>else:<EOL><INDENT>filt_out = gain_out;<EOL><DEDENT>vco_in = filt_out<EOL>if loop_type == <NUM_LIT:3>:<EOL><INDENT>vco_in = u3<EOL><DEDENT>vco_out = vco_out_last + T/<NUM_LIT:2>*(vco_in + vco_in_last)<EOL>vco_in_last = vco_in<EOL>vco_out_last = vco_out<EOL>vco_out = Kv*vco_out <EOL>ev[k] = vco_in<EOL>theta_hat[k] = vco_out<EOL><DEDENT>return theta_hat, ev, phi<EOL>

Baseband Analog PLL Simulation Model

:param theta: input phase deviation in radians
:param fs: sampling rate in sample per second or Hz
:param loop_type: 1, first-order loop filter F(s)=K_LF; 2, integrator
            with lead compensation F(s) = (1 + s tau2)/(s tau1),
            i.e., a type II, or 3, lowpass with lead compensation
            F(s) = (1 + s tau2)/(1 + s tau1)
:param Kv: VCO gain in Hz/v; note presently assume Kp = 1v/rad
            and K_LF = 1; the user can easily change this
:param fn: Loop natural frequency (loops 2 & 3) or cutoff
            frquency (loop 1)
:param zeta: Damping factor for loops 2 & 3
:param non_lin: 0, linear phase detector; 1, sinusoidal phase detector
:return: theta_hat = Output phase estimate of the input theta in radians,
         ev = VCO control voltage,
         phi = phase error = theta - theta_hat

Notes
-----
Alternate input in place of natural frequency, fn, in Hz is
the noise equivalent bandwidth Bn in Hz.

Mark Wickert, April 2007 for ECE 5625/4625
Modified February 2008 and July 2014 for ECE 5675/4675
Python version August 2014


def firwin_kaiser_hpf(f_stop, f_pass, d_stop, fs = <NUM_LIT:1.0>, N_bump=<NUM_LIT:0>):

<EOL>f_pass_eq = fs/<NUM_LIT> - f_pass<EOL>f_stop_eq = fs/<NUM_LIT> - f_stop<EOL>wc = <NUM_LIT:2>*np.pi*(f_pass_eq + f_stop_eq)/<NUM_LIT:2>/fs<EOL>delta_w = <NUM_LIT:2>*np.pi*(f_stop_eq - f_pass_eq)/fs<EOL>M = np.ceil((d_stop - <NUM_LIT:8>)/(<NUM_LIT>*delta_w))<EOL>M += N_bump<EOL>N_taps = M + <NUM_LIT:1><EOL>beta = signal.kaiser_beta(d_stop)<EOL>w_k = signal.kaiser(N_taps,beta)<EOL>n = np.arange(N_taps)<EOL>b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/<NUM_LIT:2>)) * w_k<EOL>b_k /= np.sum(b_k)<EOL>n = np.arange(len(b_k))<EOL>b_k *= (-<NUM_LIT:1>)**n<EOL>print('<STR_LIT>' % N_taps)<EOL>return b_k<EOL>

Design an FIR highpass filter using the sinc() kernel and
a Kaiser window. The filter order is determined based on
f_pass Hz, f_stop Hz, and the desired stopband attenuation
d_stop in dB, all relative to a sampling rate of fs Hz.
Note: the passband ripple cannot be set independent of the
stopband attenuation.

Mark Wickert October 2016


def firwin_lpf(N_taps, fc, fs = <NUM_LIT:1.0>):

return signal.firwin(N_taps,<NUM_LIT:2>*fc/fs)<EOL>

Design a windowed FIR lowpass filter in terms of passband
critical frequencies f1 < f2 in Hz relative to sampling rate
fs in Hz. The number of taps must be provided.

Mark Wickert October 2016


def firwin_bpf(N_taps, f1, f2, fs = <NUM_LIT:1.0>, pass_zero=False):

return signal.firwin(N_taps,<NUM_LIT:2>*(f1,f2)/fs,pass_zero=pass_zero)<EOL>

Design a windowed FIR bandpass filter in terms of passband
critical frequencies f1 < f2 in Hz relative to sampling rate
fs in Hz. The number of taps must be provided.

Mark Wickert October 2016


def firwin_kaiser_bsf(f_stop1, f_pass1, f_pass2, f_stop2, d_stop, <EOL>fs = <NUM_LIT:1.0>, N_bump=<NUM_LIT:0>):

<EOL>f_pass = (f_pass2 - f_pass1)/<NUM_LIT:2><EOL>f_stop = (f_stop2 - f_stop1)/<NUM_LIT:2><EOL>wc = <NUM_LIT:2>*np.pi*(f_pass + f_stop)/<NUM_LIT:2>/fs<EOL>delta_w = <NUM_LIT:2>*np.pi*(f_stop - f_pass)/fs<EOL>M = np.ceil((d_stop - <NUM_LIT:8>)/(<NUM_LIT>*delta_w))<EOL>M += N_bump<EOL>if ((M+<NUM_LIT:1>)/<NUM_LIT>-int((M+<NUM_LIT:1>)/<NUM_LIT>)) == <NUM_LIT:0>:<EOL><INDENT>M += <NUM_LIT:1><EOL><DEDENT>N_taps = M + <NUM_LIT:1><EOL>beta = signal.kaiser_beta(d_stop)<EOL>w_k = signal.kaiser(N_taps,beta)<EOL>n = np.arange(N_taps)<EOL>b_k = wc/np.pi*np.sinc(wc/np.pi*(n-M/<NUM_LIT:2>)) * w_k<EOL>b_k /= np.sum(b_k)<EOL>f0 = (f_pass2 + f_pass1)/<NUM_LIT:2><EOL>w0 = <NUM_LIT:2>*np.pi*f0/fs<EOL>n = np.arange(len(b_k))<EOL>b_k_bs = <NUM_LIT:2>*b_k*np.cos(w0*(n-M/<NUM_LIT:2>))<EOL>b_k_bs = -b_k_bs<EOL>b_k_bs[int(M/<NUM_LIT:2>)] += <NUM_LIT:1> <EOL>print('<STR_LIT>' % N_taps)<EOL>return b_k_bs<EOL>

Design an FIR bandstop filter using the sinc() kernel and
a Kaiser window. The filter order is determined based on
f_stop1 Hz, f_pass1 Hz, f_pass2 Hz, f_stop2 Hz, and the
desired stopband attenuation d_stop in dB for both stopbands,
all relative to a sampling rate of fs Hz.
Note: The passband ripple cannot be set independent of the
stopband attenuation.
Note: The filter order is forced to be even (odd number of taps)
so there is a center tap that can be used to form 1 - H_BPF.

Mark Wickert October 2016


def bandpass_order(f_stop1, f_pass1, f_pass2, f_stop2, dpass_dB, dstop_dB, fsamp = <NUM_LIT:1>):

dpass = <NUM_LIT:1> - <NUM_LIT:10>**(-dpass_dB/<NUM_LIT:20>)<EOL>dstop = <NUM_LIT:10>**(-dstop_dB/<NUM_LIT:20>)<EOL>Df1 = (f_pass1 - f_stop1)/fsamp<EOL>Df2 = (f_stop2 - f_pass2)/fsamp<EOL>b1 = <NUM_LIT><EOL>b2 = <NUM_LIT><EOL>b3 = -<NUM_LIT><EOL>b4 = <NUM_LIT><EOL>b5 = -<NUM_LIT><EOL>b6 = -<NUM_LIT><EOL>Df = min(Df1, Df2)<EOL>Cinf = np.log10(dstop)*(b1*np.log10(dpass)**<NUM_LIT:2> + b2*np.log10(dpass) + b3)+ (b4*np.log10(dpass)**<NUM_LIT:2> + b5*np.log10(dpass) + b6)<EOL>g = -<NUM_LIT>*np.log10(dpass/dstop) - <NUM_LIT><EOL>N = Cinf/Df + g*Df + <NUM_LIT:1><EOL>ff = <NUM_LIT:2>*np.array([<NUM_LIT:0>, f_stop1, f_pass1, f_pass2, f_stop2, fsamp/<NUM_LIT:2>])/fsamp<EOL>aa = np.array([<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>])<EOL>wts = np.array([dpass/dstop, <NUM_LIT:1>, dpass/dstop])<EOL>return int(N), ff, aa, wts<EOL>

Optimal FIR (equal ripple) Bandpass Order Determination

Text reference: Ifeachor, Digital Signal Processing a Practical Approach,
second edition, Prentice Hall, 2002.
Journal paper reference: F. Mintzer & B. Liu, Practical Design Rules for Optimum
FIR Bandpass Digital Filters, IEEE Transactions on Acoustics and Speech, pp.
204-206, April,1979.


def lowpass_order(f_pass, f_stop, dpass_dB, dstop_dB, fsamp = <NUM_LIT:1>):

dpass = <NUM_LIT:1> - <NUM_LIT:10>**(-dpass_dB/<NUM_LIT:20>)<EOL>dstop = <NUM_LIT:10>**(-dstop_dB/<NUM_LIT:20>)<EOL>Df = (f_stop - f_pass)/fsamp<EOL>a1 = <NUM_LIT><EOL>a2 = <NUM_LIT><EOL>a3 = -<NUM_LIT><EOL>a4 = -<NUM_LIT><EOL>a5 = -<NUM_LIT><EOL>a6 = -<NUM_LIT><EOL>Dinf = np.log10(dstop)*(a1*np.log10(dpass)**<NUM_LIT:2> + a2*np.log10(dpass) + a3)+ (a4*np.log10(dpass)**<NUM_LIT:2> + a5*np.log10(dpass) + a6)<EOL>f = <NUM_LIT> + <NUM_LIT>*(np.log10(dpass) - np.log10(dstop))<EOL>N = Dinf/Df - f*Df + <NUM_LIT:1><EOL>ff = <NUM_LIT:2>*np.array([<NUM_LIT:0>, f_pass, f_stop, fsamp/<NUM_LIT:2>])/fsamp<EOL>aa = np.array([<NUM_LIT:1>, <NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>])<EOL>wts = np.array([<NUM_LIT:1.0>, dpass/dstop])<EOL>return int(N), ff, aa, wts<EOL>

Optimal FIR (equal ripple) Lowpass Order Determination

Text reference: Ifeachor, Digital Signal Processing a Practical Approach,
second edition, Prentice Hall, 2002.
Journal paper reference: Herriman et al., Practical Design Rules for Optimum
Finite Imulse Response Digitl Filters, Bell Syst. Tech. J., vol 52, pp.
769-799, July-Aug., 1973.IEEE, 1973.


m24 = interp24(m)<EOL>t192 = np.arange(len(m24))/<NUM_LIT><EOL>m_max = np.max(np.abs(m24))<EOL>x192 = (<NUM_LIT:1> + a_mod*m24/m_max)*np.cos(<NUM_LIT:2>*np.pi*fc*t192) <EOL>return x192, t192, m24<EOL>

AM transmitter for Case Study of Chapter 17.

Assume input is sampled at 8 Ksps and upsampling
by 24 is performed to arrive at fs_out = 192 Ksps.

Parameters
----------
m : ndarray of the input message signal
a_mod : AM modulation index, between 0 and 1
fc : the carrier frequency in Hz

Returns
-------
x192 : ndarray of the upsampled by 24 and modulated carrier
t192 : ndarray of the upsampled by 24 time axis
m24 : ndarray of the upsampled by 24 message signal

Notes
-----
The sampling rate of the input signal is assumed to be 8 kHz.

Examples
--------
>>> n = arange(0,1000)
>>> # 1 kHz message signal
>>> m = cos(2*pi*1000/8000.*n)
>>> x192, t192 = am_tx(m,0.8,fc=75e3)


x = np.zeros(len(n))<EOL>for k, nn in enumerate(n):<EOL><INDENT>if nn >= -<NUM_LIT:2> and nn <= <NUM_LIT:5>:<EOL><INDENT>x[k] = <NUM_LIT:8> - nn<EOL><DEDENT><DEDENT>return x<EOL>

Generate a triangle pulse as described in Example 6-2
of Chapter 6.

You need to supply an index array n that covers at least [-2, 5].
The function returns the hard-coded signal of the example.

Parameters
----------
n : time index ndarray covering at least -2 to +5.

Returns
-------
x : ndarray of signal samples in x

Examples
--------
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from sk_dsp_comm import sigsys as ss
>>> n = np.arange(-5,8)
>>> x = ss.ex6_2(n)
>>> plt.stem(n,x) # creates a stem plot of x vs n


<EOL>b2,a2 = signal.butter(<NUM_LIT:10>,<NUM_LIT:1>/<NUM_LIT>)<EOL>y1 = upsample(x,<NUM_LIT:2>)<EOL>y1 = signal.lfilter(b2,a2,<NUM_LIT:2>*y1)<EOL>b3,a3 = signal.butter(<NUM_LIT:10>,<NUM_LIT:1>/<NUM_LIT>)<EOL>y2 = upsample(y1,<NUM_LIT:3>)<EOL>y2 = signal.lfilter(b3,a3,<NUM_LIT:3>*y2)<EOL>b4,a4 = signal.butter(<NUM_LIT:10>,<NUM_LIT:1>/<NUM_LIT>)<EOL>y3 = upsample(y2,<NUM_LIT:4>)<EOL>y3 = signal.lfilter(b4,a4,<NUM_LIT:4>*y3)<EOL>return y3<EOL>

Interpolate by L = 24 using Butterworth filters.

The interpolation is done using three stages. Upsample by
L = 2 and lowpass filter, upsample by 3 and lowpass filter, then
upsample by L = 4 and lowpass filter. In all cases the lowpass
filter is a 10th-order Butterworth lowpass.

Parameters
----------
x : ndarray of the input signal

Returns
-------
y : ndarray of the output signal

Notes
-----
The cutoff frequency of the lowpass filters is 1/2, 1/3, and 1/4 to
track the upsampling by 2, 3, and 4 respectively.

Examples
--------
>>> y = interp24(x)