{"id":368,"date":"2003-07-03T09:07:29","date_gmt":"2003-07-03T06:07:29","guid":{"rendered":"https:\/\/yehar.com\/blog\/?p=368"},"modified":"2020-05-11T20:35:38","modified_gmt":"2020-05-11T17:35:38","slug":"hilbert","status":"publish","type":"post","link":"https:\/\/yehar.com\/blog\/?p=368","title":{"rendered":"Hilbert transform"},"content":{"rendered":"<p>This is probably the most efficient structure for implementing a Hilbert transform. Actually, it's not a Hilbert transform, but two all-pass IIR filters whose phase difference is approximately 90 degrees over a range of frequencies symmetric around Nyquist\/2. Laurent de Soras uses these kind of filters in his <a href=\"http:\/\/ldesoras.free.fr\/prod.html#src_hiir\">HIIR<\/a> resampling library, which also has functions for coefficient calculation. <span style=\"color: #000000;\">This note is available in Maple format: <a href=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert.mws\">hilbert.mws<\/a><\/span> UPDATE 2019-06-28: See my <a href=\"https:\/\/dsp.stackexchange.com\/a\/59157\/15347\">Signal Processing Stack Exchange post<\/a> for <b>coefficient calculation<\/b> using HIIR.<\/p>\n<p><a name=\"MapleAutoBookmark1\"><\/a><\/p>\n<h2>90 degree phase difference IIR allpass pair<\/h2>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">The basic building block is:<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">H_sect := (z, a) -&gt; (a^2 - z^(-2)) \/ (1 - a^2 * z^(-2));<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert1.gif\" alt=\"[Maple Math]\" width=\"179\" height=\"122\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Equation 1. Allpass section taking one multiplication when a^2 is a known coefficient.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Each such allpass section has poles located on the real axis at <\/span> <em><span style=\"color: #000000;\">a<\/span><\/em> <span style=\"color: #000000;\"> and -<\/span> <em><span style=\"color: #000000;\">a<\/span><\/em> <span style=\"color: #000000;\">, and zeros at 1\/<\/span> <em><span style=\"color: #000000;\">a<\/span><\/em> <span style=\"color: #000000;\"> and -1\/<\/span> <em><span style=\"color: #000000;\">a<\/span><\/em> <span style=\"color: #000000;\">.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">We construct two allpass filters from such sections:<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">H_1 := z -&gt; H_sect(z, 0.6923878)*H_sect(z, 0.9360654322959)*H_sect(z, 0.9882295226860)*H_sect(z, 0.9987488452737)*z^(-1);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert2.gif\" alt=\"[Maple Math]\" width=\"692\" height=\"45\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Equation 2. First allpass filter, delayed by one sample.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">H_2 := z -&gt; H_sect(z, 0.4021921162426)*H_sect(z, 0.8561710882420)*H_sect(z, 0.9722909545651)*H_sect(z, 0.9952884791278);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert3.gif\" alt=\"[Maple Math]\" width=\"731\" height=\"20\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Equation 3. Second allpass filter, has 90 (+- 0.7) degrees relative phase to first filter over a long range of frequencies.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot({argument(H_1(exp(I*freq))), argument(H_2(exp(I*freq)))}, freq=0..Pi, phase = -Pi..Pi);<\/span><\/strong><\/p>\n<p align=\"center\"><a href=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert4.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-369\" title=\"hilbert4\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert4.gif\" alt=\"\" width=\"453\" height=\"453\" srcset=\"https:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert4.gif 453w, https:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert4-150x150.gif 150w, https:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert4-300x300.gif 300w\" sizes=\"(max-width: 453px) 85vw, 453px\" \/><\/a><a name=\"MapleAutoBookmark1\"><\/a><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 1. Phases of H_1 (green) and H_2 (red).<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot(argument(H_2(exp(I*freq))\/H_1(exp(I*freq))), freq=0..Pi, phase = -Pi..Pi);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert5.gif\" alt=\"\" width=\"453\" height=\"453\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 2. Phase difference of H_2 and H_1.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot({argument(H_2(exp(I*freq))\/H_1(exp(I*freq))), Pi\/2}, freq=0..Pi, phase = Pi\/2*0.95..Pi\/2*1.05);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert6.gif\" alt=\"\" width=\"453\" height=\"453\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 3. Phase difference of H_2 and H_1 (green), detail near 90 degrees (red).<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot(argument(H_2(exp(I*freq))\/H_1(exp(I*freq))), freq=-0.005..0.005, phase = -Pi..Pi);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert7.gif\" alt=\"\" width=\"453\" height=\"453\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 4. Phase difference of H_2 and H_1, detail near 0 Hz.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">You can use the 90 degree phase difference of the filters as such, or you can construct a complex filter and analyze its properties:<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">H := z -&gt; 0.5*(H_2(z)+I*H_1(z));<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert8.gif\" alt=\"[Maple Math]\" width=\"206\" height=\"20\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Equation 4. Combined complex filter that will remove negative frequencies.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot(20*log10(abs(H(exp(I*freq)))), freq=-Pi..Pi, dB=-60..1, axes=boxed);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert9.gif\" alt=\"\" width=\"386\" height=\"286\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 5. Frequency response of filter in Equation 4.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot(20*log10(abs(H(exp(I*freq), 0.4))), freq=-0.01..0.01, dB=-60..1);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert10.gif\" alt=\"\" width=\"386\" height=\"286\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 6. Frequency response of filter in Equation 4, transition band detail<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot(20*log10(abs(H(exp(I*freq), 0.4))), freq=0..0.01, dB=-0.0005..0.0005);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert11.gif\" alt=\"\" width=\"453\" height=\"453\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 7. Frequency response of filter in Equation 4, transition band - passband detail.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <tt>&gt; <\/tt> <strong><span style=\"color: #ff0000;\">plot(20*log10(abs(H(exp(I*freq)))), freq=0..Pi, magnitude=-0.0005..0.0005);<\/span><\/strong><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/yehar.com\/blog\/wp-content\/uploads\/2009\/09\/hilbert12.gif\" alt=\"\" width=\"386\" height=\"286\" \/><\/p>\n<p align=\"center\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Figure 8. Frequency response of filter in Equation 4, passband detail<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Transition bandwidth is 0.002 times the width of passband, stopband is attenuated down to -44 dB and passband ripple is 0.0002 dB.<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a> <span style=\"color: #000000;\">Plenty cheap for a total of 8 multiplications (plus final scaling by 0.5)!<\/span><\/p>\n<p align=\"left\"><a name=\"MapleAutoBookmark1\"><\/a><span style=\"color: #000000;\">The coefficients were found using a generic evolutionary algorithm. I believe that it would be possible to design coefficients for this filter structure using the software by Artur Krukowski, which finds coefficients for halfband filters: <\/span><span style=\"color: #000000;\"><a href=\"http:\/\/www.cmsa.wmin.ac.uk\/~artur\/Poly.html\">http:\/\/www.cmsa.wmin.ac.uk\/~artur\/Poly.html<\/a><\/span><\/p>\n<p>Update 2004\/01\/13<\/p>\n<p>Ben Saucer has succesfully implemented this filter pair to be used in his audio effect. Here are some useful (edited) excerpts from our e-mail correspondence.<\/p>\n<p>Here's a quick diagram of the allpass pair:<\/p>\n<pre class=\"crayon:false\">        ................ filter 1 .................\r\n   +--&gt; allpass --&gt; allpass --&gt; allpass --&gt; allpass --&gt; delay --&gt; out1\r\n   |\r\n  in\r\n   |    ................ filter 2 .................\r\n   +--&gt; allpass --&gt; allpass --&gt; allpass --&gt; allpass ------------&gt; out2 (+90 deg)<\/pre>\n<p>We can use cookbook formulas to convert an allpass section into code. A general IIR recurrence relation:<\/p>\n<pre class=\"crayon:false\">  out(t) = a0*in(t) + a1*in(t-1) + a2*in(t-2) + ...\r\n         + b1*out(t-1) + b2*out(t-2) + ...<\/pre>\n<p>results in the transfer function:<\/p>\n<pre class=\"crayon:false\">         a0 + a1*z^-1 + a2*z^-2 + ...\r\n  H(z) = ----------------------------\r\n          1 - b1*z^-1 - b2*z^-2 - ...<\/pre>\n<p>The allpass section in question has the following transfer function:<\/p>\n<pre class=\"crayon:false\">          a^2 - z^-2\r\n  H(z) = ------------\r\n         1 - a^2 z^-2<\/pre>\n<p>We want to convert this into the recurrence relation. According to the cookbook formulas and the above transfer function:<\/p>\n<pre class=\"crayon:false\">  a0 = a^2, a2 = -1, b2 = a^2, rest of coefficients zero\r\n\r\n  =&gt;  out(t) = a^2*in(t) - in(t-2) + a^2*out(t-2)<\/pre>\n<p>which simplifies to the one-multiplication allpass section:<\/p>\n<pre class=\"crayon:false\">  out(t) = a^2*(in(t) + out(t-2)) - in(t-2)<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This is probably the most efficient structure for implementing a Hilbert transform. Actually, it&#8217;s not a Hilbert transform, but two all-pass IIR filters whose phase difference is approximately 90 degrees over a range of frequencies symmetric around Nyquist\/2. Laurent de Soras uses these kind of filters in his HIIR resampling library, which also has functions &hellip; <a href=\"https:\/\/yehar.com\/blog\/?p=368\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Hilbert transform&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":375,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/368"}],"collection":[{"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=368"}],"version-history":[{"count":4,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/368\/revisions"}],"predecessor-version":[{"id":4558,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/368\/revisions\/4558"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/375"}],"wp:attachment":[{"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=368"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=368"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yehar.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=368"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}