audio_synch_tool package

Submodules

audio_synch_tool.mvn module

This module contains functionality concerning the adaption of the XSENS MVN-XML format into our Python setup.

The official explanation can be found in section 14.4 of this document::
https://usermanual.wiki/Document/MVNUserManual.1147412416.pdf

A copy is stored in this repository.

The following section introduces more informally the contents of the imported MVN file and the way they can be accessed from Python:

# load mvn schema https://www.xsens.com/mvn/mvnx/schema.xsd
mvn_path = "XXX"
mmvn = Mvn(mvn_path, validate=True)

# These elements contain some small metadata:
mmvn.mvn.attrib
mmvn.mvn.comment.attrib
mmvn.mvn.securityCode.attrib["code"]
mmvn.mvn.subject.attrib

# subject.segments contain 3D pos_b labels:
for ch in mmvn.mvn.subject.segments.iterchildren():
    ch.attrib, [p.attrib for p in ch.points.iterchildren()]

# Segments can look as follows: ``['Pelvis', 'L5', 'L3', 'T12', 'T8', 'Neck',
'Head', 'RightShoulder', 'RightUpperArm', 'RightForeArm', 'RightHand',
'LeftShoulder', 'LeftUpperArm', 'LeftForeArm', 'LeftHand', 'RightUpperLeg',
'RightLowerLeg', 'RightFoot', 'RightToe', 'LeftUpperLeg', 'LeftLowerLeg',
'LeftFoot', 'LeftToe']``

# sensors is basically a list of names
for s in mmvn.mvn.subject.sensors.iterchildren():
    s.attrib

#  Joints is a list that connects segment points:
for j in mmvn.mvn.subject.joints.iterchildren():
    j.attrib["label"], j.getchildren()

# miscellaneous:
for j in mmvn.mvn.subject.ergonomicJointAngles.iterchildren():
    j.attrib, j.getchildren()

for f in mmvn.mvn.subject.footContactDefinition.iterchildren():
    f.attrib, f.getchildren()

# The bulk of the data is in the frames.
print("frames_metadata:", mmvn.frames_metadata)
print("first_frame_type:", mmvn.config_frames[0]["type"])
print("normal_frames_type:", mmvn.normal_frames[0]["type"])
print("num_normal_frames:", len(mmvn.normal_frames))

# Metadata looks like this:
{'segmentCount': '23', 'sensorCount': '17', 'jointCount': '22'}

# config frames have the following fields:
['orientation', 'position', 'time', 'tc', 'ms', 'type']

# normal frames have the following fields:
['orientation', 'position', 'velocity', 'acceleration',
 'angularVelocity', 'angularAcceleration', 'footContacts',
 'sensorFreeAcceleration', 'sensorMagneticField', 'sensorOrientation',
 'jointAngle', 'jointAngleXZY', 'jointAngleErgo', 'centerOfMass', 'time',
 'index', 'tc', 'ms', 'type']

The following fields contain metadata about the frame:

time:ms since start (integer). It is close to int(1000.0 * index / samplerate), being equal most of the times and at most 1 milisecond away. It is neither truncated nor rounded, maybe it is given by the hardware.
index:starts with 0, +1 each normal frame
tc:string like ‘02:23:28:164’
ms:unix timestamp like 1515983008686 (used to compute time)
type:one of “identity”, “tpose”, “tpose-isb”, “normal”

# The following fields are float vectors of the following dimensionality:

orientation:segmentCount*4 = 92 Quaternion vector
position, velocity, acceleration, angularVelocity, angularAcceleration:
 segmentCount*3 = 69 3D vectors in (x,y,z) format
footContacts:4 4D boolean vector
sensorFreeAcceleration, sensorMagneticField:
 sensorCount*3 = 51
sensorOrientation:
 sensorCount*4 = 68
jointAngle, jointAngleXZY:
 jointCount*3 = 66
jointAngleErgo:12
centerOfMass:3

The units are SI for position, velocity and acceleration. Angular magnitudes are in radians except the jointAngle... ones that are in degrees. All 3D vectors are in (x,y,z) format, but the jointAngle... ones differ in the Euler-rotation order by which they are computed (ZXY, standard or XZY, for shoulders usually).

class audio_synch_tool.mvn.Mvn(mvn_path, validate=False)[source]

Bases: object

This class imports and adapts an XML file (expected to be in MVN format) to a Python-friendly representation. See this module’s docstring for usage examples and more information.

MVNX_SCHEMA_PATH = '/home/docs/checkouts/readthedocs.org/user_builds/audio-synch-tool/checkouts/latest/audio_synch_tool/data/mvn_schema_adapted.xsd'
export(filepath, pretty_print=True, extra_comment='')[source]

Saves the current mvn attribute to the given file path as XML and adds the self.mvn.attrib["pythonComment"] attribute with a timestamp.

extract_frame_info()[source]
Returns:The tuple (frames_metadata, config_frames, normal_frames)
static extract_frames(mvn)[source]

The bulk of the MVN file is the mvn->subject->frames section. This function parses it and returns its information in a python-friendly format.

