Multi-source signal generator (msource)

API Keywords: msource multi-source source signal generator siggen

The msource family of objects are used to generate signals useful for testing communications systems. The interface allows for creating as many overlapping signals as you want, and provides a simple way to adjust their power level and center frequency independently with sample-level granularity.

doc/msource/msourcecf_example.png

Figure [msource-example]. msourcecf example

Interface

The msource object allows you to create the following signal types:

  • id = msourcecf_add_tone(q) : add a discrete DC tone. To set the frequency of the tone, use the 'set frequency' method (see below for details)
  • id = msourcecf_add_noise(q, bw) : add a noise source with a two-sided bandwidth bw .
  • id = msourcecf_add_modem(q,ms,k,m,beta) : add a modulated data stream with the modulation scheme specified by ms , and interpolated with a square-root Nyquist filter ( LIQUID_FIRFILT_ARKAISER ) with k samples per symbol, a filter delay of m symbols, and an excess bandwidth factor beta . Internally the data stream is created with the symstream object.

You may add as many signal types as you like using the methods described above. Each invocation returns an integer identifier as a handle for manipulating properties of that particular signal type. For example, you may set the following properties for any signal type:

  • msourcecf_set_gain(q,id,gain_dB) : set the signal gain in dB
  • msourcecf_set_frequency(q,id,dphi) : set the signal's angular frequency relative to the sample rate. The value of dphi ranges from \(-\pi\) to \(\pi\) .

Additionally you may easily enable/disable each signal type using the following methods:

  • msourcecf_enable(q,id) : enable signal
  • msourcecf_disable(q,id) : disable signal

Generate samples to an output buffer of any size with msourcecf_write_samples(q,buf,buf_len) . When you're done with a signal, you can remove it from the object list with the msourcecf_remove(q,id) method.

Example

The following listing demonstrates generating various signal types using the msourcecf object:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <liquid/liquid.h>

// user-defined callback; generate tones
int callback(void *          _userdata,
             float complex * _v,
             unsigned int    _n)
{
    unsigned int * counter = (unsigned int*)_userdata;
    unsigned int i;
    for (i=0; i<_n; i++) {
        _v[i] = *counter==0 ? 1 : 0;
        *counter = (*counter+1) % 8;
    }
    return 0;
}

int main()
{
    // msource parameters
    int          ms     = LIQUID_MODEM_QPSK;    // linear modulation scheme
    unsigned int m      =    12;                // modulation filter semi-length
    float        beta   = 0.30f;                // modulation filter excess bandwidth factor
    float        bt     = 0.35f;                // GMSK filter bandwidth-time factor

    // create multi-signal source generator
    msourcecf gen = msourcecf_create_default();

    // add signals     (gen,  fc,   bw,    gain, {options})
    msourcecf_add_noise(gen,  0.0f, 1.00f, -40);               // wide-band noise
    msourcecf_add_noise(gen,  0.0f, 0.20f,   0);               // narrow-band noise
    msourcecf_add_tone (gen, -0.4f, 0.00f,  20);               // tone
    msourcecf_add_modem(gen,  0.2f, 0.10f,   0, ms, m, beta);  // modulated data (linear)
    msourcecf_add_gmsk (gen, -0.2f, 0.05f,   0, m, bt);        // modulated data (GMSK)
    unsigned int counter = 0;
    msourcecf_add_user (gen,  0.4f, 0.15f, -10, (void*)&counter, callback); // tones

    // print source generator object
    msourcecf_print(gen);

    // create spectral periodogram for estimating power spectral density
    unsigned int nfft = 1200;
    spgramcf periodogram = spgramcf_create_default(nfft);

    unsigned int buf_len = 1024;
    float complex buf[buf_len];

    // generate 50 buffers worth of samples
    unsigned int i;
    for (i=0; i<50; i++) {
        // write samples to buffer
        msourcecf_write_samples(gen, buf, buf_len);

        // push resulting sample through periodogram
        spgramcf_write(periodogram, buf, buf_len);
    }

    // compute power spectral density output
    float psd[nfft];
    spgramcf_get_psd(periodogram, psd);

    for (i=0; i<nfft; i++)
        printf("  %12.8f %12.4e\n", (float)i/(float)nfft-0.5f, psd[i]);

    // destroy objects
    msourcecf_destroy(gen);
    spgramcf_destroy(periodogram);
    return 0;
}