Hi,
I'm trying to use the filter and fft functions (listed in the filter.h file).
fir_fr16 and rfft_fr16 are the ones giving me problems at the moment.
I'm very confused about the syntax, and how to use the functions themselves.
Could somebody please help me out with this?
Specifically: How do you define the inputs: if I have data coming in, I can't define it at type "const", because it needs to be a variable.
Also, the help file lists:
#typedef struct
#{
# fract16 *h, /* filter coefficients */
# fract16 *d, /* start of delay line */
# fract16 *p, /* read/write pointer */
# int k; /* number of coefficients */
# int l; /* interpolation/decimation index */
#} fir_state_fr16;
whilst the header file lists:
typedef struct
{
fract16 *h; /* filter coefficients */
fract16 *d; /* start of delay line */
fract16 *p; /* read/write pointer */
int k; /* number of coefficients */
int l; /* interpolation/decimation index */
} _fir_fr16_state;
As you can see, these two are differently named.
This is just for fir_fr16. I also need to be able to use fft's and ifft's, so if anybody can help me out with those too, I'd much appreciate it.
I'm completely lost as to what need to be input/output to make these functions work.
Learning by examples ![]()
$(VDSP)\Blackfin\Examples\No Hardware Required\FIR Filter (C)\
$(VDSP)\Blackfin\Examples\Tutorial\fir\
I've figured out how to use rfft... However, the output is scaled.
Is there any way to get an unscaled output? Originally, in matlab, my fft's go up to values of about 100...
How can I accomplish the same thing on the DSP?
Thanks.
Alternatively, I could scale the matlab code to do the same thing as the rfft_fr16 code.
Could anybody confirm for me what exactly the scaling in the rfft_fr16 code does?
I understand it as: Divide by two if the maximum value is greater than 0.5... I don't see how this will prevent overflow though, as the value of the fft output may be much greater than 1 (ie: 100), in which case, scaling it by 0.5 will only bring it down to 50, which will still saturate...
Maybe I'm understanding it wrong, so how do each of the scaling methods work? Obviously, no scaling = Saturate if over 1. But what about the other two cases? How specifically, do they work?
Thanks.
Hi David,
Before I answer your question(s), could I just check that we are both using the same terminology?
The fir_f16 and rfft_f16 library functions operate on data of type fract16. The fract16 data type is used to represent 16-bit fixed-point data in the range from 0.999996 to -1.0. It is different from floating-point because by convention the decimal point always appear to the left of the left-most binary digit.
Compare this to a regular 16-bit integer value which is used to represent values in the range 32767 to -32768; here the decimal point is always to the right of the right-most digit. So 0x7FFF represents the integer value 32767 and the fract16 value 0.999996 (also, for example, 0x4000 is the integer value 16384 or the fract16 value 0.5).
So when you say "in matlab, my fft's go up to values of about 100..." do you mean the floating-point value "100.0" or do you mean the integer "100" (which has the effective value of 0.00305 when assigned to a fract16)?
Let me know, okay?
Hi,
I too have the same problem. I am trying to implement fft using the rfft_fr16. I get that since it is a fixed point function I need to used fixed point values which I get using float_to_fr16... here is a sinppet of the code
for(i=0;i<FFTSIZE;i++)
{
in[i]=float_to_fr16(input[i]);
}
/* Initialize the twiddle factors */
twidfft_fr16(twiddle, FFTSIZE);
/* Perform FFT */
rfft_fr16(in,out, twiddle, 1, FFTSIZE, 0, 2);
for(i=0;i<FFTSIZE;i++)
{
realf[i]=(out[i].re);
}
for(i=0;i<FFTSIZE;i++)
{
imagf[i]=(out[i].im);
}
for(i=0;i<FFTSIZE;i++)
{
real[i]=fr16_to_float(realf[i]);
imag[i]=fr16_to_float(imagf[i]);
}
Now I compare by plotting "real" with matlabs fft real values. I am getting a scaled version of the matlab values in adsp...why is that. I tried using cfft_fr16 but it gave the same result.
I have attached two images which clearly show what I am rambling about. Could someone please explain it to me???
Hi There,
I think that I can answer your question, but before I do could I first point out a couple of problems with your code snippet? The first problem is that you should be using the library function twidfftrad2_fr16 instead of twidfft_fr16; the function twidfft_fr16 will generate a twiddle table for the legacy functions cfftrad4_fr16, ifftrad4_fr16, and rfftrad4_fr16. By using this function in your application you should notice that the imaginary component of the FFT that you generate will not be correct. So you should use:
complex_fract16 twiddle[FFTSIZE/2];
twidfftrad2_fr16 (twiddle,FFTSIZE);
instead of:
complex_fract16 twiddle[(3*FFTSIZE)/4];
twidfft_fr16 (twiddle,FFTSIZE);
The second problem that I can see relates directly to the question that you are asking. The 6'th argument of rfft_fr16 is defined as a pointer to an integer, but you have specified it as '0'; correcting this error will not modify the FFT that rfft_fr16 generates but it will help you interpret the FFT. For example, instead of:
rfft_fr16(in,out, twiddle, 1, FFTSIZE, 0, 2);
use the following:
int block_exponent;
rfft_fr16(in,out, twiddle, 1, FFTSIZE, &block_exponent, 2);
Now to answer your question:
During the computation of an FFT there is a risk with fixed-point arithmetic that intermediate computations will overflow and generate saturated results, and this will obviously affect the quality of the generated output. To avoid the risk of overflow, the FFT function will have to scale intermediate results. For a given FFT, there are 'log2(FFTSIZE)' intermediate set of results, and one option is to unconditionally divide each set of intermediate results by 2 - this option is called static scaling and will result in an FFT that has been scaled by log2(FFTSIZE). Static scaling is cheap to implement on the Blackfin architecture but it can lead to a loss of precision particularly for larger FFT sizes. An alternative scaling method is known as dynamic scaling, and under dynamic scaling intermediate results are inspected and are only scaled if there is a risk that these intermediate results may cause overflow. Dynamic scaling is slower than static scaling but generally it results in a more accurate FFT.
The user selects which scaling method should be used via the 7'th argument of the rfft_fr16 function; this argument is called 'scale_method'. If the argument is set to either 0 (zero) or 1, then the function will perform static scaling; if it is set to 2 (as in your example) the function will perform dynamic scaling. If one is sure that that the FFT function will not generate a saturated result, then one can set the scale_method argument to 3, in which case the function will never scale intermediate results and there will be no loss of precision in the generated output.
To properly interpret the output from the rfft_fr16 function, one needs to know how many times the library function has scaled the intermediate results. This is particularly important for dynamic scaling and this is where the 6'th argument (known as the block exponent argument) is so important.
Before returning to your program, the FFT function will set the block exponent argument to the number of intermediate results that it has scaled (i.e. divided by 2). If static scaling has been selected, then the block_exponent argument will be set to log2(FFTSIZE), if no scaling has been selected then the block_exponent argument will be set to zero. If dynamic scaling has been specified then the block_exponent argument will be set to the number of times each set of intermediate results have be scaled - this will be some value between zero and log2(FFTSIZE).
So to check that MATLAB and rfft_fr16 generate similar FFTs, you should change the following code (at the end of your snippet):
for(i=0;i<FFTSIZE;i++)
{
real[i]=fr16_to_float(realf[i]);
imag[i]=fr16_to_float(imagf[i]);
}
to:
for(i=0;i<FFTSIZE;i++)
{
real[i]=fr16_to_float(realf[i])*ldexpf(1.0F,block_exponent);
imag[i]=fr16_to_float(imagf[i])*ldexpf(1.0F,block_exponent);
}
PS: I see that you are using version 5.0 of VisualDSP++, but I have a word of caution to anyone who is interested in this reply and is only
using Version 4.5 of VisualDSP++ (or earlier). The cfft_fr16, ifft_fr16, and rfft_fr16 library functions in the earlier releases only support static scaling and do not return a block exponent. The interface to these functions has been modified for version 5.0 of VisualDSP++.