ASCIIMath creating images

Wednesday, January 3, 2018

A trip to the library...

When I started thinking about resampling and the filters used in resampling I leaned heavily on the book by P. P. Vaidyanathanm, "Multirate Systems And Filter Banks", the "brown book" that every signal processing practitioner should have on his or her shelf (or on a shelf of a nearby colleague)!

Like many articles discussing this topic (e.g. the documentation of this MATLAB function), the key paper always referenced is Kaiser, James F. “Nonrecursive Digital Filter Design Using the I0-Sinh Window Function.” Proceedings of the 1974 IEEE International Symposium on Circuits and Systems. April, 1974, pp. 20–23. Being curious about how the equations given in Vaidyanathanm were derived, I wanted to see the original paper - but unfortunately, the earliest proceedings of ISCAS that can be found in IEEE Xplore are from 1988 - 14 years after the one I'm after.

Luckily, I happen to be on Christmas vacation at my inlaws, which live in Kitchener, which is right next door to Waterloo - home to one of the best engineering universities of the world. Unsurprisingly, they have a well-stocked library, which includes the above conference proceeding booklet and, braving the cold, I now have a copy for my own archives.

I could only copy it by taking snaps using my cellphone - the copiers need a special card to use, and the scanners need a UWaterloo login, but for reading the content, that is sufficient with today's smartphones.  It's only for personal use, and I do hope that the IEEE will eventually get around to scanning in the older papers!

Papers from that era have a certain charm.  Typewriter written equations.  FORTRAN code.  I believe the below should be FORTRAN66 (due to the IF statement; I don't think FORTRAN IV had that, and FORTRAN77 obviously didn't exist yet).  Without looking it up, do you know how that IF statement works? (Explanation at end)

