2016-07-08 11 views
1

Ich versuche, einen 60kHz Bandpassfilter auf dem STM32F407 Mikrocontroller zu implementieren, und ich habe einige Probleme. Ich habe den Filter mit Hilfe von MATLABs fdatool erzeugt und dann auch in MATLAB simuliert. Das folgende MATLAB-Skript simuliert es.CMSIS FIR Bandpassfilter

% FIR Window Bandpass filter designed using the FIR1 function. 
% All frequency values are in Hz. 
Fs = 5250000; % Sampling Frequency 

N = 1800;  % Order 
Fc1 = 59950; % First Cutoff Frequency 
Fc2 = 60050; % Second Cutoff Frequency 
flag = 'scale'; % Sampling Flag 
% Create the window vector for the design algorithm. 
win = hamming(N+1); 

% Calculate the coefficients using the FIR1 function. 
b = fir1(N, [Fc1 Fc2]/(Fs/2), 'bandpass', win, flag); 
Hd = dfilt.dffir(b); 
%---------------------------------------------------------- 
%---------------------------------------------------------- 
T = 1/Fs;   % sample time 
L = 4500;   % Length of signal 
t = (0:L-1)*T;  % Time vector 

% Animate the passband frequency span 
for f=55500:50:63500 
    signal = sin(2*pi*f*t); 
    plot(filter(Hd, signal)); 
    axis([0 L -1 1]); 

    str=sprintf('Signal frequency (Hz) %d', f); 
    title(str); 
    drawnow; 
end 

pause; 
close all; 

signal = sin(2*pi*50000*t) + sin(2*pi*60000*t) + sin(2*pi*78000*t); 
signal = signal/3; 
signal = signal(1:1:4500); 

filterInput = signal; 
filterOutput = filter(Hd,signal); 

subplot(2,1,1); 
plot(filterInput); 
axis([0 4500 -1 1]); 

subplot(2,1,2); 
plot(filterOutput) 
axis([0 4500 -1 1]); 
pause; 

close all; 

Vom FDATool extrahiere ich die Filter Co-efficents zu 16-Bit-Integer ohne Vorzeichen in q15-Format, dies wegen des ADC 12-Bit, das ich verwende. Der Header des Filterkoeffizienten, der von MATLAB erzeugt wird, ist here, und die resultierende grafische Darstellung der Koeffizienten ist in der folgenden Abbildung zu sehen: Filter co-efficents

Unten ist der Code für die Filterimplementierung, der offensichtlich nicht funktioniert und ich weiß wirklich nicht, was ich tun kann, anders habe ich einige Beispiele Online Example 1 und Example 2 sah

#include "fdacoefs.h" 

#define FILTER_SAMPLES 4500 
#define BLOCK_SIZE  900  

static uint16_t firInput[FILTER_SAMPLES]; 
static uint16_t firOutput[FILTER_SAMPLES]; 
static uint16_t firState[NUM_TAPS + BLOCK_SIZE - 1]; 

uint16_t util_calculate_filter(uint16_t *buffer, uint32_t len) 
{ 
    uint16_t i; 
    uint16_t max; 
    uint16_t min; 
    uint32_t index; 

    // Create filter instance 
    arm_fir_instance_q15 instance; 

    // Ensure that the buffer length isn't longer than the sample size 
    if (len > FILTER_SAMPLES) 
     len = FILTER_SAMPLES; 

    for (i = 0; i < len ; i++) 
    { 
     firInput[i] = buffer[i];   
    } 

    // Call Initialization function for the filter 
    arm_fir_init_q15(&instance, NUM_TAPS, &firCoeffs, &firState, BLOCK_SIZE); 

    // Call the FIR process function, num of blocks to process = (FILTER_SAMPLES/BLOCK_SIZE) 
    for (i = 0; i < (FILTER_SAMPLES/BLOCK_SIZE); i++) // 
    { 
     // BLOCK_SIZE = samples to process per call 
     arm_fir_q15(&instance, &firInput[i * BLOCK_SIZE], &firOutput[i * BLOCK_SIZE], BLOCK_SIZE); 
    } 

    arm_max_q15(&firOutput, len, &max, &index);  
    arm_min_q15(&firOutput, len, &min, &index); 

    // Convert output back to uint16 for plotting 
    for (i = 0; i < (len); i++) 
    { 
     buffer[i] = (uint16_t)(firOutput[i] - 30967); 
    } 

    return (uint16_t)((max+min)); 
} 

