diff options
author | Josh Morman <jmorman@gnuradio.org> | 2021-11-24 12:01:00 -0500 |
---|---|---|
committer | mormj <34754695+mormj@users.noreply.github.com> | 2021-11-24 14:41:53 -0500 |
commit | 2ede969ec5f3f6d361814403b7375db5f15ec14d (patch) | |
tree | d963e92732842ee3491da1282dfa09400342c96d /gr-analog/python/analog/fm_emph.py | |
parent | c6f291d57d913708a2517de3c6902425c2c575d3 (diff) |
analog: pep8 formatting
Signed-off-by: Josh Morman <jmorman@gnuradio.org>
Diffstat (limited to 'gr-analog/python/analog/fm_emph.py')
-rw-r--r-- | gr-analog/python/analog/fm_emph.py | 124 |
1 files changed, 63 insertions, 61 deletions
diff --git a/gr-analog/python/analog/fm_emph.py b/gr-analog/python/analog/fm_emph.py index 9c1107bb14..a581bdf2ac 100644 --- a/gr-analog/python/analog/fm_emph.py +++ b/gr-analog/python/analog/fm_emph.py @@ -16,22 +16,22 @@ import cmath class fm_deemph(gr.hier_block2): r""" FM Deemphasis IIR filter - + Args: fs: sampling frequency in Hz (float) tau: Time constant in seconds (75us in US, 50us in EUR) (float) - + An analog deemphasis filter: - + R o------/\/\/\/---+----o | = C | --- - + Has this transfer function: - + 1 1 ---- --- RC tau @@ -39,39 +39,39 @@ class fm_deemph(gr.hier_block2): 1 1 s + ---- s + --- RC tau - + And has its -3 dB response, due to the pole, at - + |H(j w_c)|^2 = 1/2 => s = j w_c = j (1/(RC)) - + Historically, this corner frequency of analog audio deemphasis filters been specified by the RC time constant used, called tau. So w_c = 1/tau. - + FWIW, for standard tau values, some standard analog components would be: tau = 75 us = (50K)(1.5 nF) = (50 ohms)(1.5 uF) tau = 50 us = (50K)(1.0 nF) = (50 ohms)(1.0 uF) - + In specifying tau for this digital deemphasis filter, tau specifies the *digital* corner frequency, w_c, desired. - + The digital deemphasis filter design below, uses the "bilinear transformation" method of designing digital filters: - + 1. Convert digital specifications into the analog domain, by prewarping digital frequency specifications into analog frequencies. - + w_a = (2/T)tan(wT/2) - + 2. Use an analog filter design technique to design the filter. - + 3. Use the bilinear transformation to convert the analog filter design to a digital filter design. - + H(z) = H(s)| s = (2/T)(1-z^-1)/(1+z^-1) - - + + w_ca 1 1 - (-1) z^-1 H(z) = ---- * ----------- * ----------------------- 2 fs -w_ca -w_ca @@ -81,20 +81,21 @@ class fm_deemph(gr.hier_block2): -w_ca 1 - ----- 2 fs - + We use this design technique, because it is an easy way to obtain a filter design with the -6 dB/octave roll-off required of the deemphasis filter. - + Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_, Kluwer Academic Publishers, 1989, pp 201-212 - + Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall, 1996, pp 573-583 """ def __init__(self, fs, tau=75e-6): gr.hier_block2.__init__(self, "fm_deemph", - gr.io_signature(1, 1, gr.sizeof_float), # Input signature + # Input signature + gr.io_signature(1, 1, gr.sizeof_float), gr.io_signature(1, 1, gr.sizeof_float)) # Output signature # Digital corner frequency @@ -111,8 +112,8 @@ class fm_deemph(gr.hier_block2): p1 = (1.0 + k) / (1.0 - k) b0 = -k / (1.0 - k) - btaps = [ b0 * 1.0, b0 * -z1 ] - ataps = [ 1.0, -p1 ] + btaps = [b0 * 1.0, b0 * -z1] + ataps = [1.0, -p1] # Since H(s = 0) = 1.0, then H(z = 1) = 1.0 and has 0 dB gain at DC @@ -120,18 +121,17 @@ class fm_deemph(gr.hier_block2): self.connect(self, deemph, self) - class fm_preemph(gr.hier_block2): r""" FM Preemphasis IIR filter. - + Args: fs: sampling frequency in Hz (float) tau: Time constant in seconds (75us in US, 50us in EUR) (float) - fh: High frequency at which to flatten out (< 0 means default of 0.925*fs/2.0) (float) - + fh: High frequency at which to flatten out (< 0 means default of 0.925*fs/2.0) (float) + An analog preemphasis filter, that flattens out again at the high end: - + C +-----||------+ | | @@ -144,12 +144,12 @@ class fm_preemph(gr.hier_block2): \ | o--------------------------+--------o - + (This fine ASCII rendition is based on Figure 5-15 in "Digital and Analog Communication Systems", Leon W. Couch II) - + Has this transfer function: - + 1 s + --- R1C @@ -157,58 +157,58 @@ class fm_preemph(gr.hier_block2): 1 R1 s + --- (1 + --) R1C R2 - - + + It has a corner due to the numerator, where the rise starts, at - + |Hn(j w_cl)|^2 = 2*|Hn(0)|^2 => s = j w_cl = j (1/(R1C)) - + It has a corner due to the denominator, where it levels off again, at - + |Hn(j w_ch)|^2 = 1/2*|Hd(0)|^2 => s = j w_ch = j (1/(R1C) * (1 + R1/R2)) - + Historically, the corner frequency of analog audio preemphasis filters been specified by the R1C time constant used, called tau. - + So w_cl = 1/tau = 1/R1C; f_cl = 1/(2*pi*tau) = 1/(2*pi*R1*C) w_ch = 1/tau2 = (1+R1/R2)/R1C; f_ch = 1/(2*pi*tau2) = (1+R1/R2)/(2*pi*R1*C) - + and note f_ch = f_cl * (1 + R1/R2). - + For broadcast FM audio, tau is 75us in the United States and 50us in Europe. f_ch should be higher than our digital audio bandwidth. - + The Bode plot looks like this: - - + + /---------------- / / <-- slope = 20dB/decade / -------------/ f_cl f_ch - + In specifying tau for this digital preemphasis filter, tau specifies the *digital* corner frequency, w_cl, desired. - + The digital preemphasis filter design below, uses the "bilinear transformation" method of designing digital filters: - + 1. Convert digital specifications into the analog domain, by prewarping digital frequency specifications into analog frequencies. - + w_a = (2/T)tan(wT/2) - + 2. Use an analog filter design technique to design the filter. - + 3. Use the bilinear transformation to convert the analog filter design to a digital filter design. - + H(z) = H(s)| s = (2/T)(1-z^-1)/(1+z^-1) - - + + -w_cla 1 + ------ 2 fs @@ -224,19 +224,21 @@ class fm_preemph(gr.hier_block2): -w_cha 1 - ------ 2 fs - + We use this design technique, because it is an easy way to obtain a filter design with the 6 dB/octave rise required of the premphasis filter. - + Jackson, Leland B., _Digital_Filters_and_Signal_Processing_Second_Edition_, Kluwer Academic Publishers, 1989, pp 201-212 - + Orfanidis, Sophocles J., _Introduction_to_Signal_Processing_, Prentice Hall, 1996, pp 573-583 """ + def __init__(self, fs, tau=75e-6, fh=-1.0): gr.hier_block2.__init__(self, "fm_preemph", - gr.io_signature(1, 1, gr.sizeof_float), # Input signature + # Input signature + gr.io_signature(1, 1, gr.sizeof_float), gr.io_signature(1, 1, gr.sizeof_float)) # Output signature # Set fh to something sensible, if needed. @@ -244,7 +246,7 @@ class fm_preemph(gr.hier_block2): # at z = -1.0 or z = 1.0 respectively. That makes the filter unstable # and useless. if fh <= 0.0 or fh >= fs / 2.0: - fh = 0.925 * fs/2.0 + fh = 0.925 * fs / 2.0 # Digital corner frequencies w_cl = 1.0 / tau @@ -268,11 +270,11 @@ class fm_preemph(gr.hier_block2): # That isn't what users are going to expect, so adjust with a # gain, g, so that H(z = 1) = 1.0 for 0 dB gain at DC. w_0dB = 2.0 * math.pi * 0.0 - g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \ + g = abs(1.0 - p1 * cmath.rect(1.0, -w_0dB)) \ / (b0 * abs(1.0 - z1 * cmath.rect(1.0, -w_0dB))) - btaps = [ g * b0 * 1.0, g * b0 * -z1 ] - ataps = [ 1.0, -p1 ] + btaps = [g * b0 * 1.0, g * b0 * -z1] + ataps = [1.0, -p1] preemph = filter.iir_filter_ffd(btaps, ataps, False) self.connect(self, preemph, self) |