Simple Wave Generation In Python (and SciPy)

[153Armstrong] did a short post on how easy it is to generate waveforms using Python. We agree it is simple, but actually, it isn’t so much Python per se, it is some pretty cool libraries (SciPy, in particular) that do all the hard work. That may be splitting hairs, but it is worth nothing that SciPy (pronounced “Sigh Pie”) also does other handy tricks like Fourier transforms, too. You can see a video of his results, below.

The code is simple and one of the commenters pointed out an even more efficient way to write the data to a WAV file. The basic idea is to create an array of samples in a buffer using some features of SciPy’s NumPy component.

Most regular waveforms are easy to create using an algorithm. For example, sine waves can be generally described as: y=amplitude * sine(radian_frequency*t+phase_shift)

Where y is the value of the wave at time t. The amplitude is the peak value (so 5 will give you +/-5 V) and the radian frequency is twice the value of pi times the frequency in Hertz. [153Armstrong] shows simple formulae for sine waves, symmetric and asymmetric square waves, and a sawtooth wave, using generators provided by the SciPy package. The code is on GitHub and he also links to the generators available in SciPy.

We’ve seen SciPy in some Hackaday contest entries before. You can think of it like Matlab for Python. Just keep in mind, it isn’t an inherent part of Python. If you use another language, you could use a similar library to get the same effect. And if you’re doing this in hardware, you’ll probably want to use look-up tables, to keep things fast and simple.

15 thoughts on “Simple Wave Generation In Python (and SciPy)

  1. Aren’t trig functions performed via lookup tables in math coprocessors or libraries? So may as well do your own table. I doubt they use an infinite series every time you call the function. :D For that matter, why store it in an array in memory, just stream it to a file (the file IO library may have one or more buffering layers anyways, to write out whole blocks of data at an efficient data rate.) But we’re talking Python, not efficient…generally.

    1. > But we’re talking Python, not efficient…generally.

      Just because Python is an ‘interpreted’ dynamically typed language doesn’t mean it’s slow or inefficient. It excels as a glue language for writing applications on top of high-performance libraries.

      For instance NumPy is widely used because you get optimised parallel/vector operations very easily. If your algorithm is organised properly you can easily beat a non-vectorised C implementation. Same goes for GNURadio or OpenCV.

    2. Chebychev polynomials or series or from Euler’s formula. Hyperbiolic functions are ratios of trig functions, etc. There has been a lot of numerical analysis to find the best and fastest.

      Looking up 64 bit or bigger numbers takes a huge lookup table, like block of memory with a 64 bit address. That is, uhmmm… a million terabytes.

  2. At the end of the day, what I enjoyed the most about this video, was just [153Armstrong] curiosity: “I was messing around, I didn’t think this would work…” It’s not rocket surgery, but what is?

  3. I’m making SRT subtitles for the lyrics of a lot of songs. I want to draw the waveform and slide it across the screen, tracking the sound, so I can see when someone is about to sing.

    I used Rogue Amoeba’s Fission to split the tracks, and I like their waveform view. It uses a log scale.

    The ffmpeg showwavespic filter can make a PNG file of the whole audio, but it’s a linear scale. I then have to use the overlay filter to slide the static PNG across, making a video of the waves passing from right to left.

    Could someone please recommend a better way to turn my MP3 songs into MP4 waveform videos?

  4. if you care about speed, this is a relatively slow way to generate sine waves. I refer you to http://www.hugi.scene.org/online/coding/hugi%2016%20-%20cosine.htm where Franky goes through the derivation of an algorithm that allows both sine and cosine to be generated point by point for any frequency using one add and one multiply for each point of each function. That means much better operation for whatever else you need to do.

    As to trig functions in libraries – they normally use the transcendental functions in the microprocessor as lookup tables are large and require interpolation that loses precision. The processor functions are extremely slow compared to a simple multiply as internally they use either a Cordic or modified Taylor series using many mul/add operations each. (I designed the 387 math coprocessor and did processor design for 25 years).

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.