Reconstructs a signal from a framed representation. Adds potentially overlapping frames of a signal with shape `[..., frames, frame_length]`, offsetting subsequent frames by `frame_step`. The resulting tensor has shape `[..., output_size]` where output_size = (frames - 1) * frame_step
(signal, frame_step, name=None)
| 28 | |
| 29 | @tf_export("signal.overlap_and_add") |
| 30 | def overlap_and_add(signal, frame_step, name=None): |
| 31 | """Reconstructs a signal from a framed representation. |
| 32 | |
| 33 | Adds potentially overlapping frames of a signal with shape |
| 34 | `[..., frames, frame_length]`, offsetting subsequent frames by `frame_step`. |
| 35 | The resulting tensor has shape `[..., output_size]` where |
| 36 | |
| 37 | output_size = (frames - 1) * frame_step + frame_length |
| 38 | |
| 39 | Args: |
| 40 | signal: A [..., frames, frame_length] `Tensor`. All dimensions may be |
| 41 | unknown, and rank must be at least 2. |
| 42 | frame_step: An integer or scalar `Tensor` denoting overlap offsets. Must be |
| 43 | less than or equal to `frame_length`. |
| 44 | name: An optional name for the operation. |
| 45 | |
| 46 | Returns: |
| 47 | A `Tensor` with shape `[..., output_size]` containing the overlap-added |
| 48 | frames of `signal`'s inner-most two dimensions. |
| 49 | |
| 50 | Raises: |
| 51 | ValueError: If `signal`'s rank is less than 2, or `frame_step` is not a |
| 52 | scalar integer. |
| 53 | """ |
| 54 | with ops.name_scope(name, "overlap_and_add", [signal, frame_step]): |
| 55 | signal = ops.convert_to_tensor(signal, name="signal") |
| 56 | signal.shape.with_rank_at_least(2) |
| 57 | frame_step = ops.convert_to_tensor(frame_step, name="frame_step") |
| 58 | frame_step.shape.assert_has_rank(0) |
| 59 | if not frame_step.dtype.is_integer: |
| 60 | raise ValueError("frame_step must be an integer. Got %s" % |
| 61 | frame_step.dtype) |
| 62 | |
| 63 | signal_shape = array_ops.shape(signal) |
| 64 | |
| 65 | # All dimensions that are not part of the overlap-and-add. Can be empty for |
| 66 | # rank 2 inputs. |
| 67 | outer_dimensions = signal_shape[:-2] |
| 68 | outer_rank = array_ops.size(outer_dimensions) |
| 69 | |
| 70 | def full_shape(inner_shape): |
| 71 | return array_ops.concat([outer_dimensions, inner_shape], 0) |
| 72 | |
| 73 | frame_length = signal_shape[-1] |
| 74 | frames = signal_shape[-2] |
| 75 | |
| 76 | # Compute output length. |
| 77 | output_length = frame_length + frame_step * (frames - 1) |
| 78 | |
| 79 | # If frame_length is equal to frame_step, there's no overlap so just |
| 80 | # reshape the tensor. |
| 81 | frame_step_static = tensor_util.constant_value(frame_step) |
| 82 | if (frame_step_static is not None and signal.shape.dims is not None and |
| 83 | frame_step_static == signal.shape.dims[-1].value): |
| 84 | output_shape = full_shape([output_length]) |
| 85 | return array_ops.reshape(signal, output_shape, name="fast_path") |
| 86 | |
| 87 | # The following code is documented using this example: |
nothing calls this directly
no test coverage detected