-1

How can I formulate an equation for generating a swept sine wave. I am new to signal processing and cannot find much about the topic of generating swept sine waves online. Please point me to some sources that I can use to generate an equation and use in a code. Thank you.

Paul R
  • 208,748
  • 37
  • 389
  • 560
user3453339
  • 77
  • 1
  • 1
  • 9
  • 2
    Can you generate a non-swept sine wave? – Oliver Charlesworth Mar 23 '14 at 21:40
  • You mean a frequency sweep? I wrote a program to do that once, years ago. Unfortunately I no longer have it, but I remember that I needed to solve a differential equation (on paper) to find the formula for the wave as a function of time. – Wyzard Mar 23 '14 at 21:43
  • According to [this](https://www.clear.rice.edu/elec301/Projects00/elec301/TDS/tds.html) the equation is `x(t) = sin(k*t^2)`, where `k` is the sweep rate. – Roland Smith Mar 23 '14 at 22:14
  • Possible duplicate of [How to create a sine wave generator that can smoothly transition between frequencies](http://dsp.stackexchange.com/questions/971/how-to-create-a-sine-wave-generator-that-can-smoothly-transition-between-frequen/973) ? – Paul R Mar 23 '14 at 22:18

2 Answers2

7

The simplest way to do this is to use a phase accumulator - this is a simple method and it ensures phase continuity as the frequency changes.

To generate a fixed frequency sine wave you might do this (pseudo code):

//
// A = sine wave amplitude
// fs = sample rate (Hz)
// f = sine wave frequency (Hz)
//
phi = 0;                      // phase accumulator
delta = 2 * pi * f / Fs;      // phase increment per sample
for each sample
    output = A * sin(phi);    // output sample value for current sample
    phi += delta;             // increment phase accumulator

For a swept sine wave you would ramp up the frequency linearly, i.e. ramp up delta linearly.

//
// A = sine wave amplitude
// fs = sample rate (Hz)
// f0 = initial frequency (Hz)
// f1 = final frequency (Hz)
// T_sweep = duration of sweep (s)
//
phi = 0;                      // phase accumulator
f = f0;                       // initial frequency
delta = 2 * pi * f / Fs;      // phase increment per sample
f_delta = (f1 - f0) / (Fs * T_sweep);
                              // instantaneous frequency increment per sample
for each sample
    output = A * sin(phi);    // output sample value for current sample
    phi += delta;             // increment phase accumulator
    f += f_delta;             // increment instantaneous frequency
    delta = 2 * pi * f / Fs;  // re-calculate phase increment
Community
  • 1
  • 1
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 1
    The above pseudocode works as expected when translated to JavaScript. Best answer I've seen as it actually includes an example instead of mere statements. – Ten Bitcomb Apr 08 '16 at 23:13
0

compile with gcc FILE.c -lm -o FILE

The program generates a mono 16-bit "swept" sine wave. As a bonus, it also demonstrates sweeping amplitude.

// http://www.purplemath.com/modules/grphtrig.htm

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <string.h>

const double 
    radians = (M_PI * 2);

typedef struct SineWave {

double
    rate,           // sample rate
    frequency,      // oscillation Hz.
    amplitude,      // amplitude
    phase,          // current phase
    phaseStep;      // phase step

    struct transition {

        double
            amplitude,
            amplitudeStep,
            frequency,
            frequencyStep;

    } transition;

} SineWave;

SineWave * sine_wave(double frequency, double amplitude, double rate) {
    SineWave * sw = calloc(1, sizeof(SineWave));
    sw->frequency = frequency, sw->amplitude = amplitude, sw->rate = rate;
    return sw;
}

// close enough comparison..
// http://stackoverflow.com/a/18975072
int double_equals(double a, double b)
{
    return abs(a - b) < 0.001;
}

double sine_wave_sample(SineWave * sw) {
    double sample = sw->amplitude * sin(sw->phase);
    sw->phase += sw->phaseStep;
    if (sw->transition.frequencyStep) {
        sw->frequency += sw->transition.frequencyStep;
        sw->phaseStep = radians * sw->frequency / sw->rate;
        if (double_equals(sw->frequency, sw->transition.frequency)){
            sw->transition.frequencyStep = 0;
            sw->frequency = sw->transition.frequency;
        }
    }
    if (sw->transition.amplitudeStep) {
        sw->amplitude += sw->transition.amplitudeStep;
        if (double_equals(sw->amplitude, sw->transition.amplitude)) {
            sw->transition.amplitudeStep = 0;
            sw->amplitude = sw->transition.amplitude;
        }
    }
    return sample;
}

void sine_wave_frequency_transition(SineWave * sw, double frequency, double duration) {
    sw->transition.frequency = frequency;
    sw->transition.frequencyStep = (frequency - sw->frequency) / (sw->rate * duration);
}

void sine_wave_amplitude_transition(SineWave * sw, double amplitude, double duration) {
    sw->transition.amplitude = amplitude;
    sw->transition.amplitudeStep = (amplitude - sw->amplitude) / (sw->rate * duration);
}

// test
int main(int argc, char ** argv) {

    SineWave * mono = sine_wave(0, 0, 44100); // start with "nothing"

    // transition to 500 Hz by .5 seconds.
    sine_wave_frequency_transition(mono, 500, .5);

    // transition to 50% amplitude by 1 second
    sine_wave_amplitude_transition(mono, SHRT_MAX * .5, 1);

    // 1 second of samples total
    long long samples = mono->rate * 1;

    short sample;
    while (samples--) {
        sample = sine_wave_sample(mono);
        fwrite(&sample, sizeof(sample), 1, stdout);
    }

    return 0;
}