0% found this document useful (0 votes)
97 views6 pages

Sample Adsp

This document describes designing and implementing a finite impulse response (FIR) filter. It discusses: 1) Designing an FIR filter in MATLAB to given specifications using fir2() and quantizing the coefficients using sfi(). 2) The JNI signature needed for a function that accepts a WaveFrame and returns a long. 3) Implementing the filter in C using 16-bit fixed-point arithmetic, and avoiding overflow by scaling the input signal.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
97 views6 pages

Sample Adsp

This document describes designing and implementing a finite impulse response (FIR) filter. It discusses: 1) Designing an FIR filter in MATLAB to given specifications using fir2() and quantizing the coefficients using sfi(). 2) The JNI signature needed for a function that accepts a WaveFrame and returns a long. 3) Implementing the filter in C using 16-bit fixed-point arithmetic, and avoiding overflow by scaling the input signal.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

EESC6367 Lab 4 - Real-Time FIR Filtering, Quantization Effect and Overflow The purpose of this lab is to design and

d implement in C a finite impulse response (FIR) filter on the ARM processor and study the quantization effect and overflow. The previous lab is used again here for collecting audio signal, passing the sampled signal to a C code segment for filtering, and saving the output to a file for analysis. The design of the FIR filter, i.e. generation of filter coefficients, is realized using the MATLAB filter design package. Other packages may be used for the generation of filter coefficients. Filter Design The Parks-McClellan method is used here to design (generate the coefficients) a lowpass filter for the specifications stated below:
rpass = 0.1; rstop = 20; fs = 44100; f = [1600 2400]; a = [1 0]; %passband ripple %stopbad ripple %sampling frequency %cutoff frequencies %desired amplitudes

%compute deviations dev = [(10^(rpass/20)-1)/(10^(rpass/20)+1) 10^(-rstop/20)]; [n,fo,ao,w] = firpmord(f,a,dev,fs); %estimate filter parameters B = firpm(n,fo,ao,w); %filter coefficients

This code creates an array of n+1 double precision filter coefficients. In order to confirm that the filter matches the specifications, a synthesized signal can be used for testing via the following MATLAB code:
ts = 1/fs; %sample time ns = 512; %number of fft points t = [0:ts:ts*(ns-1)]; %generate test signal to verify filter f1 = 750; f2 = 2500; f3 = 3000; x = sin(2*pi*f1*t) + sin(2*pi*f2*t) + sin(2*pi*f3*t); %plot fft of synthesized signal X = abs(fft(x,ns)); X = X(1:length(X)/2); frq = [1:1:length(X)]; subplot(3,1,1); plot(frq*(fs/ns),X); grid on; %plot normalized frequency of filter A = 1; [h,w] = freqz(B,A,512); subplot(3,1,2); plot(w/(2*pi),10*log(abs(h)));

grid on; %plot fft of filtered signal Y = filter(B,A,x); Y = abs(fft(Y,ns)); Y = Y(1:length(Y)/2); frq = [1:1:length(Y)]; subplot(3,1,3); plot(frq*(fs/ns),Y); grid on;

Filter Implementation An FIR filter simply consists of a list of coefficients which are multiplied by current and past signal sample values. FIR filtering does not involve dependency on previous output values. For a filter with N+1 coefficients, the output y(n) based on the input signal x(n) gets computed as follows: ( ) ( )

This method requires that one keeps a memory of previous signal values. If processing is performed on framed segments of M input signal samples, the calculation requires access to N+1+M sample values. This can be accomplished by allocating a static buffer of memory in the native C code and copying the input values to this buffer before processing is performed. Since the buffer is allocated statically, it will be available for subsequent calls to the filtering code. The lab report stated at the end of this documentation involves the C code implementation of this filter. A base Android application project is provided which can be used to insert C code into. Note that the previous labs provided the floating-point C code implementation. Java Native Interface It is required that a Java class be created to store the native method declarations (Filters.java is used in the code provided). A typical method declaration is shown below:
public static native float[] compute(short[] in);

This method declaration matches with the C code segment that computes the FIR filter output. You may notice that the method naming in the C code is different than in the previous labs. For this revision of the code, we consider the method of using the JNI_OnLoad function. This function specifies code that is meant to be run when Java loads a library containing native code. Here, JNI_OnLoad takes care of registering the native methods with the virtual machine. Although it is still necessary to include the JNIEnv and jobject parameters in the native methods, one does not have to use a fully qualified naming format. The JNI_OnLoad code is shown below:
jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; jint result; //get a hook to the environment result = (*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6); if (result == JNI_OK) { //find the java class to hook the native methods to jclass filters = (*env)->FindClass(env, "com/dsp/firfilter/Filters"); if (filters != NULL) { result = (*env)->RegisterNatives(env, filters, nativeMethods, 3); (*env)->DeleteLocalRef(env, filters); if(result == JNI_OK){ return JNI_VERSION_1_6; } else { //something went wrong with the method registration return JNI_ERR; } } else { //class wasn't found return JNI_ERR; } } else { //could not get environment

return JNI_ERR; } }

The RegisterNatives function takes a Java class to which the C functions will be linked, an array of native method definitions (shown below), and the number of functions to register.
static JNINativeMethod nativeMethods[] = {// Name Signature {"compute", "([S)[S", {"initialize", "(I)V", {"finish", "()V", }; Pointer (void *)&compute (void *)&initialize (void *)&finish

}, }, }

The Name column specifies the functions name as declared in the Filters.java class. The Pointer column contains a pointer to the native function. The Signature column matches input and output types in Java. Input arguments are enclosed in parenthesis, and the return type is specified to the right of the parenthesis. A chart showing the shorthand convention for defining a signature is shown below: Type Signature V Z B C S I J F D Lfully-qualified-class; [<type signature> Java Type void boolean byte char short int long float double fully-qualified-class <Java type>[]

The fully qualified class case can be used to pass along Java types that one creates from the Java specifications. In addition to the nativeMethods signatures shown above, a few examples are shown in the table below: Java Method
String toLower(String other) void sort(String [] names) double[][] collect()

Type Signature (Ljava/lang/String;) Ljava/lang/String; ([Ljava/lang/String;)V ()[[D

Within the C code, the JNI native method always has the first two parameters as JNIEnv and jobject. Any other variables passed along to the method follow afterwards. Primitive data types can be passed along using JNI. Single and multi-dimensional arrays can also be passed, as detailed in the Array Handling

section. Primitive data types do not need special treatment when used in the native code. The following table contains a few examples of different data types and their corresponding JNI naming: Java double float long int short boolean float[] float[][] JNI jdouble jfloat jlong jint jshort jboolean jfloatarray jobjectarray C double float long int short int float * float **

Array Handling Arrays from Java contain extra information such as length and need to be pinned to a pointer for access by using the JNIEnv interface as indicated below:
float *cArray = (*env)->GetFloatArrayElements(env, javaArray, NULL);

If a pointer cannot be obtained for the data on the Java heap, the contents of the array will be copied into an alternate memory location and that pointer will be returned. For accessing a two-dimensional array, one needs to have:
jfloatArray java1dArray = (*env)->GetObjectArrayElement(env, java2dArray, i); float *cArray = (*env)->GetFloatArrayElements(env, java1dArray, NULL);

When the data is used, the array should be unpinned as indicated below so that Java can resume garbage collection:
(*env)->ReleaseFloatArrayElements(env, javaArray, cArray, 0);

To save the overhead of passing the length of an array as a separate variable, the length is obtained using the JNIEnvs getArrayLength method as follows:
int size = (int) (*env)->GetArrayLength(env, javaArray);

Lab 4 Report Part 1: Using MATLAB, design an FIR filter according to the following specifications:
f = [0 600 1000 1400 2000 4000]; a = [1.25 2 1 .25 0.1 0]; ntaps = 64; %frequencies (0 to nyquist) %desired amplitude response %number of filter coefficients

by using the fir2() function of MATLAB. Next, quantize the filter by using the MATLAB fixed-point toolboxs sfi() function. For example, if coeffs denotes double precision filter coefficients, ficoeffs = sfi(coeffs,bits,bits-1) can be used to convert to quantized values with bits wordlength. To retrieve quantized coefficients, the function ficoeffs.data can be used. Test your filter using the signal: chirp(t,0,ts*ns,fs/2) with ns equal to 256 samples. Determine the minimum number of bits needed to represent the coefficients such that the maximum absolute error of the filter is less than five percent. Part 2: State what would be the type signature of a JNI function that accepts a WaveFrame as input and returns a long value. Part 3: Implement the filter in C using 16bits for the coefficients and for the input samples. All the computations must be performed using fixed-point representation. The filter output may get overflowed due to the multiplications and summations involved in the FIR filtering equation. The most effective way to avoid overflow is by scaling down the input signal magnitude before filtering and then reversing the process when the output is returned. Keep scaling the input signal samples by a scaling factor less than one (a scaling factor 0.5 can be simply achieved by left shifting) until the overflow disappears. Apply your filter to the test signal provided on eLearning and submit the text file debug output along with your report as you did in Lab 2.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy