2016-07-08 3 views
1

STM32F407 마이크로 컨트롤러에 60kHz 대역 통과 필터를 구현하려고하는데 몇 가지 문제가 있습니다. MATLAB fdatool의 도움을 받아 필터를 생성 한 다음 MATLAB에서도 시뮬레이션했습니다. 다음 MATLAB 스크립트는이를 시뮬레이트합니다. FDATool을에서 CMSIS FIR 대역 통과 필터

% 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; 

나는이 때문에 내가 사용하고 12 비트 ADC의, Q15 형식으로 16 비트 부호없는 정수로 필터 공동 efficents의 압축을 풉니 다. MATLAB에서 생성 된 필터 계수 헤더는 here이고 그 결과 생성 된 계수는 다음 그림에서 확인할 수 있습니다. Filter co-efficents

다음은 분명히 작동하지 않는 필터 구현을위한 코드입니다. 정말 다른 무엇을 할 수 있는지 모른다, 나는 ADC는 5.25 MSPS에서 샘플링과는 60kHz 신호를 4500 번 샘플링 여기 당신이 볼 수있는 온라인 몇 가지 예를 Example 1

#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)); 
} 

Example 2을 검토 한 필터에 Input을 입력하고 꽤 이상한 필터 Output을 입력하십시오.

제가 놓친 부분이 있습니까? 나는 완전히 잃어버린 포인터와 팁이 도움이되기 때문에!

+2

32 비트 MCU에서 'uint16_t'계산이 너무 많아서 다양한 오버플로 및 암시 적 프로모션 버그가 의심됩니다. 코드가 암시 적 정수 승격에 의존하는 곳이 몇 군데 있습니다. 이것은 일반적으로 암시 적 프로모션에 대해 고려하거나 알지 못하는 프로그래머의 기호이며, 이는 차례로 매우 미묘한 버그를 만듭니다. – Lundin

+0

32 비트 MCU에서 uint16_t 계산을 사용하는 것이 왜 중요합니까? 하프 워드를 처리하기위한 지침이 있으며 q15 값은 16 비트 부호없는 값으로 표시되며 ADC는 12 비트 샘플을 부호없는 16 비트 버퍼에 저장하므로 형식 변환은 어디에서 발생합니까? – Pethead

+2

32 비트 MCU는 'int'타입이 32 비트임을 의미하며, 이는 사용하는 모든 작은 정수 타입이 암시 적으로 32 비트 부호 유형으로 승격된다는 것을 의미합니다. 이것은 C에 의해 위임되어 있으며 특정 프로세서 나 컴파일러와 관련이 없습니다. 정수 승격 규칙 및 균형 조정 ("일반적인 산술 변환")이 작동하는 방법을 읽어야합니다. [CERT-C의 설명은 다음과 같습니다] (https://www.securecoding.cert.org/confluence/display/c/INT02-C.+Understand+integer+conversion+rules). – Lundin

답변

0

Lundin이 지적했듯이 나는 대신 32 비트 정수로 작업하도록 변경했으며 실제로 문제를 해결했습니다. Ofcourse는 대신 MATLABS fdatool을 사용하여 32 비트 정수로 서명 된 새 필터 공동 효과를 생성했습니다.

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)); 
} 
관련 문제