Audio Code Library: Quadrature Sine/Cosine Generator


This code is primarily an exercise in understanding the complex plane. As you trace the unit circle in the complex plane starting at 1 = e^j*0, the projection onto the real and imaginary axes produces a cosine and sine function respectively (90 degrees out of phase.) We can build a little oscillator by picking some starting point on the unit circle and then multiplying that by some phase increment (e^j*p). The phase of that increment vector defines the frequency of the oscillator, which can be changed any time once the oscillator has started.

Unless you really need the two waveforms in quadrature phase, you probably wouldn't even consider using this algorithm. If you can devote some memory to make a wavetable, an oscillator with linear interpolation will require fewer multiplies.

The code has to break the complex numbers into real and imaginary pairs, but it otherwise straightforward. There is an issue of stability, though it may not be much of an issue with floating point arithmetic. Errors in the calculation can cause our vector to stray from the unit circle. The error can be corrected by normalizing the magnitude of the vector back to 1, placing it on the unit circle. This portion of the code is commented out below, but shown to illustrate the method should you encounter this problem.

The code allows for the frequency, initial phase offset, and amplitude to be specified in the constructor.

See Also:

Please do not redistribute this code. In the event that it contains a bug, this will ensure that it can be fixed without the buggy copies floating around indefinitely.

Last Modified: 9/21/98

SinCos.h

/*********************************************************

SinCos.h - A quadrature sine/cosine generator

Copyright (c) 1998, Scott Lehman, slehman@harmony-central.com
This code may be used and modified freely provided that credit
is given to the author in any public release. Any derivative
programs must be distributed freely and/or the modified source
code made publicly available.  All code is provided AS IS and
without warranty of any kind.
*********************************************************/

#ifndef SINCOS_H
#define SINCOS_H

#include "Source.h"

class SinCos : public Source {
public:
  SinCos(float amp, float freq, float phase);
  void Initialize(void);
  void Generate(void);
  void Cleanup(void);
  ~SinCos(void){;}

private:
  float * sinOut, * cosOut, amplitude, frequency, phase;
  float rInc, iInc, rVal, iVal, temp;
  int i;
  SinCos(SinCos&){};
};


#endif

SinCos.cpp

/*********************************************************

SinCos.cpp - A quadrature sine/cosine generator

Copyright (c) 1998, Scott Lehman, slehman@harmony-central.com
This code may be used and modified freely provided that credit
is given to the author in any public release. Any derivative
programs must be distributed freely and/or the modified source
code made publicly available.  All code is provided AS IS and
without warranty of any kind.
*********************************************************/

#include "SinCos.h"
#include 


// *******************  SinCos(void)  ****************

SinCos :: SinCos(float amp, float freq, float phase)
{
  SetNumOutputs(2);
  this->amplitude = amp;
  this->frequency = freq;
  this->phase = phase * MYTWOPI;
  
  return;
}


// ******************* Initialize(void)  ***************

void SinCos :: Initialize (void)
{
  //compute starting values - e^j*phase, represented as a + bi
  //Real component represents cosine component, imaginary is sine
  rVal = cos(phase);
  iVal = sin(phase);
	
  //compute the phase increment - e^j*2*pi*f/SR in a + bi representation
  //multiplying the location by this moves us along the unit circle
  //We could easily change the frequency of the quadrature oscillator
  //by computing a new phase increment after the oscillator starts.
  rInc = cos(MYTWOPI * frequency / samplingRate);
  iInc = sin(MYTWOPI * frequency / samplingRate);
	
  //assign pointers for the two output signals
  sinOut = outputs[0];
  cosOut = outputs[1];

  return;
}


// *******************  Generate(void)  *****************

void SinCos :: Generate(void)
{
  for(i=0; i<frameLength; i++) {
    //output the two signal values
    sinOut[i] = amplitude*iVal;
    cosOut[i] = amplitude*rVal;
		
    //move us to the next spot on the unit circle
    temp = rVal*rInc - iVal*iInc;
    iVal = rVal*iInc + iVal*rInc;
    rVal = temp;             //rVal + iVal*i = (a+b*i)*(c+d*i)
		
    //optional correction to counteract any errors in the system
    //compute the actual magnitude of our vector and normalize the
    //vector length to move us back on the unit circle. This code
    //was based on a USENET post from Keith Larson of TI.
    /*		
    temp = rVal*rVal + iVal*iVal;
    temp = (3-temp)*.5;  //an approximation for 1/sqrt(temp)
    rVal *= temp;
    iVal *= temp;
    */
  }
  return;
}


// ******************  Cleanup(void)  *******************

void SinCos :: Cleanup(void)
{
  return;
}

Back to the Audio Programming Page

Back to Harmony Central® Home Page

Email: webmaster@harmony-central.com
Copyright © 1995-98 Harmony Central, Inc. All rights reserved.