PyWavelets / pywt

PyWavelets - Wavelet Transforms in Python
http://pywavelets.readthedocs.org
MIT License
2.03k stars 469 forks source link

Wavelet coefficients to single array (and vice versa?) #166

Closed stsievert closed 8 years ago

stsievert commented 8 years ago

In my subfield (signal processing), it's common to see the full level wavelet transforms represented in a single array. This adds indexing ease and wavelet transforms tend to be treated as complete arrays.

I'd like to see

x = np.random.rand(10)
coeffs = pywt.wavedec(x)
w = pywt.coeffs_to_array(coeffs)
# perform a variety of signal processing algorithms
# ...
coeffs_processed = pywt.array_to_coeffs()
y = pywt.waverec(x)

I see two options for an interface:

kwohlfahrt commented 8 years ago

This was discussed before, in #93 and #103, and the main issue was that the coefficient lengths for some padding modes aren't equal, so coefficients for >1D transform cannot be tightly packed into an array. This mismatch in lengths is also used to encode the fact that the input array was odd-length, so that information would be permanently lost.

>>> coefs = pywt.wavedec(np.ones(10), 'haar', 'periodization')
>>> list(map(len, coefs))
[2, 2, 3, 5] # 2 + 2 != 3
>>> rec = pywt.waverec(coefs, 'haar')
>>> len(rec)
10 # Note odd length step at 1st level is preserved

Of your two approaches, I'd prefer the utility function, but I'm not sure how it would deal with the issue above.

stsievert commented 8 years ago

At the very least, I'd like to see utility functions that handle 1D and 2D arrays for Haar and Daubechies wavelets. I'd be okay providing utility functions that only work in some cases and documenting when they don't work (and throwing errors if necessary). Maybe something like below?

def coeffs_to_array(coeffs, padding=None):
    if padding == 'periodization' and len(x) % 2 == 1:
        raise ValueError('When padding={} this function only works for even length arrays.'.format(padding))
    # implementation...
kwohlfahrt commented 8 years ago

That seems sensible. Use a user-define padding value, and if it is None raise an exception if the lengths don't match. It shouldn't depend on the wavelet used, and nD would be nice to have if it works for 2D. What should be done if a member of the coefficients is None? It could be filled with 0.0, the padding value, or be an error.

The other thing to think about is how to go back from the array to the coefficients? I can't think of any way without passing the coefficient sizes (or the initial size and calculating them on demand) into the array_to_coeffs function.

grlee77 commented 8 years ago

I had worked on this a little, but ran into some of the problems @kwohlfahrt mentions above. That being said, I do have a pair of functions that do exactly what you are requesting with wavelet_coeffs_to_array and array_to_wavelet_coeffs that work at least for a subset of cases. I don't think they are quite ready for submission as an official PR, but maybe I can open a work-in-progress PR (that may or may not get finished in the near future). That way you can try them out and let me know if problems come up in your use case.

grlee77 commented 8 years ago

the version I made was for the n-dimensional case

stsievert commented 8 years ago

This is closed by #168.