Skip to content

Add group delay, Nyquist, z-plane and polar plots - #107

Open
aguirreSL wants to merge 2 commits into
PyTTaMaster:developmentfrom
aguirreSL:dev-plot_more
Open

aguirreSL wants to merge 2 commits into
PyTTaMaster:developmentfrom
aguirreSL:dev-plot_more

Conversation

@aguirreSL

Copy link
Copy Markdown

Adds to pytta.functions four plots that the ITA-Toolbox has (ita_plot_groupdelay, ita_plot_nyquist, ita_plot_zplane and ita_plot_polar). Each one returns the matplotlib Figure:

  1. plot_group_delay(*sigObjs, xLim=None, yLim=None, title=None): the group delay of every channel, in ms, on a logarithmic frequency axis, from group_delay of [FEATURE] add group_delay, coherence, cepstrum and MLS #80.
  2. plot_nyquist(*sigObjs, title=None): the imaginary against the real part of the spectrum (freqSignal, as plot_freq shows it) of every channel.
  3. plot_zplane(zeros, poles, title=None): zeros and poles with the unit circle; scipy.signal.tf2zpk(b, a) gives them from the coefficients.
  4. plot_polar(angles, levels, labels=None, rLim=None, title=None): a directivity, levels in dB against angles in degrees with 0 to the front, one column per curve, closed at the first angle.

This pull request builds on #80 and shows its commit until #80 is merged.

The tests in tests/test_plot_more.py read the plotted data back:

  1. The group delay of a delay of 40 samples at 8 kHz is 5 ms at every frequency (1.8e-15 ms).
  2. The Nyquist plot of a delayed impulse is a circle above DC (radius spread 3.1e-16).
  3. The markers of plot_zplane are at the zeros and poles of a fourth-order Butterworth filter.
  4. The polar curve is closed and its zero angle points up.

Checked with Python 3.12, numpy 1.26 and scipy 1.17. The 7 failures of development (3 in test_h5io.py, 4 in test_pyttasave.py) are the same with and without this change.

Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com

aguirreSL and others added 2 commits October 31, 2026 21:53
group_delay(signal) returns the group delay of each channel in seconds,
from the derivative of the spectrum, Re{DFT(n x[n]) / DFT(x[n])} / fs,
which needs no phase unwrapping.

coherence(x, y, winSize=1024) returns the magnitude squared coherence
with scipy.signal.coherence (Welch, Hann, 50 % overlap). Channels are
paired one to one, and a single channel is paired with all of the other.

cepstrum(signal, kind='complex') returns the real or complex cepstrum.
For the complex one the integer linear phase is removed first and
returned, and icepstrum(cepstrumObj, delay) inverts it. The magnitude
floor is the same as in minimum_phase.

generate.mls(order, samplingRate) returns one period of a symmetrical
MLS from scipy.signal.max_len_seq, and mls_deconvolution(response,
order) recovers the impulse response by periodic cross-correlation
normalized by L + 1. With more than one period the first is dropped and
the others are averaged.

Tests pin the group delay of a pure delay and of a first order allpass,
the coherence of a noisy filtered signal against SNR / (1 + SNR), the
cepstra of a minimum phase filter against the analytic series, the
complex cepstrum round trip with its delay, the exact MLS
autocorrelation and the deconvolution of a FIR with its known offset
-sum(h) / (L + 1).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant