コード例 #1
0
def annotate_magnitude(ax, f, H, f0, string, **kw):
    H0 = H[np.argmin(np.abs(f - f0))]

    p0 = ax.transData.transform_point((f[0], db(H[0])))
    p1 = ax.transData.transform_point((f[-1], db(H[-1])))
    dx, dy = p1 - p0
    angle = np.rad2deg(np.arctan2(dy, dx))
    ax.text(f0, db(H0), string, rotation=angle, rotation_mode='anchor', **kw)
コード例 #2
0
def plot_crest_factor(ax, dir_crest_factor, stimuli, labels, phase_angles,
                      colors, xticks):
    for i, stm in enumerate(stimuli):
        phi, C = np.loadtxt(dir_crest_factor + stm + '.txt')
        phi -= np.pi  # shift angle by -np.pi
        color = colors(i * 0.25)
        label = labels[i]
        Cdiff = util.db(C[-90] / C[0])
        ax.plot(np.rad2deg(phi), util.db(C), c=color, label=label)
        ax.plot(-90, util.db(C[-90]), c=color, marker='o')
        color = (color if i!=3 else 'k')
        ax.text(-90, util.db(C[-90]) + 0.5, '${:+0.1f}$ dB'.format(Cdiff),
                color=color, va='bottom', ha='center')
        ax.text(100, util.db(C[100]) + 0.3, label,
                color=color, va='bottom', ha='center')
        if re.match(re.compile('square.'), stm):
            Cdiff = util.db(C[-45] / C[0])
            ax.plot(-45, util.db(C[-45]), c=color, marker='o')
            ax.text(-45, util.db(C[-45]) + 0.5, '${:+0.1f}$ dB'.format(Cdiff),
                    color=color, va='bottom', ha='left')
    ax.set_xticks(xticks)
    ax.set_xlim(xticks[0], xticks[-1])
    ax.set_xlabel(r'Phase Shift $\varphi$ / $\degree$')
    ax.set_ylabel('Crest Factor (CF) / dB')
    ax.grid(True, color='lightgray')

    color_legend = [0.5, 0.5, 0.5]
    ax.plot([-145, -125], [21, 21], c=color_legend)
    ax.plot(-135, 21, c=color_legend, marker='o')
    ax.text(-135, 21.5, 'CF change \n relative to $0\\degree$',
            color='k', va='bottom', ha='center')
コード例 #3
0
def plot_magnitude(ax, fmin, fmax, H_mag, color):
    ax.hlines(db(H_mag), fmin, fmax, colors=color)
    ax.set_yticks([-10, 0, 10])
    ax.set_xlim(fmin, fmax)
    ax.set_ylim(-12, 12)
    ax.set_xscale('log')
    ax.set_xlabel('$f$ / Hz')
    ax.set_ylabel('Magnitude / dB')
    ax.grid(True)
    # annotation
    flabel = np.sqrt(fmin * fmax)
    ax.text(flabel,
            0,
            'all-pass',
            fontsize=14,
            ha='center',
            va='bottom',
            color='k')
コード例 #4
0
# Plots
Glim = -0.21, 0.21
philim = -3, 47
wlim = wmin, wmax
wticks = 2**(np.arange(
    np.ceil(np.log2(w)[0] / 2) * 2,
    np.floor(np.log2(w[-1]) / 2) * 2 + 2, 2))
kw = {'lw': 2, 'alpha': 1, 'basex': 2}
colors = cm.get_cmap('Blues')

# frequency response
fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.25})
for n, (biquad_per_octave, H_n) in enumerate(zip(Biquad_per_octave, H)):
    col = colors((n + 2) / (len(H) + 2))
    ax[0].semilogx(w,
                   db(H_n) - Hmag,
                   c=col,
                   **kw,
                   label='{:0.0f}'.format(biquad_per_octave))

# Zeros and poles
kw_p = dict(c='k', marker='x', ls='none')
kw_z = dict(marker='o', mew=0.75, ls='none', mfc='none')
for n, (zpk) in enumerate(zpks):
    z, p, _ = zpk
    num_pole, num_zero = len(z), len(p)
    voffset = -n
    col = colors((n + 2) / (len(H) + 2))
    ax[1].plot(np.abs(p), voffset * np.ones(num_pole), **kw_p)
    ax[1].plot(np.abs(z), voffset * np.ones(num_zero), c=col, **kw_z)