Der ADC wird bei 5,25 MSPS Abtasten und es ist ein 60 kHz-Signal 4500 mal abgetastet und hier können Sie sehen, die Input an den Filter und dann die Output des Filters, die ziemlich komisch ist ..

Gibt es etwas offensichtlich, das ich verpasst habe? Weil ich komplett verloren bin und alle Hinweise und Tipps hilfreich sind!

+2

Mit so vielen 'uint16_t'-Berechnungen auf einer 32-Bit-MCU, würde ich sofort verschiedene Überlauf und implizite Promotion Bugs vermuten. Es gibt mehrere Stellen, an denen Ihr Code auf implizite Integer-Promotion angewiesen ist. Das ist normalerweise ein Zeichen für einen Programmierer, der über implizite Promotionen nicht nachdenkt, was wiederum sehr subtile Fehler verursacht. – Lundin

+0

Warum ist es wichtig, dass ich uint16_t-Berechnungen auf einer 32-Bit-MCU verwende? Es gibt Anweisungen zur Handhabung von Halbwörtern und die q15-Werte werden ebenfalls als vorzeichenlose 16-Bit-Werte dargestellt, und der ADC speichert die 12-Bit-Abtastwerte in einem vorzeichenlosen 16-Bit-Puffer, wo findet also die Typumwandlung statt? – Pethead

+2

32-Bit-MCU bedeutet, dass Ihr 'int'-Typ 32 Bit ist, was wiederum bedeutet, dass alle verwendeten kleinen Integer-Typen implizit auf 32-Bit-Typ mit Vorzeichen hochgestuft werden. Dies ist von C vorgeschrieben und hat nichts mit Ihrem spezifischen Prozessor oder Compiler zu tun. Sie müssen lesen, wie Integer-Promotion-Regeln und Balancing ("die üblichen arithmetischen Konvertierungen") funktionieren. [Hier ist eine Erklärung von CERT-C] (https://www.securecoding.cert.org/confluence/display/c/INT02-C.+Understand+integer+conversion+regeln). – Lundin

Antwort

0

Wie Lundin darauf hinwies, habe ich es geändert, um mit 32-Bit-Ganzzahlen zu arbeiten, und das hat tatsächlich mein Problem gelöst. Natürlich habe ich neue Filtereffekte mit MATLABS fdatool als 32 Bit Ganzzahlen mit Vorzeichen generiert.

static signed int firInput[FILTER_SAMPLES]; 
static signed int firOutput[FILTER_SAMPLES]; 
static signed int firState[NUM_TAPS + BLOCK_SIZE -1]; 

uint16_t util_calculate_filter(uint16_t *buffer, uint32_t len) 
{ 
    uint16_t i; 
    int power; 
    uint32_t index; 

    // Create filter instance 
    arm_fir_instance_q31 instance; 

    // Ensure that the buffer length isn't longer than the sample size 
    if (len > FILTER_SAMPLES) 
     len = FILTER_SAMPLES; 

    for (i = 0; i < len ; i++) 
    { 
     firInput[i] = (int)buffer[i];   
    } 

    // Call Initialization function for the filter 
    arm_fir_init_q31(&instance, NUM_TAPS, &firCoeffs, &firState, BLOCK_SIZE); 

    // Call the FIR process function, num of blocks to process = (FILTER_SAMPLES/BLOCK_SIZE) 
    for (i = 0; i < (FILTER_SAMPLES/BLOCK_SIZE); i++) // 
    { 
     // BLOCK_SIZE = samples to process per call 
     //arm_fir_q31(&instance, &firInput[i * BLOCK_SIZE], &firOutput[i * BLOCK_SIZE], BLOCK_SIZE); 
     arm_fir_q31(&instance, &firInput[i * BLOCK_SIZE], &firOutput[i * BLOCK_SIZE], BLOCK_SIZE); 
    } 

    arm_power_q31(&firOutput, len, &power); 

    // Convert output back to uint16 for plotting 
    for (i = 0; i < (len); i++) 
    { 
     buffer[i] = (uint16_t)(firOutput[i] - 63500); 
    } 

    return (uint16_t)((power/10)); 
}