Code Monkey home page Code Monkey logo

czt's Introduction

Chirp Z-Transform (CZT)

PyPI version ci flake8

From Wikipedia:

The chirp Z-transform (CZT) is a generalization of the discrete Fourier transform (DFT). While the DFT samples the Z plane at uniformly-spaced points along the unit circle, the chirp Z-transform samples along spiral arcs in the Z-plane, corresponding to straight lines in the S plane. The DFT, real DFT, and zoom DFT can be calculated as special cases of the CZT.

Getting Started

You can install the CZT package using pip:

# to install the latest release (from PyPI)
pip install czt

# to install the latest commit (from GitHub)
git clone https://github.com/garrettj403/CZT.git
cd CZT
pip install -e .

# to install dependencies for examples
pip install -e .[examples]

# to install dependencies for testing
pip install -e .[testing]

Example

Consider the following time-domain signal:

This is an exponentially decaying sine wave with some distortion from higher-order frequencies. We can convert this signal to the frequency-domain to investigate the frequency content using the Chirp Z-Transform (CZT):

Note that the CZT also allows us to calculate the frequency response over an arbitrary frequency range:

We can see that the signal has frequency components at 1 kHz, 2.5 kHz and 3.5 kHz. To remove the distortion and isolate the 1 kHz signal, we can apply a simple window in the frequency-domain:

Finally, we can use the Inverse Chirp Z-Transform (ICZT) to transform back to the time domain:

As we can see, we were able to remove the higher-order frequencies that were distorting our 1 kHz signal.

You can find this example and others in the examples/ directory.

References

czt's People

Contributors

besler avatar garrettj403 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

czt's Issues

ValueError for Integer arguments of A or W

If a user uses e.g. A=1 then line 61 raises an Error, due to numpy's handling of integer values to negative powers ( like int**(-np.ndarray(dtype=int)) ).
Would suggest to add A=complex(A) and W=complex(W), and/or add dtype=float to np.aranges in lines 60 and 63

Problems running czt after install: No module named czt

When I attempt to run the example "zoom-dft.ipynb" (copy-pasted into a .py file), I receive this error:

Traceback (most recent call last):
  File "zoom-dft.py" line 6, in <module>
    import czt
ModuleNotFoundError: No module named 'czt'

I'm testing on Ubuntu 20.04 LTS
Installed czt with <pip3 install czt>
Ran the program with <python3 zoom-dft.py>

I have also tried downloading the zip from this github page and installing with <python3 setup.py install --user>
I receive the same error there.

I can make it work by copying czt.py into the same directory as the example, but I don't think the installer is working right.

Zoom-DFT

Hi again @garrettj403

I am not sure if there was a special reason to implement time2freq and freq2time the way you did, therefore I did not create a pull request yet.
I have some modified code which takes care of the proper phase and scaling in time2freq and freq2time, and drops the requirement of providing an original frequency or time. Moreover I think, there is something wrong with the scaling in freq2time if not using the original time, but a zoomed in part.


I put it into a notebook to test everything. Had to zip it, because github does not allow ipynb files:
time2freq_new-zoom-dft.ipynb.zip

Here is a quick overview of its contents:


For time2freq the new code shows the same result as your original code, without the need to compute the f_orig
time2freq_original
time2freq_modified


Here you can see what I mean by the incorrect scaling in freq2time. From a quick test I would guess, that there is a factor of len(t_zoom)/len(t) missing. I could be wrong here, but I looked at the example notebook "example/time-to-freq-to-time-domain-conversion.ipynb" and there the recover of the the original function is only working, because there the time->freq conversion has no f_orig and therefor not the proper scaling, so it cancels the improper scaling in freq->time. Don't know if this is the desired behavior.
freq2time_original

However, the modified code has the same amplitude as the transform to the full range without need to provide t_orig:
freq2time_modified

(and of course units should be ms :) )


def time2freq_new(t, x, f=None):
    """Convert signal from time-domain to frequency-domain.

    Args:
        t (np.ndarray): time
        x (np.ndarray): time-domain signal
        f (np.ndarray): frequency for output signal

    Returns:
        np.ndarray: frequency-domain signal

    """

    # Input time array
    dt = t[1] - t[0]  # time step

    # Output frequency array
    if f is None:
        Nf = len(t)  # number of time points
        # proposed change:
        # f = np.fft.fftshift(np.fft.fftfreq(Nf, dt)) # fftshift -> frequencies in normal ordering
        # for now stay compatible with original code:
        f = np.linspace(-1/(2*dt),1/(2*dt),Nf)
    else:
        Nf = len(f)
        f = np.copy(f)
    df = f[1]-f[0]

    # Step
    W = np.exp(-2j * np.pi * df * dt)

    # Starting point
    A = np.exp(2j * np.pi * f[0] * dt)

    # phase
    phase = np.exp(-2j*np.pi * t[0] * f)

    # Frequency-domain transform
    freq_data = czt.czt(x, Nf, W, A)*phase

    return f, freq_data

def freq2time_new(f, X, t=None):
    """Convert signal from frequency-domain to time-domain.

    Args:
        f (np.ndarray): frequency
        X (np.ndarray): frequency-domain signal
        t (np.ndarray): time for output signal
    Returns:
        np.ndarray: time-domain signal

    """

    # Input frequency array
    df = f[1] - f[0]  # time step

    # Output time array
    if t is None:
        Nt = len(f)  # number of time points
        # proposed change:
        # t = np.fft.fftshift(np.fft.fftfreq(Nt, df)) # fftshift -> time in normal ordering
        # for now stay compatible with original code:
        t = np.linspace(0,1/df,Nt)
    else:
        Nt = len(t)
        t = np.copy(t)
    dt = t[1]-t[0]

    # Step
    W = np.exp(2j * np.pi * dt * df)

    # Starting point
    A = np.exp(-2j * np.pi * t[0] * df)

    # phase
    phase = np.exp(2j*np.pi * f[0] * t)

    # Frequency-domain transform
    # for dft and idft I will use czt, since A and W are chosen properly.
    time_data = czt.czt(X, Nt, W, A)*phase/len(f)

    return t, time_data

The following tests did not show an assertion error, so I think the new functions should work as a replacement for the oririnal ones.

np.testing.assert_almost_equal(
    czt.freq2time(*czt.time2freq(t,sig)),
    freq2time_new(*time2freq_new(t,sig)),
    decimal=12)

np.testing.assert_almost_equal(
    czt.time2freq(t,sig,freq_zoom,f_orig=freq),
    time2freq_new(t,sig,freq_zoom),
    decimal=12)

Create benchmark to find fastest t_method

czt has several different options for t_method. These methods should be compared via a benchmark to find the fastest option, which should then become the default.

Using czt in the freq2time function

I partially read the source article [1] and noticed this statement:

In some cases[15], a modified version of the forward CZT algorithm, in which the logarithmic spiral contour was traversed in the opposite direction, was described as the ICZT algorithm. However, this method does not really invert the CZT. It works only in some special cases, e.g., when A=1 and W=e^(−2πi/n). That is, in the cases when the CZT reduces to the DFT. In the general case, i.e., when A,W∈C∖{0}, that method generates a transform that does not invert the CZT.

So is it legitimate to use this approach in "freq2time" utilizing the CZT, instead of the also available ICZT?
I don't know what is meant with "special cases", so if it covers all ZoomFFT cases (with constant magnitudes).
Is it only necessary for A and W to lie on the unit circle here!?

[1] https://www.nature.com/articles/s41598-019-50234-9

2D support

Thank you very much for putting together a Numpy based chirp-z transform library together! May I ask if you have any plans to support 2D case in the near future.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.