ax[1].set_xscale('log', basex=2)
コード例 #5
0
def plot_magnitude(ax, f, H, **kw):
    ax.semilogx(f, db(H), **kw)
コード例 #6
0
f_control[::2] = f_command
f_control[1::2] = np.sqrt(f_command[:-1] * f_command[1:])
w_command = 2 * np.pi * f_command / fs
w_control = 2 * np.pi * f_control / fs
bandwidth = 1.5 * w_command
bandwidth[6] *= 0.997
bandwidth[7] *= 0.985
bandwidth[8] *= 0.929
bandwidth[9] *= 0.433

gain_factor = 0.29
gain_proto = np.array(
    [13.8, 14.5, 14.5, 14.6, 14.5, 14.5, 14.6, 14.6, 14.5, 13.6])

# 3dB per octave
slope = db(np.sqrt(2))
BWd = 6
fh = 2000
fl = fh * 2**(-BWd)
f_center = fh * 2**(-BWd / 2)
w_center = 2 * np.pi * f_center / fs
gmin, gmax = -9, 9
gain_command = np.clip(np.log2(w_command / w_center) * slope, gmin, gmax)
H_desired = np.clip(np.log2(f / f_center) * slope, gmin, gmax)
b_opt, a_opt = optimized_peq_seg(gain_command, gain_proto, gain_factor,
                                 w_command, w_control, bandwidth)
sos = np.vstack([b_opt, a_opt]).T
H = sosfreqz(sos, worN=f, fs=fs)[1]

# Plots
kw = dict(c='peru', lw=3, alpha=0.75)
コード例 #7
0
sos_zdomain = zpk2sos(*zpk)
H = sosfreqz(sos_zdomain, worN=f, fs=fs)[1]
h = sosfilt(sos_zdomain, xin)

# Plots
flim = fmin, fmax
fticks = fc * 2.**np.arange(-8, 4, 2)
fticklabels = ['7.8', '31.3', '125', '500', '2k', '8k']
fticks = 1000 * 2.**np.arange(-6, 6, 2)
fticklabels = ['15.6', '62.5', '250', '1k', '4k', '16k']
kw = dict(c='C0', lw=2, alpha=1)

fig, ax = plt.subplots(figsize=(13, 3), ncols=3, gridspec_kw={'wspace': 0.25})

# frequency response
ax[0].semilogx(f, db(H), **kw)
ax[1].semilogx(f, np.angle(H, deg=True), **kw)

# desired response
fl, fh = fc * 2**(-BWd), fc
kw_des = dict(c='k', lw=2, ls=':')
Hmag = np.clip(np.log2(f / fc) * slope, G, 0)
Hphase = 90 * slope / db(2)
ax[0].semilogx(f, Hmag, **kw_des)
ax[1].semilogx((fl, fh), (Hphase, Hphase), **kw_des)
ax[1].text(250, Hphase - 1, '45 degree', va='top', ha='center', fontsize=10)

# desired bandwidth
kw_bw = dict(color='lightgray', alpha=0.5)
fl, fh = fc * 2**(-BWd), fc
Gmin, Gmax = ax[0].get_ylim()
コード例 #8
0
for i, fo in enumerate(Filter_orders):
    _, h = util.constant_phase_shifter(fo, phase_varN, beta=beta)
    _, H = freqz(h, 1, f, fs=fs)
    gd = fo / 2 / fs
    H *= np.exp(1j * omega * gd)  # compensate group delay
    phase = np.unwrap(np.mod(np.angle(H), 2 * np.pi))
    phase_deg = np.rad2deg(phase)

    vshift = -idx_varN * voffset_tf
    color = colors[idx_varN]
    opacity = 1.2**(-i)

    # Frequency responses for varying filter order
    ax[0].semilogx(f,
                   vshift + db(H),
                   color=color,
                   lw=1.5,
                   ls=':',
                   alpha=opacity)
    ax[1].semilogx(f, phase_deg, color=color, lw=1.5, ls=':', alpha=opacity)

    # Labels: filter order
    ax[0].text(4**(-i) * 30,
               -21.5,
               r'$N={:0.0f}$'.format(fo + 1),
               rotation=33,
               va='center',
               ha='left',
               fontsize=8,
               color='k')
