Skip to content

Commit

Permalink
0.6.3 release
Browse files Browse the repository at this point in the history
See CHANGELOG.md
  • Loading branch information
OverLordGoldDragon committed Jan 23, 2022
1 parent 7e9e71f commit d15e753
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 6 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
### 0.6.2 (1-23-2022): QoL, cleanups, fixes
### 0.6.3 (1-23-2022): QoL, cleanups, fixes

#### FEATURES
- `freq_to_scale` & `scale_to_freq`, experimental
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ The Discrete Fourier Transform lays the foundation of signal processing with rea

Short form:

> John Muradeli, ssqueezepy, 2020. GitHub repository, https://github.com/OverLordGoldDragon/ssqueezepy/. DOI: 10.5281/zenodo.5080514
> John Muradeli, ssqueezepy, 2020. GitHub repository, https://github.com/OverLordGoldDragon/ssqueezepy/. DOI: 10.5281/zenodo.5080508
BibTeX:

Expand All @@ -183,7 +183,7 @@ BibTeX:
author={John Muradeli},
journal={GitHub. Note: https://github.com/OverLordGoldDragon/ssqueezepy/},
year={2020},
doi={10.5281/zenodo.5080514},
doi={10.5281/zenodo.5080508},
}
```

Expand Down
2 changes: 1 addition & 1 deletion ssqueezepy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"""


__version__ = '0.6.2'
__version__ = '0.6.3'
__title__ = 'ssqueezepy'
__author__ = 'John Muradeli'
__license__ = __doc__
Expand Down
125 changes: 123 additions & 2 deletions ssqueezepy/experimental.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
import warnings
import numpy as np
from .wavelets import Wavelet, center_frequency
from .utils import cwt_scalebounds
from .utils import backend as S, cwt_scalebounds
from .utils.common import EPS32, EPS64, p2up, trigdiff
from .ssqueezing import ssqueeze
from ._ssq_cwt import phase_cwt, phase_cwt_num
from ._ssq_stft import phase_stft, _make_Sfs


__all__ = ['freq_to_scale', 'scale_to_freq']
__all__ = ['freq_to_scale', 'scale_to_freq', 'phase_ssqueeze', 'phase_transform']


def freq_to_scale(freqs, wavelet, N, fs=1, n_search_scales=None, kind='peak',
Expand Down Expand Up @@ -136,3 +140,120 @@ def scale_to_freq(scales, wavelet, N, fs=1, padtype='reflect'):

freqs *= fs # [0, ..., fs/2]
return freqs


def phase_ssqueeze(Wx, dWx=None, ssq_freqs=None, scales=None, Sfs=None, fs=1.,
t=None, squeezing='sum', maprange=None, wavelet=None,
gamma=None, was_padded=True, flipud=False,
rpadded=False, padtype=None, N=None, n1=None,
difftype=None, difforder=None,
get_w=False, get_dWx=False, transform='cwt'):
"""Take `phase_transform` then `ssqueeze`. Can be used on an arbitrary
CWT/STFT-like time-frequency transform `Wx`.
Experimental; prefer `ssq_cwt` & `ssq_stft`.
# Arguments:
Wx, dWx (see w), ssq_freqs, scales, Sfs, fs, t, squeezing, maprange,
wavelet, gamma, was_padded, flipud:
See `help(ssqueezing.ssqueeze)`.
rpadded: bool (default None) / None
Whether `Wx` (and `dWx`) is passed in padded. `True` will unpad
`Wx` and `dWx` before SSQ. Also, if `dWx` is None:
- `rpadded==False`: will pad `Wx` in computing `dWx` if
`padtype!=None`, then unpad both before SSQ
- `rpadded==True`: won't pad `Wx` regardless of `padtype`
padtype: str / None
Used if `rpadded==False`. See `help(utils.padsignal)`. Note that
padding `Wx` isn't same as passing padded `Wx` from `cwt`, but it
can get close.
N, n1: int / None
Needed if `rpadded==True` to unpad `Wx` & `dWx` as `Wx[:, n1:n1 + N]`.
difftype, difforder: str
Used if `dWx = None` and `transform == 'cwt'`; see `help(ssq_cwt)`.
get_w, get_dWx: bool
See `help(ssq_cwt)`.
# Returns:
Tx, Wx, ssq_freqs, scales, Sfs, w, dWx
"""
w, Wx, dWx, Sfs, gamma = phase_transform(
Wx, dWx, difftype, difforder=difforder, gamma=gamma, rpadded=rpadded,
padtype=padtype, N=N, n1=n1, get_w=get_w, fs=fs, transform=transform)

if w is not None and not get_dWx:
dWx = None

if maprange is None:
maprange = 'peak' if transform == 'cwt' else 'maximal'
Tx, ssq_freqs = ssqueeze(Wx, w, ssq_freqs, scales, Sfs, fs=fs, t=t,
squeezing=squeezing, maprange=maprange,
wavelet=wavelet, gamma=gamma, was_padded=was_padded,
flipud=flipud, dWx=dWx, transform=transform)
return Tx, Wx, ssq_freqs, scales, Sfs, w, dWx


def phase_transform(Wx, dWx=None, difftype='trig', difforder=4, gamma=None,
fs=1., Sfs=None, rpadded=False, padtype='reflect', N=None,
n1=None, get_w=False, transform='cwt'):
"""Unified method for CWT & STFT SSQ phase transforms.
See `help(_ssq_cwt.phase_cwt)` and `help(_ssq_stft.phase_stft)`.
"""
def _cwt(Wx, dWx, fs, gamma, N, n1, difftype, difforder, rpadded, padtype,
get_w):
# infer `N` and/or `n1`
if N is None and not rpadded:
N = Wx.shape[-1]
if n1 is None:
_, n1, _ = p2up(N)
# compute `dWx` if not supplied
if dWx is None:
dWx = trigdiff(Wx, fs, padtype, rpadded, N=N, n1=n1, transform='cwt')

if get_w:
if difftype == 'trig':
# calculate instantaneous frequency directly from the
# frequency-domain derivative
w = phase_cwt(Wx, dWx, difftype, gamma)
elif difftype == 'phase':
# !!! bad; yields negatives, and forcing abs(w) doesn't help
# calculate inst. freq. from unwrapped phase of CWT
w = phase_cwt(Wx, None, difftype, gamma)
elif difftype == 'numeric':
# !!! tested to be very inaccurate for small scales
# calculate derivative numericly
Wx = Wx[:, (n1 - 4):(n1 + N + 4)]
dt = 1 / fs
w = phase_cwt_num(Wx, dt, difforder, gamma)
else:
w = None
return w, Wx, dWx

def _stft(Wx, dWx, fs, gamma, Sfs, get_w):
if Sfs is None:
Sfs = _make_Sfs(Wx, fs)
if get_w:
w = phase_stft(Wx, dWx, Sfs, gamma)
else:
w = None
return w, Wx, dWx, Sfs

# validate args
if transform == 'stft' and dWx is None:
raise NotImplementedError("`phase_transform` without `dWx` for "
"STFT is not currently supported.")
if rpadded and N is None:
raise ValueError("`rpadded=True` requires `N`")
if Wx.ndim > 2 and get_w:
raise NotImplementedError("`get_w=True` unsupported with batched input.")

# gamma
if gamma is None:
gamma = 10 * (EPS64 if S.is_dtype(Wx, 'complex128') else EPS32)

# take phase transform if `get_w` else only compute `dWx` (if None)
if transform == 'cwt':
w, Wx, dWx = _cwt(Wx, dWx, fs, gamma, N, n1, difftype, difforder,
rpadded, padtype, get_w)
Sfs = None
elif transform == 'stft':
w, Wx, dWx, Sfs = _stft(Wx, dWx, fs, gamma, Sfs, get_w)

return w, Wx, dWx, Sfs, gamma

0 comments on commit d15e753

Please sign in to comment.