/// script dependencies = [ "matplotlib", "scipy", ] ///

8"""
9Generate a FIR low-pass filter using the Remez exchange algorithm, and plot the frequency response.
10"""
12import argparse
13from math import pi
14
15import matplotlib.pyplot as plt
16import numpy as np
17from scipy.signal import freqz, remez
18
19
20def main():
21    args = parse_args()
22
23    weight_pb = 1 - 10 ** (-args.pbr / 20)
24    weight_sb = 10 ** (-args.sba / 20)
25    coefficients = remez(
26        args.n,
27        [0, args.fp, args.fe, args.fs / 2],
28        [1, 0],
29        weight=[weight_pb, weight_sb],
30        fs=args.fs,
31    )
32    print([float(coeff) for coeff in coefficients])
33
34    w, h = freqz(coefficients, worN=1 << 20)
35
36    figure = plt.figure()
37    axes = figure.add_subplot(
38        title="Filter Frequency Response",
39        xlabel="Frequency (Hz)",
40        ylabel="Gain (dB)",
41        xlim=(0, 40000),
42        ylim=(-80, 20),
43    )
44    axes.grid(visible=True)
45
46    axes.plot(w * (args.fs / 2) / pi, 20 * np.log10(abs(h)))
47    axes.plot(2 * [24000], [-100, 100])
48    axes.plot([0, args.fs], 2 * [-3])
49
50    plt.show(block=True)
51
52
53def parse_args():
54    arg_parser = argparse.ArgumentParser(
55        description="Generate a FIR low-pass filter using the Remez exchange algorithm"
56    )
57    arg_parser.add_argument(
58        "-fs", type=float, required=True, help="Source frequency (Hz)"
59    )
60    arg_parser.add_argument("-n", type=int, required=True, help="Number of taps")
61    arg_parser.add_argument(
62        "-fp",
63        default=16000,
64        type=float,
65        required=False,
66        help="Transition band start frequency (Hz) (default=16000)",
67    )
68    arg_parser.add_argument(
69        "-fe",
70        default=24000,
71        type=float,
72        required=False,
73        help="Stopband edge frequency (Hz) (default=24000)",
74    )
75    arg_parser.add_argument(
76        "-pbr",
77        default=0.1,
78        type=float,
79        required=False,
80        help="Desired passband ripple (dB) (default=0.1)",
81    )
82    arg_parser.add_argument(
83        "-sba",
84        default=60,
85        type=float,
86        required=False,
87        help="Desired stopband attenuation (dB) (default=60)",
88    )
89    return arg_parser.parse_args()
90
91
92if __name__ == "__main__":
93    main()