The personal website of Scott W Harden

Realtime FFT Audio Visualization with Python

WARNING: this project is largely outdated, and some of the modules are no longer supported by modern distributions of Python.For a more modern, cleaner, and more complete GUI-based viewer of realtime audio data (and the FFT frequency data), check out my Python Real-time Audio Frequency Monitor project.

I'm no stranger to visualizing linear data in the frequency-domain. Between the high definition spectrograph suite I wrote in my first year of dental school (QRSS-VD, which differentiates tones to sub-Hz resolution), to the various scripts over the years (which go into FFT imaginary number theory, linear data signal filtering with python, and real time audio graphing with wckgraph), I've tried dozens of combinations of techniques to capture data, analyze it, and display it with Python. Because I'm now branching into making microcontroller devices which measure and transfer analog data to a computer, I need a way to rapidly visualize data obtained in Python. Since my microcontroller device isn't up and running yet, linear data from a PC microphone will have to do. Here's a quick and dirty start-to-finish project anyone can tease apart to figure out how to do some of these not-so-intuitive processes in Python. To my knowledge, this is a cross-platform solution too. For the sound card interaction, it relies on the cross-platform sound card interface library PyAudio. My python distro is 2.7 (python xy), but pythonxy doesn't [yet] supply PyAudio.

The code behind it is a little jumbled, but it works. For recording, I wrote a class "SwhRecorder" which uses threading to continuously record audio and save it as a numpy array. When the class is loaded and started, your GUI can wait until it sees newAudio become True, then it can grab audio directly, or use fft() to pull the spectral component (which is what I do in the video). Note that my fft() relies on numpy.fft.fft(). The return is a nearly-symmetrical mirror image of the frequency components, which (get ready to cringe mathematicians) I simply split into two arrays, reverse one of them, and add together. To turn this absolute value into dB, I'd take the log10(fft) and multiply it by 20. You know, if you're into that kind of thing, you should really check out a post I made about FFT theory and analyzing audio data in python.

Here's the meat of the code. To run it, you should really grab the zip file at the bottom of the page. I'll start with the recorder class:

import matplotlib
matplotlib.use('TkAgg') # THIS MAKES IT FAST!
import numpy
import scipy
import struct
import pyaudio
import threading
import pylab
import struct

class SwhRecorder:
    """Simple, cross-platform class to record from the microphone."""

    def __init__(self):
        """minimal garb is executed when class is loaded."""
        self.RATE=48100
        self.BUFFERSIZE=2**12 #1024 is a good buffer size
        self.secToRecord=.1
        self.threadsDieNow=False
        self.newAudio=False

    def setup(self):
        """initialize sound card."""
        #TODO - windows detection vs. alsa or something for linux
        #TODO - try/except for sound card selection/initiation

        self.buffersToRecord=int(self.RATE*self.secToRecord/self.BUFFERSIZE)
        if self.buffersToRecord==0: self.buffersToRecord=1
        self.samplesToRecord=int(self.BUFFERSIZE*self.buffersToRecord)
        self.chunksToRecord=int(self.samplesToRecord/self.BUFFERSIZE)
        self.secPerPoint=1.0/self.RATE

        self.p = pyaudio.PyAudio()
        self.inStream = self.p.open(format=pyaudio.paInt16,channels=1,
            rate=self.RATE,input=True,frames_per_buffer=self.BUFFERSIZE)
        self.xsBuffer=numpy.arange(self.BUFFERSIZE)*self.secPerPoint
        self.xs=numpy.arange(self.chunksToRecord*self.BUFFERSIZE)*self.secPerPoint
        self.audio=numpy.empty((self.chunksToRecord*self.BUFFERSIZE),dtype=numpy.int16)

    def close(self):
        """cleanly back out and release sound card."""
        self.p.close(self.inStream)

    ### RECORDING AUDIO ###

    def getAudio(self):
        """get a single buffer size worth of audio."""
        audioString=self.inStream.read(self.BUFFERSIZE)
        return numpy.fromstring(audioString,dtype=numpy.int16)

    def record(self,forever=True):
        """record secToRecord seconds of audio."""
        while True:
            if self.threadsDieNow: break
            for i in range(self.chunksToRecord):
                self.audio[i*self.BUFFERSIZE:(i+1)*self.BUFFERSIZE]=self.getAudio()
            self.newAudio=True
            if forever==False: break

    def continuousStart(self):
        """CALL THIS to start running forever."""
        self.t = threading.Thread(target=self.record)
        self.t.start()

    def continuousEnd(self):
        """shut down continuous recording."""
        self.threadsDieNow=True

    ### MATH ###

    def downsample(self,data,mult):
        """Given 1D data, return the binned average."""
        overhang=len(data)%mult
        if overhang: data=data[:-overhang]
        data=numpy.reshape(data,(len(data)/mult,mult))
        data=numpy.average(data,1)
        return data

    def fft(self,data=None,trimBy=10,logScale=False,divBy=100):
        if data==None:
            data=self.audio.flatten()
        left,right=numpy.split(numpy.abs(numpy.fft.fft(data)),2)
        ys=numpy.add(left,right[::-1])
        if logScale:
            ys=numpy.multiply(20,numpy.log10(ys))
        xs=numpy.arange(self.BUFFERSIZE/2,dtype=float)
        if trimBy:
            i=int((self.BUFFERSIZE/2)/trimBy)
            ys=ys[:i]
            xs=xs[:i]*self.RATE/self.BUFFERSIZE
        if divBy:
            ys=ys/float(divBy)
        return xs,ys

    ### VISUALIZATION ###

    def plotAudio(self):
        """open a matplotlib popup window showing audio data."""
        pylab.plot(self.audio.flatten())
        pylab.show()

And now here's the GUI launcher:

import ui_plot
import sys
import numpy
from PyQt4 import QtCore, QtGui
import PyQt4.Qwt5 as Qwt
from recorder import *

def plotSomething():
    if SR.newAudio==False:
        return
    xs,ys=SR.fft()
    c.setData(xs,ys)
    uiplot.qwtPlot.replot()
    SR.newAudio=False

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    win_plot = ui_plot.QtGui.QMainWindow()
    uiplot = ui_plot.Ui_win_plot()
    uiplot.setupUi(win_plot)
    uiplot.btnA.clicked.connect(plotSomething)
    #uiplot.btnB.clicked.connect(lambda: uiplot.timer.setInterval(100.0))
    #uiplot.btnC.clicked.connect(lambda: uiplot.timer.setInterval(10.0))
    #uiplot.btnD.clicked.connect(lambda: uiplot.timer.setInterval(1.0))
    c=Qwt.QwtPlotCurve()
    c.attach(uiplot.qwtPlot)

    uiplot.qwtPlot.setAxisScale(uiplot.qwtPlot.yLeft, 0, 1000)

    uiplot.timer = QtCore.QTimer()
    uiplot.timer.start(1.0)

    win_plot.connect(uiplot.timer, QtCore.SIGNAL('timeout()'), plotSomething)

    SR=SwhRecorder()
    SR.setup()
    SR.continuousStart()

    ### DISPLAY WINDOWS
    win_plot.show()
    code=app.exec_()
    SR.close()
    sys.exit(code)

