This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMDSLCDK6748: How to include previous samples for FIR filter DSPF_sp_fir_gen()

Part Number: TMDSLCDK6748

Hi all,

Can you help me figure out how to include previous samples in FIR filter. According to the TMS320C67x DSP Library Programmers Ref. Guide SPRU657C, the input array starts at x(-nh+1) and ends at x(nr-1).

To test the filter, I'm using the mcaspPlayBk.c from the StarterWare C6748_StarterWare_1_20_04_01

To construct the input array for the FIR filter, I'm increasing the buffer size from its default of 2000 samples to 2015 for a 16-tap filter. The problem I have (I think) is that I don't know how to insert (nh-1) previous samples to the head of buffer. Since the data comes in frames, I'm trying to save the last (nh-1) sample from the previous frame then using them in the "current" frame. But this isn't working.

Here is my code, which is modified version of mcaspPlayBk.c:

    while(1)
    {
        if(lastFullRxBuf != lastSentTxBuf)
        {
            /*
            ** Start the transmission from the link paramset. The param set
            ** 1 will be linked to param set at PAR_TX_START. So do not
            ** update paRAM set1.
            */
            parToSend =  PAR_TX_START + (parOffTxToSend % NUM_PAR);
            parOffTxToSend = (parOffTxToSend + 1) % NUM_PAR;
            parToLink  = PAR_TX_START + parOffTxToSend;

            lastSentTxBuf = (lastSentTxBuf + 1) % NUM_BUF;

            // is this necessary?
            memcpy(tempCharBuf, (void *)rxBufPtr[lastFullRxBuf], AUDIO_BUF_SIZE);
            /*
            **convert char array to short signed int array starting at NH
            */
            unpackMcASPBuf(tempCharBuf, NUM_SAMPLES_PER_AUDIO_BUF, NH, singleChannelInt);
            counter++; //for debugging
            /*
            ** insert previous samples to front of rx frame buffer for FIR filter
            */
            insertPrevSamples(singleChannelInt, previousSamples, NH);
            /*
            ** save trailing NH samples for next frame
            */
            saveTrailingSamples(singleChannelInt, NUM_SAMPLES_PER_AUDIO_BUF, previousSamples, NH);
            /*
            ** convert to sp float for FIR filter
            */
            intToFloat(singleChannelInt, NUM_SAMPLES_PER_AUDIO_BUF + NH, DSPInputSignal);
            /*
            **FIR filter
            */
            DSPF_sp_fir_gen(DSPInputSignal, filterCoefs, DSPOutputSignal, NH, NUM_SAMPLES_PER_AUDIO_BUF );
            /*
            ** convert back to int for txBuf
            */
            floatToInt(DSPOutputSignal, NUM_SAMPLES_PER_AUDIO_BUF, tempIntBuf);
            /*
            ** interleave back into txBuf short int to char conversion
            */
            packMcASPBuf(tempIntBuf, NUM_SAMPLES_PER_AUDIO_BUF, tempCharBuf);
            memcpy((void *)txBufPtr[lastSentTxBuf], tempCharBuf, AUDIO_BUF_SIZE);
            /*
            ** Send the buffer by setting the DMA params accordingly.
            ** Here the buffer to send and number of samples are passed as
            ** parameters. This is important, if only transmit section
            ** is to be used.
            */
            BufferTxDMAActivate(lastSentTxBuf, NUM_SAMPLES_PER_AUDIO_BUF,
      }
}

The functions are:

void insertPrevSamples(short signed int* x, short signed int* p, int np){ //p = previous
        int i=0;
        for(i= 0; i < np - 1 ; ++i)
                x[i] = p[i];
}

void saveTrailingSamples(short signed int* x, int nx, short signed int* p, int np){ //p = previous
        int i=0;
        for(i= 0; i < np - 1; i++)
                p[i] = x[nx + i];
}
void unpackMcASPBuf(unsigned char* x, int nx, int nh, short signed int* y){
    int i=0;
    int indx=0;
    for(i = nh; i < nx + nh; i++){
        y[i]  = x[indx+1] << 8;
        y[i] |= x[indx+0] << 0;
        indx += 8;
    }
}
void packMcASPBuf(short int* in, int size, unsigned char* out){
    int i=0;
    int indx=0;
    int byte0;
    int byte1;
    int byte4;
    int byte5;

    for(i=0; i< size/2; i++){
        out[indx+2] = 0;
        out[indx+3] = 0;
        out[indx+6] = 0;
        out[indx+7] = 0;

        byte0 = ( in[i] >> 0 );
        byte1 = ( in[i] >> 8 );
        byte4 = ( in[i] >> 16 );
        byte5 = ( in[i] >> 24 );

        out[indx+0] = (char)byte0;
        out[indx+1] = (char)byte1;

        out[indx+4] = (char)byte4;
        out[indx+5] = (char)byte5;
        indx += 8;
    }
}

Also included is a waveform showing the corrupted nh-1 samples at the head of the buffer. 

I hope this makes sense and sorry for the lengthy explanation and code.

thank you,

Scott

 

  • The team is notified. They will post their feedback directly here.

    BR
    Tsvetolin Shulev
  • Hi, if anyone has a chance to look at this, please let me know.
    thank you,
    Scott
  • Scott,

    you are referring to the incorrect documentation of the library. Please use DSPLIB C674x for C6748 device.

    http://www.ti.com/tool/SPRC265

    DSPLIB C67x corresponds to previous generation of the DSP (C6700). The User guide(.html) for the C674x DSPLIB is in the package in the docs folder. Open the file and go to API reference section 

    The latest library has a test vectors provided for your reference and the documentation is updated as follows :

    Hope this helps.

    Regards,

    Rahul

  • Thank you for the reply. Unfortunately I don't think this addresses the problem. What I'm wanting to know is how to include previous samples in any function, whether it's a filter, convolution, or any arbitrary function. It's more of an architectural question than a library question. I'm trying to figure out how to include samples from one buffer to another. Each RX buffer consists of a frame of samples, but the buffers do not appear to fill in order. For example, it looks like RXBuffer2 might be filled after RXBuffer0.  The order seems to be random. So I'm wondering if there's a way to determine which buffer is filled. 

    Thank you,

    Scott

  • Scott,

    I do not know what is wrong with your code, but I can try to explain how the process is supposed to work.

    For this example, let nh=3 and nr=5 and the buffer size is 12 to hold two buffers worth of data. Whatever your source of data is, let it start filling at 0.

    Once 2 samples have been stored to 0 & 1, you have your nh-1 'previous samples' saved. After another 5 samples (2-6), you have enough to call DSPF_sp_fir_gen with the input buffer starting at &buffer[0] using those first 7 samples:

    01 23456 789ab

    After 5 more samples have been stored (7-b), you have a second full buffer so you can call DSPF_sp_fir_gen with the input buffer starting at &buffer[5]. The gives you nh-1=2 previous samples and nr=5 for the 2nd call:

    01234 56 789ab

    Your next samples will be stored starting at buffer+nh-1=&buffer[2]. As those samples are coming in, you will be running that second call to DSPF_sp_fir_gen. When the processing is finished, copy the last nh-1 samples a & b to the 'previous samples' at the beginning of the buffer, which would be 0 & 1.

    That last part is what you seemed to be asking in your original post, "Can you help me figure out how to include previous samples in FIR filter. According to the TMS320C67x DSP Library Programmers Ref. Guide SPRU657C, the input array starts at x(-nh+1) and ends at x(nr-1)."

    In the first function call, the input array buffer is defining buffer[0] as x(-nh+1) and the last sample buffer[6] is x(nr-1).

    In the second function call, the input array buffer is defining buffer[5] as x(-nh+1) and the last sample buffer[11(b)] is x(nr-1).

    For the third time, buffer[10] and buffer[11] were copied to the beginning of the buffer as previous samples, with new samples starting at buffer[2]. And it all starts over as the first function call.

    I hope this makes sense. I do not draw good ASCII graphs or charts or such. But you will let me know if this text description helped or confused it all worse (in which case, ... sorry).

    Regards,
    RandyP
  • Hi RandyP, thank you for the explanation. I understand your description in principle, but I don't understand how to implement it with this architecture. 

    Maybe I could use your example to explain how I'm trying to implement FIR/Convolution (or anything that requires previous samples). In the Starterware code, the buffer size is set at nr=2000. Also, the sampling frequency is configured at 48kHz. Therefore, as I understand it, each RxBuffer holds (2000 samples/48kHz) = 41.667ms (approx) worth of data.

    So, the question I have is: how do I process this data? The Starterware code does not indicate how to utilized previous samples, it only show how to use current or future samples.

    For example, with RxBuffer having nr=2000 samples, I'm creating a new buffer of size nr+nh-1, then assigning tempBuffer[nh-1] = RxBuffer[0]. For the first function call, the first tempBuffer[0] to tempBuffer[nh-1] are filled with zeros. But for all subsequent calls to the filter (or convolution, etc), the first nh-1 elements of the array must contain the last nh-1 samples from the previous RxBuffer.

    This last statement is the part where I'm confused. I don't understand how to include the last nh-1 samples from the previous frame buffer of 2000 samples into the current frame buffer.

    Can you please relate this scenario to your example?

    thank you,

    Scott

  • Scott,

    That was the best of an explanation I can come up with. If it does not make sense, I will have to live with that. But it is too difficult to try to take your different definition of buffers and make it fit into mine. My recommendation is to take my explanation using your values for nh & nr. I defined one physical buffer and defined its size. And you start saving samples at the beginning, not by filling the first locations with 0's.

    If that does not work for you, we can see if Rahul has someone else to help you.

    Regards,
    RandyP
  • Hi Randy,

    Thank you  again fro you help. My intent was to make it easier by using your example instead of using the Starterware buffers. But I would prefer to use the Starterware buffers. Can you give your description in terms of the device architecture?

    thank you,

    Scott