Qu

ellip

Builtin index · Signal processing

result = ellip(order, ripple_db, atten_db, kind, cutoff, fs)

Input: order, ripple_db, atten_db, kind, cutoff, fs · Output: result

What it is

order: number; ripple_db/atten_db: numbers (dB); kind: string; cutoff: number or length-2 vector (Hz); fs: number (Hz).

Overloads

cutoff can be number or vector.

2 forms. Each carries its own inputs, outputs and worked example — pick the tab for the one you are calling.

CodeInputOutputDescription
result = ellip(order, ripple_db, atten_db, "low"/"high", cutoff, fs)
order numberorder: number.
ripple_db numberripple_db/atten_db: numbers (dB).
atten_db numberripple_db/atten_db: numbers (dB).
"low"/"high" —not documented yet
cutoff number or vectorcutoff: number or length-2 vector (Hz).
fs numberfs: number (Hz).
result number
A single Hz number.

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

fs = 1000
lp = ellip(4, 1, 40, "low", 100, fs)
bp = ellip(4, 1, 40, "band", [80, 120], fs)
print("lowpass sections: {shape(lp.sos)[0]}")    # lowpass sections: 2

print("bandpass sections: {shape(bp.sos)[0]}")   # bandpass sections: 4

output
lowpass sections: 2
bandpass sections: 4

from signal-processing

fs = 1000
ep = ellip(4, 1, 40, "low", 100, fs)
c1 = cheby1(4, 1, "low", 100, fs)
c2 = cheby2(4, 40, "low", 100, fs)
print("ellip stable: {is_stable(ep)}, cheby1 stable: {is_stable(c1)}, cheby2 stable: {is_stable(c2)}")

fir = fir1(6, 100, kind="low", window="hamming", fs=fs)
b = fir.b
a = [1]
n = 0:1:255
t = n / fs
x = sin(2*pi*40*t) + sin(2*pi*300*t)
y  = filter_ba(b, a, x)
y2 = lfilter(b, a, x)               # lfilter is the same builtin under another name

print("filter_ba/lfilter agree: {max(abs(y - y2)) < 1e-12}")

lsq = firls(20, [0, 0.2, 0.3, 1.0], [1, 1, 0, 0])   # low-pass band edges/response

print("firls taps: {length(lsq.b)}")

gd = group_delay(fir, 256)
print("FIR group delay (should be ~order/2=3): {gd[10]}")
print("ellip filter has {length(poles(ep))} poles")

ep.fvtool()   # 2x2 magnitude/phase/group-delay/impulse-response figure

pzplot(ep)    # pole-zero plot with the unit circle and stability verdict

output
ellip stable: true, cheby1 stable: true, cheby2 stable: true
filter_ba/lfilter agree: true
firls taps: 21
FIR group delay (should be ~order/2=3): 3
ellip filter has 4 poles
-80 -60 -40 -20 0 0 150 300 450 Magnitude Response Frequency (Hz) Magnitude (dB) -150 -100 -50 0 50 100 150 0 150 300 450 Phase Response Frequency (Hz) Phase (deg) -250 -200 -150 -100 -50 0 0 150 300 450 Group Delay Frequency (Hz) Delay (samples) -20 -10 0 10 20 0 20 40 60 x=-0.135, y=0.991 x=-0.135, y=-0.991 x=0.57, y=0.821 x=0.57, y=-0.821 Pole-Zero Plot (stable) Real part Imaginary part

from signal-processing

CodeInputOutputDescription
result = ellip(order, ripple_db, atten_db, "band"/"stop", cutoff, fs)
order numberorder: number.
ripple_db numberripple_db/atten_db: numbers (dB).
atten_db numberripple_db/atten_db: numbers (dB).
"band"/"stop" —not documented yet
cutoff number or vectorcutoff: number or length-2 vector (Hz).
fs numberfs: number (Hz).
result vector
A length-2 [low, high] Hz vector.

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

fs = 1000
lp = ellip(4, 1, 40, "low", 100, fs)
bp = ellip(4, 1, 40, "band", [80, 120], fs)
print("lowpass sections: {shape(lp.sos)[0]}")    # lowpass sections: 2

print("bandpass sections: {shape(bp.sos)[0]}")   # bandpass sections: 4

output
lowpass sections: 2
bandpass sections: 4

from signal-processing

fs = 1000
ep = ellip(4, 1, 40, "low", 100, fs)
c1 = cheby1(4, 1, "low", 100, fs)
c2 = cheby2(4, 40, "low", 100, fs)
print("ellip stable: {is_stable(ep)}, cheby1 stable: {is_stable(c1)}, cheby2 stable: {is_stable(c2)}")

fir = fir1(6, 100, kind="low", window="hamming", fs=fs)
b = fir.b
a = [1]
n = 0:1:255
t = n / fs
x = sin(2*pi*40*t) + sin(2*pi*300*t)
y  = filter_ba(b, a, x)
y2 = lfilter(b, a, x)               # lfilter is the same builtin under another name

print("filter_ba/lfilter agree: {max(abs(y - y2)) < 1e-12}")

lsq = firls(20, [0, 0.2, 0.3, 1.0], [1, 1, 0, 0])   # low-pass band edges/response

print("firls taps: {length(lsq.b)}")

gd = group_delay(fir, 256)
print("FIR group delay (should be ~order/2=3): {gd[10]}")
print("ellip filter has {length(poles(ep))} poles")

ep.fvtool()   # 2x2 magnitude/phase/group-delay/impulse-response figure

pzplot(ep)    # pole-zero plot with the unit circle and stability verdict

output
ellip stable: true, cheby1 stable: true, cheby2 stable: true
filter_ba/lfilter agree: true
firls taps: 21
FIR group delay (should be ~order/2=3): 3
ellip filter has 4 poles
-80 -60 -40 -20 0 0 150 300 450 Magnitude Response Frequency (Hz) Magnitude (dB) -150 -100 -50 0 50 100 150 0 150 300 450 Phase Response Frequency (Hz) Phase (deg) -250 -200 -150 -100 -50 0 0 150 300 450 Group Delay Frequency (Hz) Delay (samples) -20 -10 0 10 20 0 20 40 60 x=-0.135, y=0.991 x=-0.135, y=-0.991 x=0.57, y=0.821 x=0.57, y=-0.821 Pole-Zero Plot (stable) Real part Imaginary part

from signal-processing

How it works

ellip(order, ripple_db, atten_db, kind, cutoff, fs) — designs a digital elliptic (Cauer) filter, equiripple in both the passband (within ripple_db dB of 0dB) and the stopband (at least atten_db dB down) simultaneously — the steepest transition band of any of the classical IIR families at a given order, at the cost of ripple in both bands (vs. Butterworth's monotonic, ripple-free response). Same kind/cutoff/fs conventions as butter; cutoff is the point in the transition band where the gain first drops below -ripple_db (matching MATLAB's/SciPy's own ellip(n, Rp, Rs, Wn)), not Butterworth's -3dB point. Model kind "filter", field sos — same shape as butter, so every generic filter function (sosfilt/filtfilt/ freqz/group_delay/fvtool/filter_init/filter_next/ poles/zeros/is_stable/pzplot) works on an ellip design with no changes at all.

From the note above this builtin in the interpreter, where the reasoning was written down as it was built.