Note that by commenting-out the FFT line and using "c.setData(SR.xs,SR.audio)" you can plot linear PCM data to visualize sound waves like this:

Download Source Code

Finally, here’s the zip file. It contains everything you need to run the program on your own computer (including the UI scripts which are not written on this page)

DOWNLOAD: SWHRecorder.zip

If you make a cool project based on this one, I'd love to hear about it. Good luck!

Markdown source code last modified on January 18th, 2021
---
title: Realtime FFT Audio Visualization with Python
date: 2013-05-09 19:52:02
tags: python, old
---

# Realtime FFT Audio Visualization with Python

>  WARNING: this project is largely outdated, and some of the modules are no longer supported by modern distributions of Python.For a more modern, cleaner, and more complete GUI-based viewer of realtime audio data (and the FFT frequency data), check out my [Python Real-time Audio Frequency Monitor](https://www.swharden.com/wp/2016-07-31-real-time-audio-monitor-with-pyqt/) project.

__I'm no stranger to visualizing linear data in the frequency-domain.__ Between the high definition spectrograph suite I wrote in my first year of dental school ([QRSS-VD](http://www.swharden.com/blog/qrss_vd/), which differentiates tones to sub-Hz resolution), to the various scripts over the years (which go into [FFT imaginary number theory](http://www.swharden.com/blog/2010-06-23-insights-into-ffts-imaginary-numbers-and-accurate-spectrographs/), linear data [signal filtering with python](http://www.swharden.com/blog/2009-01-21-signal-filtering-with-python/), and real time [audio graphing with wckgraph](http://www.swharden.com/blog/2010-03-05-realtime-fft-graph-of-audio-wav-file-or-microphone-input-with-python-scipy-and-wckgraph/)), I've tried dozens of combinations of techniques to capture data, analyze it, and display it with Python. Because I'm now branching into making microcontroller devices which measure and transfer analog data to a computer, I need a way to rapidly visualize data obtained in Python. Since my microcontroller device isn't up and running yet, linear data from a PC microphone will have to do.  Here's a quick and dirty start-to-finish project anyone can tease apart to figure out how to do some of these not-so-intuitive processes in Python. To my knowledge, this is a cross-platform solution too. For the sound card interaction, it relies on the cross-platform sound card interface library [PyAudio](http://people.csail.mit.edu/hubert/pyaudio/). My python distro is 2.7 ([python xy](https://code.google.com/p/pythonxy/)), but pythonxy doesn't [yet] supply PyAudio.


<div class="text-center img-border">

[![](realtime-fft-spectrum-python-pyqwt-graph_thumb.jpg)](realtime-fft-spectrum-python-pyqwt-graph.png)

</div>

__The code behind it is a little jumbled, but it works.__ For recording, I wrote a class "SwhRecorder" which uses threading to continuously record audio and save it as a numpy array. When the class is loaded and started, your GUI can wait until it sees _newAudio_ become _True_, then it can grab _audio_ directly, or use fft() to pull the spectral component (which is what I do in the video). Note that my fft() relies on [numpy.fft.fft()](http://docs.scipy.org/doc/numpy/reference/generated/numpy.fft.fft.html). The return is a nearly-symmetrical mirror image of the frequency components, which (get ready to cringe mathematicians) I simply split into two arrays, reverse one of them, and add together. To turn this absolute value into dB, I'd take the log10(fft) and multiply it by 20. You know, if you're into that kind of thing, you should really check out a [post I made about FFT theory and analyzing audio data in python](http://www.swharden.com/blog/2010-06-23-insights-into-ffts-imaginary-numbers-and-accurate-spectrographs/).

![](https://www.youtube.com/embed/vQ1e47VXxZg)

__Here's the meat of the code.__ To run it, you should really grab the zip file at the bottom of the page. I'll start with the recorder class:

```python
import matplotlib
matplotlib.use('TkAgg') # THIS MAKES IT FAST!
import numpy
import scipy
import struct
import pyaudio
import threading
import pylab
import struct

class SwhRecorder:
    """Simple, cross-platform class to record from the microphone."""

    def __init__(self):
        """minimal garb is executed when class is loaded."""
        self.RATE=48100
        self.BUFFERSIZE=2**12 #1024 is a good buffer size
        self.secToRecord=.1
        self.threadsDieNow=False
        self.newAudio=False

    def setup(self):
        """initialize sound card."""
        #TODO - windows detection vs. alsa or something for linux
        #TODO - try/except for sound card selection/initiation

        self.buffersToRecord=int(self.RATE*self.secToRecord/self.BUFFERSIZE)
        if self.buffersToRecord==0: self.buffersToRecord=1
        self.samplesToRecord=int(self.BUFFERSIZE*self.buffersToRecord)
        self.chunksToRecord=int(self.samplesToRecord/self.BUFFERSIZE)
        self.secPerPoint=1.0/self.RATE

        self.p = pyaudio.PyAudio()
        self.inStream = self.p.open(format=pyaudio.paInt16,channels=1,
            rate=self.RATE,input=True,frames_per_buffer=self.BUFFERSIZE)
        self.xsBuffer=numpy.arange(self.BUFFERSIZE)*self.secPerPoint
        self.xs=numpy.arange(self.chunksToRecord*self.BUFFERSIZE)*self.secPerPoint
        self.audio=numpy.empty((self.chunksToRecord*self.BUFFERSIZE),dtype=numpy.int16)

    def close(self):
        """cleanly back out and release sound card."""
        self.p.close(self.inStream)

    ### RECORDING AUDIO ###

    def getAudio(self):
        """get a single buffer size worth of audio."""
        audioString=self.inStream.read(self.BUFFERSIZE)
        return numpy.fromstring(audioString,dtype=numpy.int16)

    def record(self,forever=True):
        """record secToRecord seconds of audio."""
        while True:
            if self.threadsDieNow: break
            for i in range(self.chunksToRecord):
                self.audio[i*self.BUFFERSIZE:(i+1)*self.BUFFERSIZE]=self.getAudio()
            self.newAudio=True
            if forever==False: break

    def continuousStart(self):
        """CALL THIS to start running forever."""
        self.t = threading.Thread(target=self.record)
        self.t.start()

    def continuousEnd(self):
        """shut down continuous recording."""
        self.threadsDieNow=True

    ### MATH ###

    def downsample(self,data,mult):
        """Given 1D data, return the binned average."""
        overhang=len(data)%mult
        if overhang: data=data[:-overhang]
        data=numpy.reshape(data,(len(data)/mult,mult))
        data=numpy.average(data,1)
        return data

    def fft(self,data=None,trimBy=10,logScale=False,divBy=100):
        if data==None:
            data=self.audio.flatten()
        left,right=numpy.split(numpy.abs(numpy.fft.fft(data)),2)
        ys=numpy.add(left,right[::-1])
        if logScale:
            ys=numpy.multiply(20,numpy.log10(ys))
        xs=numpy.arange(self.BUFFERSIZE/2,dtype=float)
        if trimBy:
            i=int((self.BUFFERSIZE/2)/trimBy)
            ys=ys[:i]
            xs=xs[:i]*self.RATE/self.BUFFERSIZE
        if divBy:
            ys=ys/float(divBy)
        return xs,ys

    ### VISUALIZATION ###

    def plotAudio(self):
        """open a matplotlib popup window showing audio data."""
        pylab.plot(self.audio.flatten())
        pylab.show()
```

__And now here's the GUI launcher:__

```python
import ui_plot
import sys
import numpy
from PyQt4 import QtCore, QtGui
import PyQt4.Qwt5 as Qwt
from recorder import *

def plotSomething():
    if SR.newAudio==False:
        return
    xs,ys=SR.fft()
    c.setData(xs,ys)
    uiplot.qwtPlot.replot()
    SR.newAudio=False

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    win_plot = ui_plot.QtGui.QMainWindow()
    uiplot = ui_plot.Ui_win_plot()
    uiplot.setupUi(win_plot)
    uiplot.btnA.clicked.connect(plotSomething)
    #uiplot.btnB.clicked.connect(lambda: uiplot.timer.setInterval(100.0))
    #uiplot.btnC.clicked.connect(lambda: uiplot.timer.setInterval(10.0))
    #uiplot.btnD.clicked.connect(lambda: uiplot.timer.setInterval(1.0))
    c=Qwt.QwtPlotCurve()
    c.attach(uiplot.qwtPlot)

    uiplot.qwtPlot.setAxisScale(uiplot.qwtPlot.yLeft, 0, 1000)

    uiplot.timer = QtCore.QTimer()
    uiplot.timer.start(1.0)

    win_plot.connect(uiplot.timer, QtCore.SIGNAL('timeout()'), plotSomething)

    SR=SwhRecorder()
    SR.setup()
    SR.continuousStart()

    ### DISPLAY WINDOWS
    win_plot.show()
    code=app.exec_()
    SR.close()
    sys.exit(code)
```

_Note that by commenting-out the FFT line and using "c.setData(SR.xs,SR.audio)" you can plot linear PCM data to visualize sound waves like this:_

<div class="text-center img-border">

[![](pcm_thumb.jpg)](pcm.png)

</div>

### Download Source Code

Finally, here’s the zip file. It contains everything you need to run the program on your own computer (including the UI scripts which are not written on this page)

**DOWNLOAD:** [SWHRecorder.zip](SWHRecorder.zip)

_If you make a cool project based on this one, I'd love to hear about it. Good luck!_

Realtime Data Plotting in Python

WARNING: this project is largely outdated, and some of the modules are no longer supported by modern distributions of Python.For a more modern, cleaner, and more complete GUI-based viewer of realtime audio data (and the FFT frequency data), check out my Python Real-time Audio Frequency Monitor project. I love using python for handing data. Displaying it isn't always as easy. Python fast to write, and numpy, scipy, and matplotlib are an incredible combination. I love matplotlib for displaying data and use it all the time, but when it comes to realtime data visualization, matplotlib (admittedly) falls behind. Imagine trying to plot sound waves in real time. Matplotlib simply can't handle it. I've recently been making progress toward this end with PyQwt with the Python X,Y distribution. It is a cross-platform solution which should perform identically on Windows, Linux, and MacOS. Here's an example of what it looks like plotting some dummy data (a sine wave) being transformed with numpy.roll().

How did I do it? Easy. First, I made the GUI with QtDesigner (which comes with Python x,y). I saved the GUI as a .ui file. I then used the pyuic4 command to generate a python script from the .ui file. In reality, I use a little helper script I wrote designed to build .py files from .ui files and start a little "ui.py" file which imports all of the ui classes. It's overkill for this, but I'll put it in the ZIP anyway. Here's what the GUI looks like in QtDesigner:

After that, I tie everything together in a little script which updates the plot in real time. It takes inputs from button click events and tells a clock (QTimer) how often to update/replot the data. Replotting it involves just rolling it with numpy.roll(). Check it out:

import ui_plot #this was generated by pyuic4 command
import sys
import numpy
from PyQt4 import QtCore, QtGui
import PyQt4.Qwt5 as Qwt

numPoints=1000
xs=numpy.arange(numPoints)
ys=numpy.sin(3.14159*xs*10/numPoints) #this is our data

def plotSomething():
    global ys
    ys=numpy.roll(ys,-1)
    c.setData(xs, ys)
    uiplot.qwtPlot.replot()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    win_plot = ui_plot.QtGui.QMainWindow()
    uiplot = ui_plot.Ui_win_plot()
    uiplot.setupUi(win_plot)

    # tell buttons what to do when clicked
    uiplot.btnA.clicked.connect(plotSomething)
    uiplot.btnB.clicked.connect(lambda: uiplot.timer.setInterval(100.0))
    uiplot.btnC.clicked.connect(lambda: uiplot.timer.setInterval(10.0))
    uiplot.btnD.clicked.connect(lambda: uiplot.timer.setInterval(1.0))

    # set up the QwtPlot (pay attention!)
    c=Qwt.QwtPlotCurve()  #make a curve
    c.attach(uiplot.qwtPlot) #attach it to the qwtPlot object
    uiplot.timer = QtCore.QTimer() #start a timer (to call replot events)
    uiplot.timer.start(100.0) #set the interval (in ms)
    win_plot.connect(uiplot.timer, QtCore.SIGNAL('timeout()'), plotSomething)

    # show the main window
    win_plot.show()
    sys.exit(app.exec_())
Markdown source code last modified on January 18th, 2021
---
title: Realtime Data Plotting in Python
date: 2013-05-08 16:34:27
tags: python, old
---

# Realtime Data Plotting in Python

>  WARNING: this project is largely outdated, and some of the modules are no longer supported by modern distributions of Python.For a more modern, cleaner, and more complete GUI-based viewer of realtime audio data (and the FFT frequency data), check out my [Python Real-time Audio Frequency Monitor](https://www.swharden.com/wp/2016-07-31-real-time-audio-monitor-with-pyqt/) project.
__I love using python for handing data. Displaying it isn't always as easy.__ Python fast to write, and numpy, scipy, and matplotlib are an incredible combination. I love matplotlib for displaying data and [use it all the time](http://swharden.com/blog/matplotlib), but when it comes to realtime data visualization, matplotlib (admittedly) falls behind. Imagine trying to plot sound waves in real time. Matplotlib simply can't handle it. I've recently been making progress toward this end with PyQwt with the [Python X,Y](https://code.google.com/p/pythonxy/) distribution. It is a cross-platform solution which should perform identically on Windows, Linux, and MacOS. Here's an example of what it looks like plotting some dummy data (a sine wave) being transformed with numpy.roll().

<div class="text-center img-border">

![](f.gif)

</div>

__How did I do it?__ Easy. First, I made the GUI with [QtDesigner](http://qt-project.org/doc/qt-4.8/designer-manual.html) (which comes with Python x,y). I saved the GUI as a .ui file. I then used the pyuic4 command to generate a python script from the .ui file. In reality, I use a little helper script I wrote designed to build .py files from .ui files and start a little "ui.py" file which imports all of the ui classes. It's overkill for this, but I'll put it in the ZIP anyway.  Here's what the GUI looks like in QtDesigner:

<div class="text-center img-border">

[![](qtdesigner-python-windows-qwtplot_thumb.jpg)](qtdesigner-python-windows-qwtplot.png)

</div>

__After that, I tie everything together in a little script which updates the plot in real time.__ It takes inputs from button click events and tells a clock (QTimer) how often to update/replot the data. Replotting it involves just rolling it with [numpy.roll()](http://docs.scipy.org/doc/numpy/reference/generated/numpy.roll.html).  Check it out:

```python
import ui_plot #this was generated by pyuic4 command
import sys
import numpy
from PyQt4 import QtCore, QtGui
import PyQt4.Qwt5 as Qwt

numPoints=1000
xs=numpy.arange(numPoints)
ys=numpy.sin(3.14159*xs*10/numPoints) #this is our data

def plotSomething():
    global ys
    ys=numpy.roll(ys,-1)
    c.setData(xs, ys)
    uiplot.qwtPlot.replot()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    win_plot = ui_plot.QtGui.QMainWindow()
    uiplot = ui_plot.Ui_win_plot()
    uiplot.setupUi(win_plot)

    # tell buttons what to do when clicked
    uiplot.btnA.clicked.connect(plotSomething)
    uiplot.btnB.clicked.connect(lambda: uiplot.timer.setInterval(100.0))
    uiplot.btnC.clicked.connect(lambda: uiplot.timer.setInterval(10.0))
    uiplot.btnD.clicked.connect(lambda: uiplot.timer.setInterval(1.0))

    # set up the QwtPlot (pay attention!)
    c=Qwt.QwtPlotCurve()  #make a curve
    c.attach(uiplot.qwtPlot) #attach it to the qwtPlot object
    uiplot.timer = QtCore.QTimer() #start a timer (to call replot events)
    uiplot.timer.start(100.0) #set the interval (in ms)
    win_plot.connect(uiplot.timer, QtCore.SIGNAL('timeout()'), plotSomething)

    # show the main window
    win_plot.show()
    sys.exit(app.exec_())
```

Fixing Slow Matplotlib in Python(x,y)

I recently migrated to Python(x,y) and noticed my matplotlib graphs are resizing unacceptably slowly when I use the pan/zoom button. I'm quite a fan of numpy, scipy, matplotlib, the python imaging library (PIL), and GUI platforms like Tk/TkInter, pyGTK, and pyQT, but getting them all to play nicely is a sometimes pain. I'm considering migrating entirely to Python(x,y) because, as a single distribution, it's designed to install all these libraries (and many more) in a compatible way out of the box. However, when I did, I noticed matplotlib graphs would resize, rescale, and drag around the axes very slowly. After a lot of digging on the interweb, I figured out what was going wrong. I'll show you by plotting 20 random data points the slow way (left) then the fast way (right).

THE PROBLEM: See the difference between the two plots? The one on the left (SLOW!) uses the Qt4Agg backend, which renders the matplotlib plot on a QT4 canvas. This is slower than the one on the right, which uses the more traditional TkAgg backend to draw the plot on a Tk canvas with tkinter (FASTER!). Check out matplotlib's official description of what a backend is and which ones you can use. When you just install Python and matplotlib, Tk is used by default.

import numpy
import matplotlib
matplotlib.use('TkAgg') # <-- THIS MAKES IT FAST!
import pylab
pylab.plot(numpy.random.random_integers(0,100,20))
pylab.title("USING: "+matplotlib.get_backend())
pylab.show()

THE FIX: Tell matplotlib to stop using QT to draw the plot, and let it plot with Tk. This can be done immediately after importing matplotlib, but must be done before importing pylab using the line matplotlib.use('TkAgg'). Here's the full example I used to generate the demonstration plots above. Change TkAgg to Qt4Agg (or comment-out the 'use' line if you're using PythonXY) and you will see performance go down the tube. Alternatively, make a change to the matplotlib rc file to customize default behavior when the package is loaded.

Markdown source code last modified on January 18th, 2021
---
title: Fixing Slow Matplotlib in Python(x,y)
date: 2013-04-15 11:55:27
tags: python, old
---

# Fixing Slow Matplotlib in Python(x,y)

__I recently migrated to [Python(x,y)](https://code.google.com/p/pythonxy/) and noticed my matplotlib graphs are resizing unacceptably slowly when I use the pan/zoom button.__ I'm quite a fan of [numpy](http://www.scipy.org/Download), [scipy](http://www.scipy.org/Download), [matplotlib](http://matplotlib.org), the [python imaging library (PIL)](http://www.pythonware.com/products/pil/), and GUI platforms like [Tk/TkInter](http://wiki.python.org/moin/TkInter), [pyGTK](http://www.pygtk.org/), and [pyQT](http://www.riverbankcomputing.com/software/pyqt/intro), but getting them all to play nicely is a sometimes pain. I'm considering migrating entirely to [Python(x,y)](https://code.google.com/p/pythonxy/) because, as a single distribution, it's designed to install all [these libraries (and many more)](https://code.google.com/p/pythonxy/wiki/StandardPlugins) in a compatible way out of the box. However, when I did, I noticed matplotlib graphs would resize, rescale, and drag around the axes very slowly. After a lot of digging on the interweb, I figured out what was going wrong. I'll show you by plotting 20 random data points the slow way (left) then the fast way (right).

<div class="text-center img-small">

[![](matplotlib-qt4agg_thumb.jpg)](matplotlib-qt4agg.jpg)
[![](matplotlib-tkagg_thumb.jpg)](matplotlib-tkagg.jpg)

</div>

__THE PROBLEM:__ See the difference between the two plots? The one on the left (SLOW!) uses the Qt4Agg backend, which renders the matplotlib plot on a QT4 canvas. This is slower than the one on the right, which uses the more traditional TkAgg backend to draw the plot on a Tk canvas with tkinter (FASTER!).  Check out [matplotlib's official description of what a backend is](http://matplotlib.org/faq/usage_faq.html#what-is-a-backend) and which ones you can use. When you just install Python and matplotlib, Tk is used by default.

```python
import numpy
import matplotlib
matplotlib.use('TkAgg') # <-- THIS MAKES IT FAST!
import pylab
pylab.plot(numpy.random.random_integers(0,100,20))
pylab.title("USING: "+matplotlib.get_backend())
pylab.show()
```

__THE FIX:__ Tell matplotlib to stop using QT to draw the plot, and let it plot with Tk. This can be done immediately after importing matplotlib, but must be done before importing pylab using the line `` matplotlib.use('TkAgg') ``. Here's the full example I used to generate the demonstration plots above. Change TkAgg to Qt4Agg (or comment-out the 'use' line if you're using PythonXY) and you will see performance go down the tube. Alternatively, [make a change to the matplotlib rc file](http://matplotlib.org/users/customizing.html) to customize default behavior when the package is loaded.

Create Mono and Stereo Wave Files with Python

My current project involves needing to create stereo audio in real time with Python. I'm using PyAudio to send the audio data to the sound card, but in this simple example I demonstrate how to create mono and stereo sounds with Python. I'm disappointed there aren't good simple case examples on the internet, so I'm sharing my own. It doesn't get much easier than this!

Python 2

from struct import pack
from math import sin, pi
import wave
import random

RATE=44100

## GENERATE MONO FILE ##
wv = wave.open('test_mono.wav', 'w')
wv.setparams((1, 2, RATE, 0, 'NONE', 'not compressed'))
maxVol=2**15-1.0 #maximum amplitude
wvData=""
for i in range(0, RATE*3):
    wvData+=pack('h', maxVol*sin(i*500.0/RATE)) #500Hz
wv.writeframes(wvData)
wv.close()

## GENERATE STERIO FILE ##
wv = wave.open('test_stereo.wav', 'w')
wv.setparams((2, 2, RATE, 0, 'NONE', 'not compressed'))
maxVol=2**15-1.0 #maximum amplitude
wvData=""
for i in range(0, RATE*3):
    wvData+=pack('h', maxVol*sin(i*500.0/RATE)) #500Hz left
    wvData+=pack('h', maxVol*sin(i*200.0/RATE)) #200Hz right
wv.writeframes(wvData)
wv.close()

The output is two sound files which look like this:

Python 3

from struct import pack
from math import sin, pi
import wave
import random
from os.path import abspath

# create a bytestring containing "short" (2-byte) sine values
SAMPLE_RATE = 44100
waveData = b''
maxVol = 2**15-1.0
frequencyHz = 500.0
fileLengthSeconds = 3
for i in range(0, SAMPLE_RATE * fileLengthSeconds):
    pcmValue = sin(i*frequencyHz/SAMPLE_RATE * pi * 2)
    pcmValue = int(maxVol*pcmValue)
    waveData += pack('h', pcmValue)

# save the bytestring as a wave file
outputFileName = 'output.wav'
wv = wave.open(outputFileName, 'w')
wv.setparams((1, 2, SAMPLE_RATE, 0, 'NONE', 'not compressed'))
wv.writeframes(waveData)
wv.close()
print(f"saved {abspath(outputFileName)}")
Markdown source code last modified on January 18th, 2021
---
title: Create Mono and Stereo Wave Files with Python
date: 2011-07-08 09:22:04
tags: python, old
---

# Create Mono and Stereo Wave Files with Python

__My current project involves needing to create stereo audio in real time__ with Python. I'm using PyAudio to send the audio data to the sound card, but in this simple example I demonstrate how to create mono and stereo sounds with Python. I'm disappointed there aren't good simple case examples on the internet, so I'm sharing my own. It doesn't get much easier than this!

### Python 2

```python
from struct import pack
from math import sin, pi
import wave
import random

RATE=44100

## GENERATE MONO FILE ##
wv = wave.open('test_mono.wav', 'w')
wv.setparams((1, 2, RATE, 0, 'NONE', 'not compressed'))
maxVol=2**15-1.0 #maximum amplitude
wvData=""
for i in range(0, RATE*3):
    wvData+=pack('h', maxVol*sin(i*500.0/RATE)) #500Hz
wv.writeframes(wvData)
wv.close()

## GENERATE STERIO FILE ##
wv = wave.open('test_stereo.wav', 'w')
wv.setparams((2, 2, RATE, 0, 'NONE', 'not compressed'))
maxVol=2**15-1.0 #maximum amplitude
wvData=""
for i in range(0, RATE*3):
    wvData+=pack('h', maxVol*sin(i*500.0/RATE)) #500Hz left
    wvData+=pack('h', maxVol*sin(i*200.0/RATE)) #200Hz right
wv.writeframes(wvData)
wv.close()
```

__The output__ is two sound files which look like this:

<div class="text-center img-border">

[![](mono_thumb.jpg)](mono.png)

[![](stereo_thumb.jpg)](stereo.png)

</div>

### Python 3

```python
from struct import pack
from math import sin, pi
import wave
import random
from os.path import abspath

# create a bytestring containing "short" (2-byte) sine values
SAMPLE_RATE = 44100
waveData = b''
maxVol = 2**15-1.0
frequencyHz = 500.0
fileLengthSeconds = 3
for i in range(0, SAMPLE_RATE * fileLengthSeconds):
    pcmValue = sin(i*frequencyHz/SAMPLE_RATE * pi * 2)
    pcmValue = int(maxVol*pcmValue)
    waveData += pack('h', pcmValue)

# save the bytestring as a wave file
outputFileName = 'output.wav'
wv = wave.open(outputFileName, 'w')
wv.setparams((1, 2, SAMPLE_RATE, 0, 'NONE', 'not compressed'))
wv.writeframes(waveData)
wv.close()
print(f"saved {abspath(outputFileName)}")
```

ATMega48 + LM335 + MAX232 = Serial Port Multi-Channel Temperature Measurement

While working to perfect my temperature-controlled manned experimental propagation transmitter (MEPT), I developed the need to accurately measure temperature inside my Styrofoam enclosure (to assess drift) and compare it to external temperature (to assess insulation effects). I accomplished this utilizing the 8 ADC channels of the ATMega48 and used its in-chip USART capabilities to send this data to a PC for logging. I chose the ATMega48 over the ATTiny2313 (which has USART but no ADCs) and the ATTiny44a (which has ADCs but no USART). From when I see, no ATTiny series ATMEL AVR has both! Lucky for me, the ATMega48 is cheap at $2.84 USD. Here's my basic circuit idea:

EDIT: the voltage reference diagram is wrong at the bottom involving the zener diode. Reference the picture to the right for the CORRECT way to use such a diode as a voltage reference. (stupid me!)

MULTIPLE SENSORS - Although in this demonstration post I only show a single sensor, it's possible to easily have 8 sensors in use simultaneously since the ATMega48 has 8 ADC pins, and even more (infinitely) if you want to design a clever way to switch between them.

LM335 Temperature Sensor - selected because it's pretty cheap (< $1) and quantitative. In other words, every 10mV drop in voltage corresponds to a change of 1ºC. If I wanted to be even cheaper, I would use thermistors (<$0.10) which are more qualitative, but can be calibrated I guess.

Notes on power stability - The output of the sensor is measured with the ADC (analog to digital converter) of the microcontroller. The ADC has a 10-bit resolution, so readings are from 0 to 2^10 (1024). AREF and AVCC can be selected as a voltage reference to set what the maximum value (1024) should be. If the ADC value is 1V (for example) and AREF is 1V, the reading will be 1024. If AREF becomes 5V, the reading will be 1024/5. Make sense? If AREF is fluctuating like crazy, the same ADC voltage will be read as differing vales which is not what we want, therefore care should be taken to ensure AREF is ripple-free and constant. Although I did it by adding a few capacitors to the lines of the power supply (not very precise), a better way would be to use a zener diode (perhaps 4.1V?) as a voltage reference.

Here is my circuit. I'm clocking the chip at 9.21MHz which works well for 19200 baud for serial communication. Refer to my other MAX232 posts for a more detailed explanation of how I chose this value. The temperature sensor (blurry) is toward the camera, and the max232 is near the back. Is that an eyelash on the right? Gross!

The data is read by a Python script which watches the serial port for data and averages 10 ADC values together to produce a value with one more significant digit. This was my way of overcoming continuously-fluctuating values.

Here you can see me testing the device by placing an ice cube on the temperature sensor. I had to be careful to try to avoid getting water in the electrical connections. I noticed that when I pressed the ice against the sensor firmly, it cooled at a rate different than if I simply left the ice near it.NOTICE THE PROGRAMMER in the background (slightly blurry). The orange wires connect the AVR programmer to my circuit, and after the final code is completed and loaded onto the microcontroller these orange wires will be cut away.

Here is some actual data from the device. The LM335 readout is in Kelvin, such that 3.00V implies 300K = 80ºF = 27ºC (room temperature). The data is smooth until I touch it with the soldering iron (spike), then it gets cool again and I touch it with a cold piece of metal (wimpy dip), then later I put an ice cube on it (bigger dip). Pretty good huh? Remember, 0.01V change = 1ºC change. The bottom of the dip is about 2.8V = 280K = 44ºF = 7ºC. If I left the cube on longer, I imagine it would reach 0ºC (273K, or 2.73V).For everyone's reference, here's the pinout diagram of the ATMega48:

import socket
import sys
import serial

ser = serial.Serial('COM1', 19200, timeout=1)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

chunk=""
i=0
data = ser.readline()
while True:
    i+=1
    data = ser.readline()
    data=data.replace("n","")
    data=data.replace("r","")
    data="["+data[:-1]+"]"
    data=eval(data)
    val=sum(data)/float(len(data))
    print i,data,val
    chunk=chunk+"%.01f,"%val
    if i==100:
        print "nSAVING"
        i=0
        f=open("data.txt","a")
        f.write(chunk)
        f.close()
        chunk=""

and the code to PLOT the data file:


import matplotlib.pyplot as plt
import numpy

def smoothTriangle(data,degree,dropVals=False):
        """performs moving triangle smoothing with a variable degree."""
        """note that if dropVals is False, output length will be identical
        to input length, but with copies of data at the flanking regions"""
        triangle=numpy.array(range(degree)+[degree]+range(degree)[::-1])+1
        smoothed=[]
        for i in range(degree,len(data)-degree*2):
                point=data[i:i+len(triangle)]*triangle
                smoothed.append(sum(point)/sum(triangle))
        if dropVals: return smoothed
        smoothed=[smoothed[0]]*(degree+degree/2)+smoothed
        while len(smoothed)<len(data):smoothed.append(smoothed[-1])
        return smooth

print "loading..."
f=open("data.txt")
raw="["+f.read()+"]"
f.close()
data=eval(raw)

print "converting..."
data=numpy.array(data)
data=data/1024.0*5 #10-bit resolution, 5V max

print "graphing"
plt.plot(data)

plt.grid(alpha=.5)
plt.title("ATMega48 LM335 Temperature Sensor")
plt.ylabel("Voltage (V)")
plt.xlabel("Time (5/sec)")
plt.show()

Also, the AVR-GCC code loaded on the ATMega48:

#define F_CPU 9210000UL

#include <avr/io.h>
#include <util/delay.h>

void init_usart(unsigned long);

unsigned int readADC(char times){
    unsigned long avg=0;
    for (char i=0; i<times; i++){
        ADCSRA |= (1<<ADSC); // reset value
        while (ADCSRA & ( 1<<ADSC)) {}; // wait for measurement
        avg=avg+ADC;
    }
    avg=avg/times;
    return avg;
}

int main (void){

    ADMUX = 0b0100101; // AVCC ref on ADC5
    ADCSRA = 0b10000111; //ADC Enable, Manual Trigger, Prescaler 128
    ADCSRB = 0;

    DDRD=255;

    init_usart(19200);
    for(;;){
        for(char j=0;j<10;j++){
            sendNum(readADC(10)>>6); // shift to offset 10bit 16bit
            send(44); // COMMA
            PORTD=255;_delay_ms(10);
            PORTD=0;_delay_ms(10);
            }
        send(10);send(13); // LINE BREAK
        }
    }

void sendNum(unsigned int num){
        char theIntAsString[7];
        int i;
        sprintf( theIntAsString, "%u", num );
        for (i=0; i < strlen(theIntAsString); i++)
        {send(theIntAsString[i]);}
}

void send (unsigned char c){
        while((UCSR0A & (1<<UDRE0)) == 0) {}
        UDR0 = c;
}

void init_usart (unsigned long baud)
{
    /////////////////////////
    //        Baud Generation
    unsigned int UBRR_2x_off;
    unsigned int UBRR_2x_on;
    unsigned long closest_match_2x_off;
    unsigned long closest_match_2x_on;
    unsigned char off_2x_error;
    unsigned char on_2x_error;

    UBRR_2x_off = F_CPU/(16*baud) - 1;
    UBRR_2x_on = F_CPU/(8*baud) - 1;

    closest_match_2x_off = F_CPU/(16*(UBRR_2x_off + 1));
    closest_match_2x_on = F_CPU/(8*(UBRR_2x_on + 1));

    off_2x_error = 255*(closest_match_2x_off/baud - 1);
    if (off_2x_error <0) {off_2x_error *= (-1);}
    on_2x_error = 255*(closest_match_2x_on/baud -1);
    if (on_2x_error <0) {on_2x_error *= (-1);}

    if(baud > F_CPU / 16)
    {
        UBRR0L = 0xff & UBRR_2x_on;
        UBRR0H = 0xff & (UBRR_2x_on>>8);
        UCSR0A |= (1<<U2X0);
    } else {

        if (off_2x_error > on_2x_error)
        {
            UBRR0L = 0xff & UBRR_2x_on;
            UBRR0H = 0xff & (UBRR_2x_on>>8);
            UCSR0A |= (1<<U2X0);
        } else {
            UBRR0L = 0xff & UBRR_2x_off;
            UBRR0H = 0xff & (UBRR_2x_off>>8);
            UCSR0A &= ~(1<<U2X0);
        }
    }
    /////////////////////////
    //    Configuration Registers
    UCSR0B = (0<<RXCIE0) |//We don't want this interrupt
    (0<<TXCIE0) |//We don't want this interrupt
    (0<<UDRIE0) |//We don't want this interrupt
    (1<<RXEN0) |//Enable RX, we wont use it here but it can't hurt
    (1<<TXEN0) |//Enable TX, for Talkin'
    (0<<UCSZ02);//We want 8 data bits so set this low

    UCSR0A |= (0<<U2X0) |//already set up, so don't mess with it
    (0<<MPCM0) ;//We wont need this

    UCSR0C = (0<<UMSEL01) | (0<<UMSEL00) |//We want UART mode
    (0<<UPM01) | (0<<UPM00) |//We want no parity bit
    (0<<USBS0) |//We want only one stop bit
    (1<<UCSZ01) | (1<<UCSZ00) |//We want 8 data bits
    (0<<UCPOL0) ;//This doesn't effect UART mode
}

UPDATE: A day later I added multiple sensors to the device. I calibrated one of them by putting it in a plastic bag and letting it set in ice water, then I calibrated the rest to that one. You can see as my room temperature slowly falls for the night, the open air sensor (red) drops faster than the insulated one in a Styrofoam box. Also, I did a touch of math to convert voltage to kelvin to Fahrenheit. You can also see spikes where it quickly approached 90+ degrees from the heat of my fingers as I handled the sensor. Cool!

UPDATE: a day and a half later, here's what the fluctuations look like. Notice the cooling of night, the heating of day, and now (near the end of the graph) the scattered rain causes more rapid fluctuations. Also, although one sensor is in an insulated styrofoam box, it still fluctuates considerably. This measurement system is prepped and ready to go for crystal oven tests!

Markdown source code last modified on January 18th, 2021
---
title: Serial Port Multi-Channel Temperature Measurement
date: 2010-11-24 08:17:03
tags: circuit, microcontroller, python, old
---

# ATMega48 + LM335 + MAX232 = Serial Port Multi-Channel Temperature Measurement

__While working to perfect my temperature-controlled manned experimental propagation transmitter (MEPT), I developed the need to accurately measure temperature inside my Styrofoam enclosure (to assess drift) and compare it to external temperature (to assess insulation effects).__ I accomplished this utilizing the 8 ADC channels of the ATMega48 and used its in-chip USART capabilities to send this data to a PC for logging.  I chose the ATMega48 over the ATTiny2313 (which has USART but no ADCs) and the ATTiny44a (which has ADCs but no USART).  From when I see, no ATTiny series ATMEL AVR has both!  Lucky for me, the [ATMega48 is cheap](http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail&name=ATMEGA48-20PU-ND) at $2.84 USD. Here's my basic circuit idea: 

<div class="text-center img-border"> 

[![](IMG_4559_thumb.jpg)](IMG_4559.jpg)

</div>

EDIT: the voltage reference diagram is wrong at the bottom involving the zener diode. Reference the picture to the right for the CORRECT way to use such a diode as a voltage reference. (stupid me!)

<div class="text-center"> 

![](aref.jpg)

</div>

__MULTIPLE SENSORS__ - Although in this demonstration post I only show a single sensor, it's possible to easily have 8 sensors in use simultaneously since the ATMega48 has 8 ADC pins, and even more (infinitely) if you want to design a clever way to switch between them.

__LM335 Temperature Sensor__ - selected because it's pretty cheap (< $1) and quantitative. In other words, every 10mV drop in voltage corresponds to a change of 1ºC.  If I wanted to be even cheaper, I would use thermistors (<$0.10) which are more qualitative, but can be calibrated I guess.

Notes on power stability  - The output of the sensor is measured with the ADC (analog to digital converter) of the microcontroller. The ADC has a 10-bit resolution, so readings are from 0 to 2^10 (1024).  AREF and AVCC can be selected as a voltage reference to set what the maximum value (1024) should be.  If the ADC value is 1V (for example) and AREF is 1V, the reading will be 1024.  If AREF becomes 5V, the reading will be 1024/5. Make sense?  If AREF is fluctuating like crazy, the same ADC voltage will be read as differing vales which is not what we want, therefore care should be taken to ensure AREF is ripple-free and constant.  Although I did it by adding a few capacitors to the lines of the power supply (not very precise), a better way would be to use a <a href="http://en.wikipedia.org/wiki/Zener_diode">zener diode (perhaps 4.1V?) as a voltage reference.

<div class="text-center img-border">

[![](IMG_4575_thumb.jpg)](IMG_4575.jpg)

</div>

<b>Here is my circuit.</b> I'm clocking the chip at 9.21MHz which works well for 19200 baud for serial communication. Refer to my other MAX232 posts for a more detailed explanation of how I chose this value. The temperature sensor (blurry) is toward the camera, and the max232 is near the back. Is that an eyelash on the right? Gross!

<div class="text-center img-border"> 

![](logger.jpg)

</div>

<b>The data is read by a Python script</b> which watches the serial port for data and averages 10 ADC values together to produce a value with one more significant digit. This was my way of overcoming continuously-fluctuating values.

<div class="text-center img-border"> 

[![](IMG_4564_thumb.jpg)](IMG_4564.jpg)

</div>

<b>Here you can see me testing the device</b> by placing an ice cube on the temperature sensor. I had to be careful to try to avoid getting water in the electrical connections. I noticed that when I pressed the ice against the sensor firmly, it cooled at a rate different than if I simply left the ice near it.<b>NOTICE THE PROGRAMMER</b> in the background (slightly blurry). The orange wires connect the AVR programmer to my circuit, and after the final code is completed and loaded onto the microcontroller these orange wires will be cut away.

<div class="text-center"> 

[![](lm335-microcontroller-graph-annotated_thumb.jpg)](lm335-microcontroller-graph-annotated.png)

</div>

<b>Here is some actual data from the device.</b> The LM335 readout is in Kelvin, such that 3.00V implies 300K = 80ºF = 27ºC (room temperature). The data is smooth until I touch it with the soldering iron (spike), then it gets cool again and I touch it with a cold piece of metal (wimpy dip), then later I put an ice cube on it (bigger dip). Pretty good huh? Remember, 0.01V change = 1ºC change. The bottom of the dip is about 2.8V = 280K = 44ºF = 7ºC. If I left the cube on longer, I imagine it would reach 0ºC (273K, or 2.73V).<b>For everyone's reference, here's the pinout diagram of the ATMega48:</b>

<div class="text-center img-medium"> 

[![](atmega48pinout_thumb.jpg)](atmega48pinout.png)

</div>

```python
import socket
import sys
import serial

ser = serial.Serial('COM1', 19200, timeout=1)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

chunk=""
i=0
data = ser.readline()
while True:
    i+=1
    data = ser.readline()
    data=data.replace("n","")
    data=data.replace("r","")
    data="["+data[:-1]+"]"
    data=eval(data)
    val=sum(data)/float(len(data))
    print i,data,val
    chunk=chunk+"%.01f,"%val
    if i==100:
        print "nSAVING"
        i=0
        f=open("data.txt","a")
        f.write(chunk)
        f.close()
        chunk=""

```

<b>and the code to PLOT the data file:</b>

```python

import matplotlib.pyplot as plt
import numpy

def smoothTriangle(data,degree,dropVals=False):
        """performs moving triangle smoothing with a variable degree."""
        """note that if dropVals is False, output length will be identical
        to input length, but with copies of data at the flanking regions"""
        triangle=numpy.array(range(degree)+[degree]+range(degree)[::-1])+1
        smoothed=[]
        for i in range(degree,len(data)-degree*2):
                point=data[i:i+len(triangle)]*triangle
                smoothed.append(sum(point)/sum(triangle))
        if dropVals: return smoothed
        smoothed=[smoothed[0]]*(degree+degree/2)+smoothed
        while len(smoothed)<len(data):smoothed.append(smoothed[-1])
        return smooth

print "loading..."
f=open("data.txt")
raw="["+f.read()+"]"
f.close()
data=eval(raw)

print "converting..."
data=numpy.array(data)
data=data/1024.0*5 #10-bit resolution, 5V max

print "graphing"
plt.plot(data)

plt.grid(alpha=.5)
plt.title("ATMega48 LM335 Temperature Sensor")
plt.ylabel("Voltage (V)")
plt.xlabel("Time (5/sec)")
plt.show()
```

<b>Also, the AVR-GCC code loaded on the ATMega48:</b>

```c
#define F_CPU 9210000UL

#include <avr/io.h>
#include <util/delay.h>

void init_usart(unsigned long);

unsigned int readADC(char times){
    unsigned long avg=0;
    for (char i=0; i<times; i++){
        ADCSRA |= (1<<ADSC); // reset value
        while (ADCSRA & ( 1<<ADSC)) {}; // wait for measurement
        avg=avg+ADC;
    }
    avg=avg/times;
    return avg;
}

int main (void){

    ADMUX = 0b0100101; // AVCC ref on ADC5
    ADCSRA = 0b10000111; //ADC Enable, Manual Trigger, Prescaler 128
    ADCSRB = 0;

    DDRD=255;

    init_usart(19200);
    for(;;){
        for(char j=0;j<10;j++){
            sendNum(readADC(10)>>6); // shift to offset 10bit 16bit
            send(44); // COMMA
            PORTD=255;_delay_ms(10);
            PORTD=0;_delay_ms(10);
            }
        send(10);send(13); // LINE BREAK
        }
    }

void sendNum(unsigned int num){
        char theIntAsString[7];
        int i;
        sprintf( theIntAsString, "%u", num );
        for (i=0; i < strlen(theIntAsString); i++)
        {send(theIntAsString[i]);}
}

void send (unsigned char c){
        while((UCSR0A & (1<<UDRE0)) == 0) {}
        UDR0 = c;
}

void init_usart (unsigned long baud)
{
    /////////////////////////
    //        Baud Generation
    unsigned int UBRR_2x_off;
    unsigned int UBRR_2x_on;
    unsigned long closest_match_2x_off;
    unsigned long closest_match_2x_on;
    unsigned char off_2x_error;
    unsigned char on_2x_error;

    UBRR_2x_off = F_CPU/(16*baud) - 1;
    UBRR_2x_on = F_CPU/(8*baud) - 1;

    closest_match_2x_off = F_CPU/(16*(UBRR_2x_off + 1));
    closest_match_2x_on = F_CPU/(8*(UBRR_2x_on + 1));

    off_2x_error = 255*(closest_match_2x_off/baud - 1);
    if (off_2x_error <0) {off_2x_error *= (-1);}
    on_2x_error = 255*(closest_match_2x_on/baud -1);
    if (on_2x_error <0) {on_2x_error *= (-1);}

    if(baud > F_CPU / 16)
    {
        UBRR0L = 0xff & UBRR_2x_on;
        UBRR0H = 0xff & (UBRR_2x_on>>8);
        UCSR0A |= (1<<U2X0);
    } else {

        if (off_2x_error > on_2x_error)
        {
            UBRR0L = 0xff & UBRR_2x_on;
            UBRR0H = 0xff & (UBRR_2x_on>>8);
            UCSR0A |= (1<<U2X0);
        } else {
            UBRR0L = 0xff & UBRR_2x_off;
            UBRR0H = 0xff & (UBRR_2x_off>>8);
            UCSR0A &= ~(1<<U2X0);
        }
    }
    /////////////////////////
    //    Configuration Registers
    UCSR0B = (0<<RXCIE0) |//We don't want this interrupt
    (0<<TXCIE0) |//We don't want this interrupt
    (0<<UDRIE0) |//We don't want this interrupt
    (1<<RXEN0) |//Enable RX, we wont use it here but it can't hurt
    (1<<TXEN0) |//Enable TX, for Talkin'
    (0<<UCSZ02);//We want 8 data bits so set this low

    UCSR0A |= (0<<U2X0) |//already set up, so don't mess with it
    (0<<MPCM0) ;//We wont need this

    UCSR0C = (0<<UMSEL01) | (0<<UMSEL00) |//We want UART mode
    (0<<UPM01) | (0<<UPM00) |//We want no parity bit
    (0<<USBS0) |//We want only one stop bit
    (1<<UCSZ01) | (1<<UCSZ00) |//We want 8 data bits
    (0<<UCPOL0) ;//This doesn't effect UART mode
}

```

<b>UPDATE:</b> A day later I added multiple sensors to the device. I calibrated one of them by putting it in a plastic bag and letting it set in ice water, then I calibrated the rest to that one. You can see as my room temperature slowly falls for the night, the open air sensor (red) drops faster than the insulated one in a Styrofoam box. Also, I did a touch of math to convert voltage to kelvin to Fahrenheit. You can also see spikes where it quickly approached 90+ degrees from the heat of my fingers as I handled the sensor. Cool!

<div class="text-center"> 

[![](3traces_thumb.jpg)](3traces.png)

</div>

<b>UPDATE:</b> a day and a half later, here's what the fluctuations look like. Notice the cooling of night, the heating of day, and now (near the end of the graph) the scattered rain causes more rapid fluctuations. Also, although one sensor is in an insulated styrofoam box, it still fluctuates considerably. This measurement system is prepped and ready to go for crystal oven tests!

<div class="text-center"> 

[![](insulated3_thumb.jpg)](insulated3.png)

</div>
Pages