コード例 #9
0
# Plots
col = 'C0'

fig, ax = plt.subplots(figsize=(12, 4), ncols=2, gridspec_kw={'wspace': 0.33})

# impulse response and decay curve
ax[0].stem(n, h, markerfmt=col + 'o', linefmt=col, basefmt=col, label='$h[n]$')
ax[0].plot(n_dense_neg, envelope_neg, 'k--', zorder=0, label=r'$2 / \pi n$')
ax[0].plot(n_dense_pos, envelope_pos, 'k--', zorder=0)
ax[0].set_ylim(-0.8, 0.8)
ax[0].set_xlabel('$n$ / sample')
ax[0].legend()

# decay curve in log-log axes with quantization errors
ax[1].semilogx(sample, util.db(envelope), 'k--', label=r'$|2 / \pi n|$')
ax[1].hlines(util.db(E16), nmin, nmax, colors='C1', zorder=0)
ax[1].hlines(util.db(E24), nmin, nmax, colors='C3', zorder=0)
ax[1].grid(color='lightgray')
ax[1].set_xlabel('$n$ / sample')
ax[1].set_ylabel('Amplitude / dB')
ax[1].set_xlim(nmin, nmax)
p0 = ax[1].transData.transform_point((sample[0], util.db(envelope[0])))
p1 = ax[1].transData.transform_point((sample[-1], util.db(envelope[-1])))
dx, dy = p1 - p0
angle = np.rad2deg(np.arctan2(dy, dx))
ax[1].text(1000, -60, r'$\frac{2}{\pi n}$', rotation=angle, fontsize=25)
ax[1].text(100, util.db(E16), r'16-bit noise floor', va='bottom')
ax[1].text(100, util.db(E24), r'24-bit noise floor', va='bottom')

# secondary x-axis in seconds
コード例 #10
0
# %%
from datetime import datetime, date, time

from numpy import TooHardError
from util import file, stg, tool, db, indicator as ind

import matplotlib.pyplot as plt

import pandas as pd
from plotly.offline import iplot, init_notebook_mode
import plotly.graph_objs as go

import talib

sql = "SELECT StockID, TradeDate, Open, High, Low, Close, Volume FROM dailyholc WHERE StockID in ('2330', '2303')"
stkdailyDF = db().selectDatatoDF(sql_statment = sql)
stkdailyDF = ind(stkdailyDF).addMFIvalueToDF()
# %%


stkdailyDF = ind(stkdailyDF).getSignalByIndicator(inds = ["MACD"])


stkdailyDF = ind(stkdailyDF).addMAvalueToDF()
stkdailyDF = ind(stkdailyDF).addSARvalueToDF(acc = 0.02, max = 0.2)   # Default acc = 0.02, max = 0.2
stkdailyDF = ind(stkdailyDF).addSARvalueToDF(acc = 0.03, max = 0.3)   # Default acc = 0.02, max = 0.2
stkdailyDF = ind(stkdailyDF).addBBANDvalueToDF()
stkdailyDF = ind(stkdailyDF).addMAXMINvalueToDF()
stkdailyDF = ind(stkdailyDF).getSignalByIndicator(inds = ["SMA", "SAR", "MAXMIN", "BBands"])

# %%
コード例 #11
0
Glim = -9.5, 9.5
philim = -21, 21
wlim = wmin, wmax
wticks = 2**(np.arange(np.ceil(np.log2(w)[0]/2)*2,
                       np.floor(np.log2(w[-1])/2)*2 + 2, 2))
kw_pos = dict(lw=1.5, c='C3', alpha=0.5, basex=2)
kw_neg = dict(lw=1.5, c='C0', alpha=1, basex=2)

fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.25})

# frequency response
w_mag, w_ph = 2**-9, 2**-3
for n, (Gd, H_n) in enumerate(zip(Desired_gain, H)):
    kw = kw_pos if Gd > 0 else kw_neg
#    col = 'C3' if Gd > 0 else 'C0'
    ax[0].semilogx(w, db(H_n), **kw)
    ax[1].semilogx(w, np.rad2deg(np.angle(H_n)), **kw)
    label = '{:+0.0f} dB'.format(Gd)
    phi = nearest_value(w_ph, w, np.angle(H_n, deg=True))
    ax[0].annotate(label, (w_mag, Gd), ha='left', va='bottom', fontsize=10)
    ax[1].annotate(label, (w_ph, phi), ha='center', va='bottom', fontsize=10)

