spyrit.core.meas.DynamicHadamSplit2d.forward

DynamicHadamSplit2d.forward(x: tensor) tensor[source]

Simulates noisy measurements leveraging the Kronecker structure of the 2d splitted Hadamard transform A.

Each measurement is acquired as, for \(k \in \{1, ..., 2M\}\):

\[y_k = \mathcal{N}\left( \sum_{i, j} A_{1d}[r_k, i] x_{t=k}[i, j] A_{1d}[j, c_k] \right),\]

where \(A_{1d} \in \mathbb{R}_+^{2h\times h}\) contains the positive and negative components of a 1d Hadamard matrix, \(x_{t=k} \in \mathbb{R}^{h \times h}\) is \(k^{\rm{th}}\) frame of the video, \((r_k, c_k) = (\left \lfloor k / h \right\rfloor, k \bmod h)\) are the row and column indices of the 1d Hadamard matrix used to generate the 2d Hadamard pattern used at time \(t=k\).

Args:

x (torch.tensor): Video signal \(x\) whose dimensions self.meas_dims must be of shape self.meas_shape and dimension self.time_dim must be of size 2 * self.M.

Returns:

torch.tensor: Measurement vector \(m\) of length 2*self.M.

Example:
>>> import torch
>>> from spyrit.core.noise import Poisson
>>> from spyrit.core.meas import DynamicHadamSplit2d
>>>
>>> x = torch.rand([1, 2 * 32**2, 3, 40, 40])  # dummy RGB video with 2 * 32**2 frames of size 40x40
>>> alpha = 5  # noise level
>>> noise_op = Poisson(alpha=alpha, g=1/alpha)
>>> meas_op = DynamicHadamSplit2d(time_dim=1, h=32, M=32**2, img_shape=(40, 40), noise_model=noise_op)  # acquisition with 2*M splitted Hadamard patterns of size hxh.
>>> print(meas_op)
DynamicHadamSplit2d(
  (noise_model): Poisson()
)
>>>
>>> y = meas_op(x)  # simulate noisy dynamic measurements
>>> print(y.shape)
torch.Size([1, 3, 2048])