dsp_vector library inconsistency

Technical questions regarding the XTC tools and programming with XMOS.
woodsb
Experienced Member
Posts: 79
Joined: Thu Nov 17, 2016 11:24 pm

dsp_vector library inconsistency

Post by woodsb »

Hello:

Posting this here as it seems germane to the forum and the version on Q&A forum not receiving response from XMOS.

The portion of the dsp_vector library that treats complex arithmetic requires real and imaginary parts in separate vectors. Yet the same library's FFT provides real and imaginary parts as elements of a structure, making the two portions, in a sense, incompatible. For instance, if I've read it correctly, a response to a related question (viewtopic.php?f=47&t=5199&p=26517&hilit=dsp_vector#p26517) suggests that users write their own routines for the dsp_vector library functions for this very reason.

I imagine almost all complex DSP is done on the results of FFTs, so am surprised these two libraries are not compatible.

Am I missing something? Is there an easy way to use these two libraries together? If not, any plans, XMOS, to make this possible?

Thanks,
Bill
User avatar
andrew
Verified
Experienced Member
Posts: 117
Joined: Fri Dec 11, 2009 10:22 am

Post by andrew »

Would you mind letting us know which functions in particular you are calling and I'll try to explain the intent of the functions. Thanks
woodsb
Experienced Member
Posts: 79
Joined: Thu Nov 17, 2016 11:24 pm

Post by woodsb »

Thanks, Andrew, for the response.

I am looking at the lib_dsp.pdf version 3.0.0.

An example of the functions I would like to call is application of dsp_vector_mulv_complex() to the output of several dsp_fft_split_spectrum() calls. The latter works with variable type dsp_complex_t, whilst the former works with int32_t variable types. I copied below the prototypes from lib_dsp.pdf.

Please note that I understand at least one, albeit inefficient, way to make these and other lib_dsp functions work together (e.g., copying the dsp_complex_t real and imaginary parts to separate int32_t variables). I also know how to code up the complex multiply without using the library function (and thus avoiding the copying).

What I am asking is if there are any plans to re-write these, or add new, functions to be called with the same variable types, or if there is some "trick" I am missing that avoids inefficiencies like the copying I refer to. (I am assuming that a re-write or add, or "trick", would be more efficient than my xc-level code for the complex multiply.)

Note, also, it would be nice to have a library version of a dot product for complex vectors.

thanks,
Bill


dsp_fft_split_spectrum(dsp_complex_t pts[], const uint32_t N)

dsp_vector_mulv_complex(const int32_t input_vector_X_re[],
const int32_t input_vector_X_im[],
const int32_t input_vector_Y_re[],
const int32_t input_vector_Y_im[],
int32_t result_vector_R_re[],
int32_t result_vector_R_im[],
const int32_t vector_length,
const int32_t q_format)
User avatar
andrew
Verified
Experienced Member
Posts: 117
Joined: Fri Dec 11, 2009 10:22 am

Post by andrew »

Normally, when working in the frequency domain I work with complex multiplications meaning I will use: dsp_complex_mul_vector() or others from dsp_complex.h.
In your case if you would like to use dsp_vector_mulv_complex() then I would recommend writing a type for deinterleave and interleave function. An array of dsp_complex_t is such that each real value is at every other word aligned position, as are the imaginary values.

You could use a reinterpret cast to make this easy, i.e.

Code: Select all

int32_t re[L/2], im[L/2];
for(unsigned i=0; i<L; i+=2){
    re[i/2] = (complex, int32_t[])[i];
    im[i/2] = (complex, int32_t[])[i+1];
}
I hope that helps.
User avatar
johned
XCore Addict
Posts: 185
Joined: Tue Mar 26, 2013 12:10 pm

Post by johned »

Converted Andrew's suggestion in to functions.
I've used vectorLength rather than the length of the interleaved array.

In general the overhead off de-interleaving after the FFT is better than doing vector processing of interleaved I and Q.

J

Code: Select all

void interleave (const int re[],
    const int im[],
    dsp_complex_t complex[],
    const unsigned vectorLength)

{
    for (unsigned i=0; i<vectorLength; i++) {
        (complex, int32_t[])[2*i]   = re[i];
        (complex, int32_t[])[2*i+1] = im[i];
    }
}

void deinterleave (const dsp_complex_t complex[],
    int re[],
    int im[],
    const unsigned vectorLength)

{
    for (unsigned i=0; i<vectorLength; i++) {
        re[i] = (complex, int32_t[])[2*i];
        im[i] = (complex, int32_t[])[2*i+1];
    }
}
woodsb
Experienced Member
Posts: 79
Joined: Thu Nov 17, 2016 11:24 pm

Post by woodsb »

Andrew, you mentioned dsp_complex.h. Apologize if I'm a bit slow on the uptake, but is that part of the XMOS lib_dsp? I don't see dsp_complex when I download lib_dsp from XMOS.

cheers,
Bill
woodsb
Experienced Member
Posts: 79
Joined: Thu Nov 17, 2016 11:24 pm

Post by woodsb »

Hello johned and Andrew,

Thanks for the code help, too. I am unfamiliar with that casting method.

Is "re = (complex, int32_t[])[2*i];" equivalent to "re = complex.re;" ?

If not, how do they differ?

Thanks,
Bill