# decorations
ax[0].set_xlim(wmin, wmax)
ax[0].set_ylim(Glim)
ax[0].set_xticks(wticks)
ax[0].grid(True)
ax[0].yaxis.set_major_locator(MultipleLocator(3))
ax[0].yaxis.set_minor_locator(MultipleLocator(1))
ax[0].set_xlabel(r'$\omega$ / $\omega_\textrm{\footnotesize u}$')
ax[0].set_ylabel('Level in dB')
コード例 #12
0
    sos = low_shelving_2nd_cascade(w0, Gb, num_biquad, biquad_per_octave)
    H[n] = sosfreqs(sos, worN=w)[1]

# Plots
wlim = wmin, wmax
wticks = 2**(np.arange(
    np.ceil(np.log2(w)[0] / 2) * 2,
    np.floor(np.log2(w[-1]) / 2) * 2 + 2, 2))
kw = {'lw': 1.5, 'alpha': 0.75, 'basex': 2}

fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.25})

# frequency response
for n, (BWd, H_n) in enumerate(zip(Desired_bandwidth, H)):
    col = 'C3' if Gain[n] > 0 else 'C0'
    ax[0].semilogx(w, db(H_n), c=col, **kw)
    ax[1].semilogx(w, np.angle(H_n, deg=True), c=col, **kw)

# desired response
Hmag = np.clip(np.log2(w / w0) * slope, G, 0)
Hphase = 90 * slope / db(2)
ax[0].semilogx(w, Hmag, 'k:', **kw)
ax[1].semilogx((wmin, wmax), (Hphase, Hphase), 'k:', **kw)

# decorations
ax[0].set_xlim(wmin, wmax)
ax[0].set_xticks(wticks)
ax[0].yaxis.set_major_locator(MultipleLocator(3))
ax[0].yaxis.set_minor_locator(MultipleLocator(1))
ax[0].grid(True)
ax[0].set_xlabel(r'$\omega$ / $\omega_\textrm{\footnotesize u}$')
コード例 #13
0
x_Mp = util.periodic_signal(x_1p, long_repetition)
y_fir = np.zeros((len(phase_angles), N))  # selection of long signal
Y_fir = np.zeros((len(phase_angles), N // 2 + 1), dtype='complex128')
for i, phi in enumerate(phase_angles):
    h = util.constant_phase_shifter(filter_order, phi, beta=8.6)[1]
    y = util.acausal_filter(x_Mp, h)[n_start:n_stop]
    y_fir[i] = y
    Y_fir[i] = np.fft.rfft(y)

# I. Float64

# Waveforms - DFT vs FIR methods
t = np.arange(len(y_fir[0])) / fs * 1000
fig, ax = plt.subplots(figsize=(12, 5), ncols=3, sharey=True)
for i, (phi, yd, yf) in enumerate(zip(phase_angles, y_dft, y_fir)):
    ax[i].plot(t, util.db(yd), c='lightgray', label='DFT')
    ax[i].plot(t, util.db(yd - yf), label='diff')
    ax[i].set_xlabel('$t$ / ms')
    ax[i].set_title('{:0.0f}'.format(np.rad2deg(phi)))
    ax[i].grid(True)
ax[0].set_ylabel('Amplitude / dB')
ax[0].legend(loc='upper right')
fig.suptitle('[FLOAT] Waveforms - DFT vs FIR')

# Spectra - DFT vs FIR methods
Nrfft = N // 2 + 1
f = np.arange(Nrfft) / N * fs
fig, ax = plt.subplots(figsize=(12, 5), ncols=3, sharey=True)
for i, (phi, Yd, Yf) in enumerate(zip(phase_angles, Y_dft, Y_fir)):
    ax[i].plot(f, util.db(Yd), 'lightgray', label='DFT')
    ax[i].plot(f, util.db(Yd - Yf), label='diff')
コード例 #14
0
                       sharex=True,
                       sharey=True)

for i, stml in enumerate(stimuli):
    s0 = sf.read(dir_stimuli + stml + '_phi000.wav')[0][:, 0]
    try:
        sp = sf.read(dir_stimuli + stml + '_phi270.wav')[0][:, 0]
    except:
        sp = sf.read(dir_stimuli + stml + '_phi315.wav')[0][:, 0]
    S0 = np.fft.rfft(s0)
    Sp = np.fft.rfft(sp)
    Smax = np.max(np.abs(S0))
    N = len(s0)
    f = fs * np.arange(N // 2 + 1) / N
    axi = ax.flat[i]
    axi.plot(f, db(S0 / Smax), 'C0', lw=1, label='Original Signal')
    axi.plot(f,
             db((np.abs(S0) - np.abs(Sp)) / Smax),
             'C3',
             lw=2,
             label='Magnitude Deviation')
    axi.set_xlim(-5, 120)
    axi.set_ylim(-150, 10)
    axi.set_title(a_label[i])
    axi.grid(True)
ax[1, 0].set_xlim()
ax[1, 0].legend(loc='upper left')
for axi in ax[1]:
    axi.set_xlabel('$f$ / Hz')
for axi in ax[:, 0]:
    axi.set_ylabel('Magnitude / dB')
コード例 #15
0
wticks = 2**(np.arange(
    np.ceil(np.log2(w)[0] / 2) * 2,
    np.floor(np.log2(w[-1]) / 2) * 2 + 2, 2))
kw = {'lw': 2, 'alpha': 1, 'basex': 2}
labels = [
    '{:0.0f}'.format(biquad_per_octave)
    for biquad_per_octave in Biquad_per_octave
]
colors = cm.get_cmap('Blues')

# frequency response
fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.25})
for n, (biquad_per_octave, H_n) in enumerate(zip(Biquad_per_octave, H)):
    col = colors((n + 3) / (len(H) + 3))
    ax[0].semilogx(w,
                   db(H_n),
                   c=col,
                   **kw,
                   label='{:0.0f}'.format(biquad_per_octave))
    ax[1].semilogx(w, np.angle(H_n, deg=True), c=col, **kw)

