| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- from types import SimpleNamespace
- import numpy as np
- def decompress_shape(
- compressed_shape: SimpleNamespace, force_decompression: bool = False
- ) -> np.ndarray:
- """
- Decompress a gradient or pulse shape compressed with a run-length compression scheme on the derivative. The given
- shape is structure with the following fields:
- - num_samples - the number of samples in the uncompressed waveform
- - data - containing the compressed waveform
- See also `compress_shape.py`.
- Parameters
- ----------
- compressed_shape : SimpleNamespace
- Run-length encoded shape.
- force_decompression : bool, default=False
- Returns
- -------
- decompressed_shape : numpy.ndarray
- Decompressed shape.
- """
- data_pack = compressed_shape.data
- data_pack_len = len(data_pack)
- num_samples = int(compressed_shape.num_samples)
- if not force_decompression and num_samples == data_pack_len:
- # Uncompressed shape
- decompressed_shape = data_pack
- return decompressed_shape
- decompressed_shape = np.zeros(num_samples) # Pre-allocate result matrix
- # Decompression starts here
- data_pack_diff = data_pack[1:] - data_pack[:-1]
- # When data_pack_diff == 0 the subsequent samples are equal ==> marker for repeats (run-length encoding)
- data_pack_markers = np.where(data_pack_diff == 0.0)[0]
- count_pack = 0 # Points to current compressed sample
- count_unpack = 0 # Points to current uncompressed sample
- for i in range(len(data_pack_markers)):
- # This index may have "false positives", e.g. if the value 3 repeats 3 times, then we will have 3 3 3
- next_pack = data_pack_markers[i]
- current_unpack_samples = next_pack - count_pack
- if current_unpack_samples < 0: # Rejects false positives
- continue
- elif current_unpack_samples > 0: # We have an unpacked block to copy
- decompressed_shape[
- count_unpack : count_unpack + current_unpack_samples
- ] = data_pack[count_pack:next_pack]
- count_pack += current_unpack_samples
- count_unpack += current_unpack_samples
- # Packed/repeated section
- rep = int(data_pack[count_pack + 2] + 2)
- decompressed_shape[count_unpack : (count_unpack + rep)] = data_pack[count_pack]
- count_pack += 3
- count_unpack += rep
- # Samples left?
- if count_pack <= data_pack_len - 1:
- assert data_pack_len - count_pack == num_samples - count_unpack
- # Copy the rest of the shape, it is unpacked
- decompressed_shape[count_unpack:] = data_pack[count_pack:]
- decompressed_shape = np.cumsum(decompressed_shape)
- return decompressed_shape
|