dsp_vector library inconsistency

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
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
Experienced Member
Posts: 114
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
Experienced Member
Posts: 114
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
Contact:

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
Post Reply