As for what I learned from the paper (on first quick read): those formulas relating N and beta to the Stopband attenuation and transition band width were fitted to empirical data.  I expected as much - but still I wanted to confirm that to myself. (If on a closer read I turn out to be wrong, I'll correct this post)

So there's one item off my list of things to to in 2018. Visit the UWaterloo Campus and its library.  Good fun.


The FORTRAN IF statement: That is known as the "arithmetic IF" or "three-way IF" statement. The expression after the IF is evaluated, and if it is negative, the execution jumps to the first label ("2", exiting the subroutine). If the result is 0, we go to the second label ("1"), and if it is positive, to the third (also "1").  Here, each term of the power series expansion is calculated, and as soon as the new term is less than 2x10^-9 of the approximation, the code terminates. And IIRC, FORTRAN is call-by-reference.

Wednesday, November 1, 2017

Halloween Raspberry Pi project

Halloween is a great time to do projects if you have kids.  There is a lot of fun to be had building animated things for displays or costumes.  In our case, Madeline and I collaborated on a great costume for our son, who wanted to go as a Robot.  She found some shiny material and sewed it up, and I build an animated control panel.

The Rπ0 controls a IIC-connected OLED display (128x32) and 9 LEDs via the GPIOs. I could theoretically have used an Arduino - but the OLED display is 3.3V only, and I only have 5V Arduinos (I know I can just underclock them, but not during development).  Thickness was also a factor - the Rπ0 is VERY flat.

The panel is built mostly of Moosgummi (craft foam rubber), and I mounted my Raspberry Pi 0 into it.  The Rπ0 and all the other stuff is mounted in a sandwich of Moosgummi sheets with strips of Moosgummi around the edge.  Power and development (eg. changing the scrolling message or the blink pattern) is done trough a gap, through which a (short) USB cable is fed.  The LEDs are connected trough 150 Ohm resistors directly to the GPIOs.

The SD card has Raspbian Stretch Lite on it, to which I added the Adafruit SSD1306 Python library.  The Python script (placed in a Gist here) running the display and the LEDs sits in the (FAT-formatted) boot partition, and is called from rc.local.  Once that was all in place, I used the Read-Only Raspbian script to make the system read-only; this way I can just pull the power once the trick-or-treating is done.  The script on the boot partition can still be edited at will by remounting /boot read-write (or pulling the SD card and editing it on a different computer!)  The Rπ0 acts as a USB Ethernet gadget, and I can just ssh into it.

Life lesson learned: Mounting blinking LEDs on your kids makes them very easy to find at night! Note to self: next time, add lights to the back (of the kids) as well.

Sunday, May 7, 2017

NNResample package on PyPI

In the previous post, I described my filter generation method for scipy.signal.resample_poly, where the filter is designed such that the first null if the filter is on Nyquist.  For easier inclusion into my own projects, I made it into a package as a self-standing function, and then decided to make that my first submission to PyPI.  The package depends only on numpy and scipy>=0.18.0.

So, if you want to use my resampler, you can now simply do `pip install nnresample`. To report bugs, the link to the repository is

I've included one "special feature": since it takes a little time to generate the filter (to search for the null and regenerate the filter afterwards) the generated filter is cached in a global for re-use.

As for the name, since I'm calling it "Null-on-Nyquist Resampler", the obvious name should be non-resample, but I think that could be confusing...

Wednesday, May 3, 2017

Resampling in Python: Electric Bugaloo

In a previous post, I looked at some sample rate conversion methods for Python, at least for audio data.  I did some more digging into it, and thanks to a note by Prof. Christian Muenker from the Munich University of Applied Sciences I was made aware of scipy.signal.resample_poly (new in scipy since 0.18.0).  This lead me down a bit of a rabbit-hole and I ended up with a Jupyter Notebook which I'm not going to copy-paste here since there is quite a bit of code and some LaTeX in there.  Here is the link to it instead.

For the impatient, here are the interesting bits:

def resample_poly_filter(up, down, beta=5.0, L=16001):
    # *** this block STOLEN FROM scipy.signal.resample_poly ***
    # Determine our up and down factors
    # Use a rational approximation to save computation time on really long
    # signals
    g_ = gcd(up, down)
    up //= g_
    down //= g_
    max_rate = max(up, down)

    sfact = np.sqrt(1+(beta/np.pi)**2)
    # generate first filter attempt: with 6dB attenuation at f_c.
    filt = firwin(L, 1/max_rate, window=('kaiser', beta))
    N_FFT = 2**19
    NBINS = N_FFT/2+1
    paddedfilt = np.zeros(N_FFT)
    paddedfilt[:L] = filt
    ffilt = np.fft.rfft(paddedfilt)
    # now find the minimum between f_c and f_c+sqrt(1+(beta/pi)^2)/L
    bot = int(np.floor(NBINS/max_rate))
    top = int(np.ceil(NBINS*(1/max_rate + 2*sfact/L)))
    firstnull = (np.argmin(np.abs(ffilt[bot:top])) + bot)/NBINS
    # generate the proper shifted filter
    filt2 = firwin(L, -firstnull+2/max_rate, window=('kaiser', beta))
    return filt2

wfilt = resample_poly_filter(P, Q, L=2**16+1)
plt.specgram(scipy_signal.resample_poly(sig, P, Q, window=wfilt)*30, scale='dB', Fs=P, NFFT=256)

Recycling my test sweep from the previous post, I get:
Sweep resampled using my own filter
But really, please read the Notebook.  Comments are welcome!

Monday, March 20, 2017

Publication update

This blog has been basically been inactive since last October since being a PostDoc means that there are a whole bunch other things that I am busy with.  And of course, it was winter - that means statistically, there is always someone in the family who is sick (kids bring home every germ that is going around...).

View of Kiel. Source: Johannes Barre 2006, on Wikipedia
But it is spring now!  And I have just returned from DAGA 2017 in Kiel (where we found a very nice Thai restaurant) so time to update some of my work!

First off, my colleagues in Hannover published "Customized high performance low power processor for binaural speaker localization" at ICECS 2016 in Monte Carlo, Monaco (paper on IEEE Xplore), there was the Winter plenary of Hearing4all, and at DAGA 2017, I presented "Pitch features for low-complexity online speaker tracking", and Sarina (Ph.D. student I'm co-supervising) presented "A distance measure to combine monaural and binaural auditory cues for sound source segregation", both of which can be found on my homepage.  In the pipeline is now "Real-time Implementation of a GMM-based Binaural Localization Algorithm on a VLIW-SIMD Processor" by Christopher, which has been accepted and will be presented at ICME 2017 in Hong Kong in July, and I submitted a paper ("Segregation and Linking of Speech Glimpses in Multisource Scenarios on a Hearing Aid") to EUSIPCO 2017; that one is still in review.

I was also teaching a class in the past semester ("5.04.4223 Introduction into Music Information Retrieval") which, because it's a brand new class took a crazy amount of work to prepare for - but I think the students really enjoyed it, and I saw some very good code being written for the final project.

Now back to real work (writing more papers, that is)!  (Well, there's one or two topics I'll put on the blog in the next little while, too.  Later.)

Friday, March 17, 2017

What happened to my homepage? Or: why you should read emails from your hosting provider carefully...

Having had about a million things on my plate recently (WHEN was the last time I blogged anything?), I tend to prioritize emails - and I did kinda ignore an email sent out by Atlassian in January.  It meant to inform me that the personal homepages on BitBucket were moving from to (and switching to https in the process); a redirect from Jan 23rd on, then the old link would be dead after March 1st.

I noticed this of course only when I suddenly couldn't access my homepage. D'Oh!

I have now gone though most of the blog postings here to fix all the links.  If you find any that I missed (or other dead links) please let me know in the comments! Thanks!

Sunday, October 23, 2016

A (very) short trip to Korea

Panorama view from my room at the Nest Hotel in Incheon.  The Incheon Airport is visible on the right.
Earlier this month, I was in Incheon, South Korea, to present a talk at the Symposium for "Statistical physics, machine learning, and its application to speech and pattern recognition", organized by Prof. Kang-Hun Ahn as part of the Korea Institute for Advanced Study (KIAS).  I was specifically invited to give a talk there (along with Jörg Lücke and Steven van de Par). One does not refuse such an invitation, esp. as a post-doc trying to make an academic career happen.

As a conference, the event was very good, in both of scientific content and forging connections that hopefully can  continue in the future.  Many interesting discussions happened outside the sessions, too.
The location of the Symposium banquet. It was excellent.  Don't ask me for the name though; but I can give the coordinates: 37°25'53.1"N 126°25'27.0"E

The trip was bizarre for me for one reason, though.  It's the first time I traveled that far just to present at a conference.  Unfortunately, this symposium was scheduled not long after I had returned from Italy (where I was at MLSP 2016, coupled with a 1 week vacation), and the week before classes start here at the University of Oldenburg; so I had no time to do any sightseeing in Korea.  I literally arrived the day before the first day of the symposium, and left the morning after the last day.  Total time in Korea: about 66 hours. Total time flying there and back: 30 hours. We (myself, Jörg, and Steven) never went further than about 5 km from the Airport.

I certainly hope to go to Korea again, but then stay a little longer! There is so much to see, and I have friends in Japan I'd like to visit, too.  (I've been to Jeju before, so I know Korea can be very beautiful. Next time I'd like to bring the wife and kids along!)