Matmul Transform¶
The Matmul
transform performs matrix multiplication between input data and a specified matrix, enabling linear transformations of time-series data.
Overview¶
Matmul
is a versatile transform that:
- Applies a linear transformation to each time slice of the input data
- Supports different array backends for efficient computation
- Handles gap buffers appropriately
- Preserves the time structure of frames
Basic Usage¶
# Basic usage of Matmul (not tested by mkdocs)
"""
import numpy as np
from sgnts.transforms import Matmul
from sgnts.sources import FakeSeriesSource
from sgnts.base import NumpyBackend
# Create a matrix for multiplication
# This example creates a 2x4 matrix that will transform 4D inputs to 2D outputs
matrix = np.array([
[1, 2, 3, 4], # First output channel
[5, 6, 7, 8] # Second output channel
])
# Create a source with matching shape
source = FakeSeriesSource(
rate=2048,
sample_shape=(4,), # 4-dimensional data at each time point
signal_type="white"
)
# Create a Matmul transform
matmul_transform = Matmul(
matrix=matrix,
backend=NumpyBackend
)
# Connect source to matmul transform
source.add_dest(matmul_transform)
# Process data
source.process()
matmul_transform.process()
# Pull the transformed frame
frame = matmul_transform.pull()
# The frame contains data that has been matrix-multiplied with the specified matrix
# Original data shape: (4, N) where N is the number of time samples
# Output data shape: (2, N) - the number of rows in the matrix determines the output dimensions
"""
Dimensionality Reduction¶
A common use case for Matmul
is dimensionality reduction:
# Dimensionality reduction example (not tested by mkdocs)
"""
import numpy as np
from sgnts.transforms import Matmul
from sgnts.sources import FakeSeriesSource
# Create a high-dimensional source
source = FakeSeriesSource(
rate=2048,
sample_shape=(16,), # 16-dimensional data
signal_type="white"
)
# Create a matrix that projects 16D data to 3D
# This could be derived from PCA or other dimensionality reduction techniques
reduction_matrix = np.random.randn(3, 16) # 3 output dimensions, 16 input dimensions
# Normalize the matrix rows
for i in range(reduction_matrix.shape[0]):
reduction_matrix[i, :] = reduction_matrix[i, :] / np.linalg.norm(reduction_matrix[i, :])
# Create a Matmul transform for dimensionality reduction
dim_reducer = Matmul(matrix=reduction_matrix)
# Connect and process
source.add_dest(dim_reducer)
source.process()
dim_reducer.process()
# Pull the reduced-dimension frame
frame = dim_reducer.pull()
# The output data has shape (3, N) instead of the original (16, N)
"""
Coordinate Transformations¶
Matmul
can be used to apply coordinate transformations:
# Coordinate transformation example (not tested by mkdocs)
"""
import numpy as np
from sgnts.transforms import Matmul
from sgnts.sources import FakeSeriesSource
# Create a source with 3D data (e.g., x, y, z coordinates)
source = FakeSeriesSource(
rate=2048,
sample_shape=(3,),
signal_type="white"
)
# Create a rotation matrix (45 degrees around z-axis)
theta = np.pi / 4 # 45 degrees
rotation_matrix = np.array([
[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1]
])
# Create a Matmul transform
rotator = Matmul(matrix=rotation_matrix)
# Connect and process
source.add_dest(rotator)
source.process()
rotator.process()
# Pull the rotated frame
frame = rotator.pull()
# The data has been rotated 45 degrees around the z-axis
"""
Channel Mixing¶
Matmul
can mix channels in multichannel data:
# Channel mixing example (not tested by mkdocs)
"""
import numpy as np
from sgnts.transforms import Matmul
from sgnts.sources import FakeSeriesSource
# Create a source with stereo audio (2 channels)
source = FakeSeriesSource(
rate=44100, # Audio sample rate
sample_shape=(2,), # Stereo audio
signal_type="sine",
fsin=440 # 440 Hz tone
)
# Create a matrix for stereo to mono conversion
# Average the left and right channels (0.5 * left + 0.5 * right)
stereo_to_mono = np.array([[0.5, 0.5]]) # 1x2 matrix
# Create a Matmul transform
mixer = Matmul(matrix=stereo_to_mono)
# Connect and process
source.add_dest(mixer)
source.process()
mixer.process()
# Pull the mixed frame
frame = mixer.pull()
# The output has been converted from stereo (2 channels) to mono (1 channel)
"""
Integration in Processing Pipelines¶
# Pipeline integration example (not tested by mkdocs)
"""
import numpy as np
from sgnts.transforms import Matmul, AmplifyTransform
from sgnts.sources import FakeSeriesSource
from sgnts.sinks import DumpSeriesSink
# Create a source with multi-channel data
source = FakeSeriesSource(
rate=2048,
sample_shape=(4,),
signal_type="sine",
fsin=10.0
)
# Create a matrix that extracts specific channels
# This matrix selects channels 0 and 2 from the 4-channel input
extraction_matrix = np.array([
[1, 0, 0, 0], # Select channel 0
[0, 0, 1, 0] # Select channel 2
])
# Create a Matmul transform
extractor = Matmul(matrix=extraction_matrix)
# Create an amplifier to boost the selected channels
amplifier = AmplifyTransform(factor=2.0)
# Create a sink
sink = DumpSeriesSink(fname="extracted_channels.txt")
# Connect the pipeline
source.add_dest(extractor)
extractor.add_dest(amplifier)
amplifier.add_dest(sink)
# Run the pipeline
for _ in range(10):
source.process()
extractor.process()
amplifier.process()
sink.process()
# The output file contains only channels 0 and 2, amplified by a factor of 2
"""
Best Practices¶
When using Matmul
:
-
Match matrix dimensions - ensure that the number of columns in your matrix matches the first dimension of your input data
-
Consider normalization - normalize matrix rows to prevent scaling issues, especially for coordinate transforms
-
Use appropriate backend - choose the array backend that best matches your computation needs (NumPy, PyTorch, etc.)
-
Mind computational cost - matrix multiplication can be computationally intensive for large matrices or high sample rates
-
Check output shape - the output shape will be (matrix.shape[0], original_time_samples)
-
Consider chaining - multiple matrix multiplications can be combined by multiplying the matrices first, which is more efficient than applying them sequentially