# desired response
wl, wh = w0 * 2**(-BWd), w0
Hmag = np.clip(np.log2(w / w0) * slope, G, 0)
Hphase = 90 * slope / db(2)
ax[0].semilogx(w, Hmag, 'k:', **kw)
ax[1].semilogx((wl, w0), (Hphase, Hphase), 'k:', **kw)
ax[1].text(np.sqrt(wl * w0),
           Hphase - 1,
           '{:0.0f} deg'.format(Hphase),
           fontsize=10,
コード例 #16
0
ファイル: GetHOLCbyStock.py プロジェクト: MenghsuanLiu/Python
# %%
from datetime import date, timedelta
import pandas as pd
# from datetime import date, timedelta, datetime
from util import con, cfg, db, tool

# day = date.today().strftime("%Y%m%d")
# minDF = db().selectDatatoDF(sql_statment = f"SELECT * FROM dailyminsholc WHERE TradeDate = {day}")

day = date.today().strftime("%Y-%m-%d")
# day = "2021-10-15"
api = con().LoginToServerForStock(simulate=False)
tb = cfg().getValueByConfigFile(key="tb_mins")
# %%

stock_lst = tool.DFcolumnToList(db().selectDatatoDF(
    cfg().getValueByConfigFile(key="tb_basic")),
                                colname="StockID")

DFtoDBmin = pd.DataFrame()
for id in stock_lst:
    stkDF = con(api).getKarData(stkid=id, sdate=day, edate=day)
    stkDF = stkDF.filter(items=[
        "StockID", "TradeDate", "TradeTime", "Open", "High", "Low", "Close",
        "Volume"
    ])
    print(id)

    db().updateDFtoDB(stkDF, tb_name=tb)

# %%
コード例 #17
0
H = sosfreqs(sos, worN=w)[1]

# Plots
Glim = -9.5, 1
wlim = wmin, wmax
wticks = 2**(np.arange(
    np.ceil(np.log2(w)[0] / 2) * 2,
    np.floor(np.log2(w[-1]) / 2) * 2 + 2, 2))
kw = dict(lw=2, alpha=1, basex=2)
kw_dotted = dict(color='gray', linestyle=':', linewidth=1)
kw_artist = dict(edgecolor='gray', linestyle=':', linewidth=1)
colors = cm.get_cmap('Blues')

# frequency response
fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.1})
ax[0].semilogx(w, db(H_biquads.T), c='gray', **kw, zorder=2)
ax[0].semilogx(w, Hmag, 'k:', **kw)
ax[0].semilogx(w, db(H), c='C0', **kw, zorder=3)

ax[1].plot([-1, 0], [1, 0], 'C7:', lw=1)

# Pole zero plot
kw_z = dict(c='C0', marker='o', ms=9, ls='none', mew=1, mfc='none', alpha=1)
kw_p = dict(c='k', marker='x', ms=9, ls='none', mew=1)
kw_dot = dict(marker='.', ms=10)
ylim = ax[0].get_ylim()
for n, sosi in enumerate(sos):
    z, p, _ = sos2zpk(sosi[np.newaxis, :])
    z, p = z[0], p[0]
    wc = np.abs(np.sqrt(z * p))
コード例 #18
0
    H[n] = sosfreqs(sos, worN=w)[1]
    shelving_filters.append(sos)

# Plots
wlim = wmin, wmax
wticks = 2**(np.arange(np.ceil(np.log2(w)[0]/2)*2,
                       np.floor(np.log2(w[-1])/2)*2 + 2, 2))
kw = {'lw': 2, 'alpha': 1, 'basex': 2}
colors = cm.get_cmap('Blues')

fig, ax = plt.subplots(figsize=(10, 4), ncols=2, gridspec_kw={'wspace': 0.25})

# frequency response
for n, H_n in enumerate(H):
    col = colors((n + 3) / (len(H) + 3))
    ax[0].semilogx(w, db(H_n), c=col, **kw)
    ax[1].semilogx(w, np.rad2deg(np.unwrap(np.angle(H_n))), c=col, **kw)

# desired response
wl, wh = w0 * 2**(-BWd), w0
Hmag = np.clip(np.log2(w/w0) * slope, G, 0)
Hphase = np.round(90 * slope / db(2), decimals=0)
ax[0].semilogx(w, Hmag, 'k:', **kw)
ax[1].semilogx((wl, w0), (Hphase, Hphase), 'k:', **kw)
ax[1].text(np.sqrt(wl * w0), Hphase - 10, '{:0.0f} deg'.format(Hphase),
           fontsize=10, ha='center', va='top')

# decorations
ax[0].set_xlim(wmin, wmax)
ax[0].set_xticks(wticks)
ax[0].grid(True)
コード例 #19
0
wticks = 2**(np.arange(
    np.ceil(np.log2(w)[0] / 4) * 4,
    np.floor(np.log2(w[-1]) / 4) * 4 + 4, 4))
kw = dict(linewidth=2, alpha=1, basex=2)
kw_z = dict(c='C0', marker='o', ms=9, ls='none', mew=1, mfc='none', alpha=1)
kw_p = dict(c='k', marker='x', ms=9, ls='none', mew=1)
kw_artist = dict(edgecolor='gray', linestyle=':', linewidth=1)
colors = [
    cm.get_cmap('Oranges')(x)[:3]
    for x in np.linspace(0.33, 1, num=max_order, endpoint=False)
]

fig, ax = plt.subplots(figsize=(13, 3), ncols=3, gridspec_kw={'wspace': 0.3})

for Hi, ci in zip(H, colors):
    ax[0].semilogx(w / wc, db(Hi), c=ci, **kw)
    ax[1].semilogx(w / wc, np.angle(Hi, deg=True), c=ci, **kw)
ax[0].set_xlim(wlim)
ax[0].set_xticks(wticks)
ax[0].grid(True)
ax[0].set_xlabel(r'$\omega$ / $\omega_\textrm{\footnotesize c}$')
ax[0].set_ylabel('Level in dB')
ax[0].yaxis.set_major_locator(MultipleLocator(3))
ax[0].yaxis.set_minor_locator(MultipleLocator(1))
ax[0].legend(orders, title='Filter order', facecolor='w')

ax[1].set_xlim(wlim)
ax[1].set_xticks(wticks)
ax[1].grid(True)
ax[1].set_xlabel(r'$\omega$ / $\omega_\textrm{\footnotesize c}$')
ax[1].set_ylabel('Phase in degree')