Parameters:mvn – An XML tree, expected to be in MVN format
Returns:a tuple (frames_metadata, config_frames, normal_frames) where the metadata is a dict in the form {'segmentCount': '23', 'sensorCount': '17', 'jointCount': '22'}, the config frames are the first 3 frame entries (expected to contain special config info) and the normal_frames are all frames starting from the 4th. Both frame outputs are relational collections of dictionaries that can be formatted into tabular form.
static extract_normalframe_magnitudes(normal_frames)[source]
Returns:A list of the magnitude names in each of the self.normal_frames
extract_normalframe_sequences(frames_metadata, normal_frames)[source]
Returns:a dict with np arrays of shape (num_normalframes, num_channels) where the number of channels is e.g. 1 for scalar magnitudes, 3 for 3D vectors (in xyz format)…
extract_segments()[source]
Returns:A list of the segment names in self.mvn.subject.segments, ordered by id (starting at 1 and incrementing +1).
get_audio_synch()[source]
Returns:a list with the audio_sample attributes for the normal frames, or None if there is at least 1 normal frame without the audio_sample attribute. Note that this function assumes that the entries are integers in the form ‘123’, so they are retrieved int(x). If that is not the case, they may be truncated or even throw an exception.
set_audio_synch(stretch, shift)[source]

Given the list of normal frames in this Mvn, each one with an “index” field, this function adds an audio_sample attribute to each frame, where audio_sample = round(index * stretch + shift). See utils.convert_anchors for converting anchor points into stretch and shift.

audio_synch_tool.plotters module

audio_synch_tool.utils module

class audio_synch_tool.utils.DownsamplableFunction(y_arr, max_datapoints, x_arr=None)[source]

Bases: object

Encapsulates the downsampling functionality to prevent side effects, and reduce code verbosity in plotter.

downsampled(xstart, xend, verbose=False)[source]

This function performs downsampling by reading one sample every (xend-xstart)//max_datapoints from x_vals and y_vals.

class audio_synch_tool.utils.IdentityFormatter[source]

Bases: object

This functor can be passed to plt.FuncFormatter to generate custom tick labels. It fulfills the interface (val, pos)->str.

Specifically, for a given val returns str(val). In most cases this is the default matplotlib behaviour, but using this formatter forces it to behave ALWAYS like this and avoid some other smart conversions like scientific notation for big numbers.

class audio_synch_tool.utils.ProportionalFormatter(ratio, num_decimals=3)[source]

Bases: object

This functor can be passed to plt.FuncFormatter to generate custom tick labels. It fulfills the interface (val, pos)->str.

Specifically, converts val number representing a sample into a string in the form val [val2] where val2 = val * ratio. This can be useful e.g. to show the original values if the signal was resampled.

class audio_synch_tool.utils.SampleToTimestampFormatter(samplerate, num_decimals=3, show_idx=True)[source]

Bases: object

This functor can be passed to plt.FuncFormatter to generate custom tick labels. It fulfills the interface (val, pos)->str.

Specifically, converts val number representing a sample into a string showing the corresponding elapsed time since sample 0, asuming the given samplerate. Usage example:

ax.xaxis.set_major_formatter(plt.FuncFormatter(
                             SampleToTimestampFormatter(sr)))
class audio_synch_tool.utils.SharedXlimCallbackFunctor(functors)[source]

Bases: object

If multiple axes share the x-limits, calling the functor from one of them triggers a call for every one of them.

class audio_synch_tool.utils.SynchedMvnFormatter(mvn, num_decimals=3)[source]

Bases: object

This functor can be passed to plt.FuncFormatter to generate custom tick labels. It fulfills the interface (val, pos)->str.

Specifically, it looks in the MVN file for the frame index with the given val and, if found, returns the string val [frame_idx] (otherwise just val). For that, it expects that the frame has defined the audio_sample attribute.

class audio_synch_tool.utils.Timedelta(sample_nr, samplerate)[source]

Bases: object

as_tuple()[source]
Returns:the tuple of integers (days, hours, mins, secs, microsecs)
days
hours
microsecs
mins
sample_nr
samplerate
secs
total_seconds
class audio_synch_tool.utils.XlimCallbackFunctor(axis, lines, arrays, shared_axes, verbose=False)[source]

Bases: object

Encapsulates the downsampling callback functionality to prevent side effects. Instances of this functor can be passed to an axis like this:

``ax.callbacks.connect('xlim_changed',
                 DownsamplingCallbackFunctor(ax, [line1..], [arr1...]))``
audio_synch_tool.utils.arr_has_all_integers(arr)[source]
audio_synch_tool.utils.convert_anchors(ori1, dest1, ori2, dest2)[source]

Given a signal that we want to shift and stretch on the x axis, this affine operation can be defined by picking 2 points of the signal (ori1 and ori2, called here “anchors”), and mapping them to other 2 points (dest1 and dest2). For the given anchors, this function returns the corresponding stretching ratio and shifting amount (after stretching) needed to match the given anchors. This is given by solving the formula:

``[dest1, dest2] = shift + stretch * [ori1, ori2]``
Parameters:ori1 (number) – any real-valued number. Same for ori2, dest1, dest2.
Returns:a tuple (stretch, shift) with 2 real-valued numbers.
audio_synch_tool.utils.make_timestamp(timezone='Europe/Berlin')[source]

Output example: day, month, year, hour, min, sec, milisecs: 10_Feb_2018_20:10:16.151

audio_synch_tool.utils.resolve_path(*path_elements)[source]

A convenience path wrapper to find elements in this package. Retrieves the absolute path, given the OS-agnostic path relative to the package root path (by bysically joining the path elements via os.path.join). E.g., the following call retrieves the absolute path for <PACKAGE_ROOT>/a/b/test.txt:

resolve_path("a", "b", "test.txt")
Params strings path_elements:
 From left to right, the path nodes, the last one being the filename.
Return type:str

Module contents