Andrew Que Sites list Photos
Projects Contact
Main
   This is a shot from a few mornings ago.  While I was approaching State St. I saw this frame and I had to stop and capture it.  There is some interesting color contrast—blue sky, white building, yellow-orange tint from the street light.  There is also some texture contrast.  A solid blue sky, rough brick, shinny smooth tile, and the chain linked fence.  I found it interesting.
   At work I've been learning C Sharp.  Today I learned about how the language implements interfaces and abstract classes.  I also learned the type-checking is often done at run-time rather than compile time.  This I really don't like because I'd rather have type checking errors reported when I'm building rather than when I'm trying to run on the target system.  In addition, exceptions seem to lock our application and the entire system—and this makes for an irritating debug process.  But I am using a microsoft programming environment, and it's a long way from the stability I got use to working in aerospace.
Cannon Fire

Cannon Fire

   Went with Amber to a Civil War reenactment in Boscobel, Wisconsin.  There was a fairly large group of precipitants which made for a good battle.  The cannon fire was really great—you could feel the concussion in your chest.  There was also a good demonstration of Civil War battlefield medical treatment.  While the presents of anesthetic was an improvement over Revolutionary War era medicine it still left a lot to be desired.  I also found it interesting that doctors treated wounded from both sides.

I thought I'd share a simple moving average template class. I got this idea while at work yesterday when talking to an electrical engineer about making a writing efficient average function. Afterward I continued to think about ways to continue to improve upon the idea.

A mean average is simply the sum of all the data divided by the number of data points. A moving average assumes a fixed number of data points. When new data is added, the oldest sample is lost replaced with the new data added. So the mean average reflects the average over the most recent data only. This functions like a low-pass filter and is often used as an easy way to clean up analog signals.

What if the moving average was over a huge number of samples, and the type of samples was some kind of object with computationally difficult math operations? Perhaps the moving average is being preformed on a long list of arbitrary-precision data points. Adding up all the data points and dividing by the number of points could take too long.

We can speed the process of taking the average by keeping a sum. When a new point is added, the oldest data point is subtracted from the sum, and the new data added. In this way the only math operation needed to take the average at any time is dividing by the number of samples.

In making an average class I also considered how to resize the moving average. If the average becomes larger, empty data is simply placed at the end. If it becomes smaller, only the most recent samples need to be saved.

Here is a C++ implementation:

//==============================================================================
// Template class for keeping a moving average.
// Assumes math operations on 'TYPE' are computationally expensive, so used
// sparingly.
//==============================================================================
templateclass TYPE >
  class Average
  {
    protected:
      // Storage of all the data points that make the average.
      TYPE * array;

      // A representation of zero in the type of this template.
      TYPE zero;

      // Index into 'array' to save next data point.
      unsigned currentIndex;

      // How many data points are currently in array.
      unsigned top;

      // Length of 'array'.
      unsigned length;

      // Running sum used to compute average.
      TYPE sum;

    public:
      //------------------------------------------------------------------------
      // Create moving average with 'lengthParameter' number of samples to be
      // averaged together.
      //------------------------------------------------------------------------
      Average( unsigned lengthParameter )
      {
        length = lengthParameter;

        // Allocate storage for
        array = new TYPE[ length ];

        // We need a definition of zero, so make a cast to get this.
        // NOTE: This is important if TYPE is truly a class.
        zero = static_cast< TYPE >( 0 );

        reset();
      }

      //------------------------------------------------------------------------
      // Reset all data in average.
      // NOTE: Average result will be the equivalent of zero.
      //------------------------------------------------------------------------
      void reset()
      {
        // Empty array.
        for ( currentIndex = 0; currentIndex < length; ++currentIndex )
          array[ currentIndex ] = zero;

        currentIndex = 0;
        top = 0;
        sum = 0;
      }

      //------------------------------------------------------------------------
      // Resize the number of samples used in average.
      // If the size becomes larger, then the average will not change until
      // more data is added.
      // If the size becomes smaller, then the last 'newLength' samples will be
      // copied to new average.
      //------------------------------------------------------------------------
      void resize( unsigned newLength )
      {
        // Allocate memory for new array.
        TYPE * newArray = new TYPE[ newLength ];

        // Reset sum.
        sum = zero;
        for ( unsigned count = newLength; count > 0--count )
        {
          unsigned index = count - 1;

          // Do we have data to copy from the old array at this index?
          if ( index < top )
          {
            // Get previous data index.
            if ( currentIndex == 0 )
              currentIndex = length - 1;
            else
              currentIndex -= 1;

            // Save data in new array.
            newArray[ index ] = array[ currentIndex ];

            // Sum this data.
            sum += newArray[ index ];
          }
          else
            // Set this position to zero.
            newArray[ index ] = zero;
       }

        // Delete old array holder and switch to new array.
        delete array;
        array = newArray;

        // Move top if the new length is lower than previous top.
        if ( top > newLength )
          top = newLength;

        // New length.
        length = newLength;

        // Set new index location.
        currentIndex = top;
        if ( currentIndex >= length )
          currentIndex = 0;
      }

      //------------------------------------------------------------------------
      // Return the computed average.
      // NOTE: Uses the data in the average thus far.  If average isn't full,
      // then only those data points in the array are used.
      //------------------------------------------------------------------------
      TYPE get() const
      {
        TYPE result;

        if ( top > 0 )
          result = sum / static_cast< TYPE >( top );
        else
          result = zero;

        return result;
      }

      //------------------------------------------------------------------------
      // Return the number of data points in the moving average so far.
      //------------------------------------------------------------------------
      unsigned getNumberOfDataPoints() const
      {
        return top;
      }

      //------------------------------------------------------------------------
      // Add new data to average.
      //------------------------------------------------------------------------
      void push( TYPE newData )
      {
        // Remove old data from average sum.
        sum -= array[ currentIndex ];

        // Add new data to average sum.
        sum += newData;

        // Save new data.
        array[ currentIndex ] = newData;

        // Advance index.
        ++currentIndex;

        // If this marks the top...
        if ( currentIndex > top )
          // Update the top.
          top = currentIndex;

        // Wrap-around index.
        if ( currentIndex >= length )
          currentIndex = 0;
      }

  };

Download the code

Use it like this:

  Average< int > average( 5 );

  average.push( 1 );
  average.push( 2 );
  average.push( 3 );

  int meanAverage = average.get();

This code will create a rolling average of up to 5 elements.  It then adds the data [1, 2, 3] to the average.  'meanAverage' will be 2.

   Did a set along State Street in the early morning hours, hoping to test my twilight strategy.  Despite having a fairly dark sky I could have still begun eariler.  However, the things I wanted to have happen did happen.  I did not get the heavy lens flare like when I was shooting at night.
   This shot is one I liked quite a bit, but need to shoot again.  The HDR brings out the detail inside the store.  By this point in my ride the sun had just about risen, so I faked the sky by using the sky from the darkest of the images. 
   Dawn over the city of Madison as seen from the edge of Lake Monona.  This is an other HDR shot consisting of 3 images: -3, -1, +1 f-stops.  There were two things I wanted to see.  First, if I could capture better clouds and stars at twilight.  Two, would the images wash out less in twilight.  By the time I took these shots it was past twilight.  However I did capture some stars and the clouds.  The wash out from street light is mitigated by the light from the sky.
Kobold's Cave 7/29/2012

Kobold's Cave 7/29/2012

   I took a few more pictures of the Kobold's Cave today.  Since my last set of pictures, I've moved some things around and added more lighting.  I had two monitors stored at the far side of the room which I moved into under utilized space in my main area.  Then there was the trick to getting a picture on all of them.  The Black Dragon is a trusty machine, and I used it the last time I took pictures—so I knew that worked.  The Red Dragon has I/O problems and won't run reliable.  Try as I might I was never able to get an operating system onto the hard drive.  I was hoping I could boot via USB, but no such luck.  None of my Ubuntu live CDs would boot either.  So I decided to go simple and got Damn Small Linux to boot and run.  I don't know the last time the White Dragon had been powered on, but it also came up without issue. 
   A few days ago I installed the rest of my LED reel lighting.  It can be seen illuminating the shelves on the far wall.  In this picture they are turned all the way up which is not how they are typically run—the lights are too bright to normally keep on high.  Note there are no clamp lights running so no colored compact florescent bulbs are on.  With the red LED rope, the two LED arm lamps and the LED reel lights I found I do not need the additional light from the CFL.  This lowers energy consumption and (naturally) heating caused by lighting.
   The red rope light (66 feet) draw 48 watts, the two LED bulbs and under cabinet strip (at full-power) draw 24 watts, and the LED reel (at full-power) draws 20 watts for a total draw of 72 watts.  However, I usually have the lights dimmed some, so the power draw is actually about 60 watts.  All the CFL together draw 113 watts, so the LED solution is much more efficient.