Em sistemas embarcados, o processamento de sinais é uma etapa fundamental para extrair informações úteis de sensores ruidosos ou sinais analógicos digitalizados. Um sistema de aquisição de dados, por exemplo, raramente trabalha com sinais puros: leituras de sensores sofrem interferências eletromagnéticas, ruídos térmicos ou distorções causadas por componentes eletrônicos. Filtros digitais são técnicas matemáticas e computacionais aplicadas para atenuar esses ruídos, isolar frequências específicas ou prever valores futuros com base em medições passadas.
Este artigo abordará uma variedade de filtros, desde os mais simples e amplamente usados, como a Média Móvel (Moving Average), até técnicas mais sofisticadas como o Filtro de Kalman. Cada técnica será apresentada com sua motivação, estrutura matemática e exemplos de implementação prática em C ou pseudo-C para microcontroladores. O objetivo é tornar o tema acessível mesmo para quem está iniciando no campo do processamento digital de sinais, mas também útil a profissionais buscando soluções eficazes e eficientes para aplicações em tempo real.
Filtro de Média Móvel
O filtro de média móvel é uma das técnicas mais simples e intuitivas para suavizar sinais ruidosos. Ele funciona como uma janela deslizante que calcula a média dos últimos N valores de entrada. Por sua simplicidade, é amplamente utilizado em sistemas embarcados com recursos computacionais limitados, como sensores de temperatura, pressão, ou leitura de sinais analógicos via ADC (Conversor Analógico-Digital).
Problema Resolvido
Sinais adquiridos por sensores frequentemente contêm flutuações indesejadas — ruídos de alta frequência — que podem dificultar decisões ou controles baseados nesses dados. O filtro de média móvel reduz essas flutuações ao suavizar o sinal, permitindo uma resposta mais estável em aplicações como termostatos, sistemas de controle de motor, ou leitura de biossensores.
Estrutura Matemática
A média móvel simples é definida pela fórmula: \[y[n] = \frac{1}{N} \sum_{i=0}^{N-1} x[n-i]\]
onde:
- y[n] é o valor filtrado no instante n,
- x[n] é a amostra de entrada no instante n,
- N é o tamanho da janela de média.
Exemplo de Código em C
#include <stdint.h>
#define WINDOW_SIZE 8
typedef struct {
int16_t buffer[WINDOW_SIZE];
uint8_t index;
int32_t sum;
} MovingAverageFilter;
void initFilter(MovingAverageFilter *filter) {
for (int i = 0; i < WINDOW_SIZE; i++)
filter->buffer[i] = 0;
filter->index = 0;
filter->sum = 0;
}
int16_t updateFilter(MovingAverageFilter *filter, int16_t newValue) {
// Subtrai o valor mais antigo da soma
filter->sum -= filter->buffer[filter->index];
// Armazena o novo valor
filter->buffer[filter->index] = newValue;
// Adiciona o novo valor à soma
filter->sum += newValue;
// Move o índice circular
filter->index = (filter->index + 1) % WINDOW_SIZE;
// Retorna a média
return (int16_t)(filter->sum / WINDOW_SIZE);
}
Análise
Este filtro apresenta desempenho estável e implementação eficiente, sem necessidade de operações complexas como multiplicações ou divisões em ponto flutuante (exceto pela divisão final, que pode ser otimizada via deslocamento quando NNN é potência de 2). Contudo, sua resposta a variações rápidas do sinal é lenta, pois ele tende a “amortecer” transientes, tornando-o inadequado para sistemas que exigem alta reatividade.
Aplicações Típicas
- Leitura de sensores analógicos com ruído ambiente
- Suavização de variações de corrente em fontes chaveadas
- Estabilização de sinais de entrada em filtros digitais mais complexos
Filtro Exponencial (Média Móvel Exponencial)
O filtro exponencial, também conhecido como filtro de primeira ordem ou filtro IIR de coeficiente simples, é uma alternativa ao filtro de média móvel que introduz uma ponderação decrescente nas amostras anteriores. Em vez de considerar todos os valores com o mesmo peso, como no filtro de média móvel simples, ele dá mais importância às amostras mais recentes, o que permite uma resposta mais ágil às variações do sinal.
Problema Resolvido
O filtro de média móvel tradicional tende a atrasar a resposta do sistema quando a janela é grande. O filtro exponencial resolve esse problema permitindo um controle mais refinado sobre a “inércia” do filtro. Ele é particularmente útil quando é necessário suavizar sinais sem causar atrasos excessivos, como em leitura de sensores em tempo real, entrada de joysticks, ou medições de corrente em fontes chaveadas.
Estrutura Matemática
O filtro exponencial é definido pela equação de diferença: \[y[n] = \alpha \cdot x[n] + (1 – \alpha) \cdot y[n-1]\]
onde:
- y[n] é a saída filtrada no tempo nnn,
- x[n] é a entrada no tempo nnn,
- \(\alpha \in (0, 1)\) é o coeficiente de suavização: quanto mais próximo de 1, mais peso a nova entrada terá (resposta rápida); quanto mais próximo de 0, mais lenta e suave será a resposta.
Exemplo de Código em C
cCopiarEditar#include <stdint.h>
typedef struct {
float alpha;
float output;
} ExponentialFilter;
void initExponentialFilter(ExponentialFilter *filter, float alpha) {
filter->alpha = alpha;
filter->output = 0.0f;
}
float updateExponentialFilter(ExponentialFilter *filter, float input) {
filter->output = filter->alpha * input + (1.0f - filter->alpha) * filter->output;
return filter->output;
}
Versão para Inteiros (sem ponto flutuante)
Para microcontroladores sem FPU (Unidade de Ponto Flutuante), pode-se usar uma versão com inteiros, escalando os valores:
cCopiarEditar#include <stdint.h>
#define ALPHA_FIXED 32 // Ex: 32 representa 0.125 se o fator de escala for 256
#define SCALE 256
typedef struct {
int32_t output;
} ExpFilterFixed;
int16_t updateExpFilterFixed(ExpFilterFixed *filter, int16_t input) {
filter->output = (ALPHA_FIXED * input + (SCALE - ALPHA_FIXED) * filter->output) / SCALE;
return (int16_t)filter->output;
}
Análise
O filtro exponencial possui resposta mais rápida do que a média móvel para o mesmo nível de suavização. Seu atraso de grupo é menor e o consumo de memória é reduzido, pois não é necessário armazenar buffers. Contudo, ele possui “memória infinita”, ou seja, o valor passado nunca desaparece completamente — o que pode ser uma desvantagem em alguns casos, como em detecção de transientes.
Aplicações Típicas
- Filtros de ruído para sinais de sensores IMU (Acelerômetro/Giroscópio)
- Suavização de sinais de controle em robôs e drones
- Filtros de corrente em fontes chaveadas com resposta rápida
- Modelagem de resposta térmica em sistemas com controle PID
Filtro de Média Ponderada (Janela com Pesos Customizados)
O filtro de média ponderada é uma generalização do filtro de média móvel, onde cada amostra na janela recebe um peso diferente. Essa abordagem permite maior controle sobre quais partes do sinal têm maior influência na saída filtrada. O uso de pesos permite ajustar o filtro para atender a diferentes requisitos de resposta, como reduzir o ruído sem atenuar mudanças rápidas relevantes.
Problema Resolvido
Sinais que contêm ruídos esporádicos ou picos indesejados (outliers) podem afetar significativamente a média simples. A média ponderada, ao atribuir menos peso a amostras mais antigas (ou potencialmente mais ruidosas), permite que o sistema reaja de forma mais eficiente a mudanças reais sem ser tão suscetível a ruídos momentâneos. É especialmente útil quando o sistema exige suavização, mas sem perder a capacidade de detectar transições.
Estrutura Matemática
A média ponderada é definida como: \[y[n] = \frac{\sum_{i=0}^{N-1} w_i \cdot x[n-i]}{\sum_{i=0}^{N-1} w_i}\]
onde:
- \(w_i\) é o peso atribuído à iii-ésima amostra da janela,
- x[n−i] é a iii-ésima amostra mais recente,
- N é o tamanho da janela.
Exemplo de pesos com ênfase nas amostras mais recentes: w={1,2,3,4}w = \{1, 2, 3, 4\}w={1,2,3,4}
Exemplo de Código em C
#include <stdint.h>
#define WINDOW_SIZE 4
typedef struct {
int16_t buffer[WINDOW_SIZE];
uint8_t index;
} WeightedAverageFilter;
const uint8_t weights[WINDOW_SIZE] = {1, 2, 3, 4}; // pesos: mais recente tem maior peso
int16_t updateWeightedFilter(WeightedAverageFilter *filter, int16_t newValue) {
filter->buffer[filter->index] = newValue;
filter->index = (filter->index + 1) % WINDOW_SIZE;
int32_t weightedSum = 0;
int32_t weightTotal = 0;
uint8_t idx = filter->index;
for (uint8_t i = 0; i < WINDOW_SIZE; i++) {
idx = (idx == 0) ? WINDOW_SIZE - 1 : idx - 1;
weightedSum += filter->buffer[idx] * weights[i];
weightTotal += weights[i];
}
return (int16_t)(weightedSum / weightTotal);
}
Análise
O filtro de média ponderada oferece maior flexibilidade que a média móvel simples, com custo computacional ligeiramente superior. Ele é eficaz para eliminar ruídos do tipo “espeto” (spike noise) e ao mesmo tempo manter a capacidade de rastrear tendências. Sua eficiência depende da escolha apropriada dos pesos — os quais podem ser lineares, exponenciais ou customizados para a aplicação.
Aplicações Típicas
- Suavização de sinais de sensores em ambientes ruidosos
- Pré-processamento de sinais em sistemas de classificação (ex: ECG, EMG)
- Estabilização de leituras em interfaces homem-máquina (joysticks, sliders, etc.)
- Leitura de sinais analógicos sujeitos a distorções temporárias
Filtro Mediano (Median Filter)
O filtro mediano é uma técnica não linear de processamento de sinais especialmente eficaz na remoção de ruídos impulsivos, como picos isolados (outliers) que podem ocorrer em medições físicas. Diferentemente da média móvel, ele não suaviza gradualmente o sinal, mas substitui o valor central de uma janela de amostras pela mediana — o valor que está no meio quando os dados são ordenados. Isso o torna ideal para preservar bordas e transições bruscas enquanto elimina ruídos esporádicos.
Problema Resolvido
Em sistemas embarcados que realizam medições sujeitas a interferências eletromagnéticas, conexões instáveis ou saltos ocasionais de leitura (por exemplo, sensores de distância ultrassônicos, sensores de corrente em ambientes industriais ou dados de visão computacional embarcada), a presença de picos pode prejudicar decisões e controles. O filtro mediano elimina essas perturbações preservando a integridade do sinal real.
Estrutura Matemática
Para uma janela de tamanho NNN, o filtro ordena as amostras e seleciona a mediana: \[y[n] = \text{median}(x[n – (N-1)/2], …, x[n], …, x[n + (N-1)/2])\]
Onde:
- y[n] é a saída filtrada,
- x[n] é a amostra no tempo nnn,
- A mediana é o valor central da sequência ordenada.
Exemplo de Código em C (Janela de 5 Amostras)
#include <stdint.h>
#define WINDOW_SIZE 5
typedef struct {
int16_t buffer[WINDOW_SIZE];
uint8_t index;
} MedianFilter;
void insertValue(MedianFilter *filter, int16_t value) {
filter->buffer[filter->index] = value;
filter->index = (filter->index + 1) % WINDOW_SIZE;
}
int compare(const void *a, const void *b) {
return (*(int16_t*)a - *(int16_t*)b);
}
int16_t getMedian(MedianFilter *filter) {
int16_t temp[WINDOW_SIZE];
for (int i = 0; i < WINDOW_SIZE; i++)
temp[i] = filter->buffer[i];
qsort(temp, WINDOW_SIZE, sizeof(int16_t), compare);
return temp[WINDOW_SIZE / 2];
}
Uso Típico
cCopiarEditarMedianFilter filter = {{0}, 0};
void loop() {
int16_t newSample = read_adc();
insertValue(&filter, newSample);
int16_t cleanValue = getMedian(&filter);
// Use cleanValue no controle ou visualização
}
Análise
Embora seja mais robusto a ruídos extremos, o filtro mediano tem maior custo computacional do que os filtros baseados em média. O uso de qsort()
pode ser otimizado com algoritmos específicos para mediana de 3, 5 ou 7 valores, comuns em sistemas embarcados. Ele não distorce o sinal original em regiões com variação suave e é muito eficaz para rejeitar ruídos impulsivos. No entanto, seu uso não é adequado para sistemas que exigem filtragem de ruído gaussiano ou precisão em pequenas variações.
Aplicações Típicas
- Sensores ultrassônicos ou infravermelhos com ruído espúrio
- Processamento de imagem (eliminação de pixels corrompidos)
- Sensores analógicos de baixo custo (temperatura, corrente, tensão)
- Filtragem de sinais biológicos (ex: ECG, EMG) em sistemas embarcados
Filtro de Kalman
O Filtro de Kalman é um algoritmo matemático sofisticado para estimar o estado de um sistema dinâmico a partir de medições ruidosas. Ele é amplamente utilizado em sistemas embarcados para fusão sensorial (como em IMUs), navegação, robótica e controle adaptativo. Ao contrário dos filtros tradicionais, o Kalman considera não só os valores observados, mas também as incertezas associadas tanto ao modelo quanto às medições, fazendo previsões e correções iterativas.
Problema Resolvido
Em muitos sistemas embarcados, as medições de sensores apresentam ruído, e o modelo do sistema também pode ser incerto. O filtro de Kalman resolve esse problema ao estimar o “verdadeiro estado” do sistema — mesmo que ele não seja diretamente observável — usando uma abordagem estatística baseada em modelos. É ideal para casos em que múltiplas fontes de dados devem ser integradas (por exemplo, acelerômetro + giroscópio) ou quando o sistema sofre variações lentas mas importantes.
Estrutura Matemática (Kalman 1D)
O modelo básico de um sistema linear com ruído aditivo é:
Modelo de estado: \[\hat{x}_{k|k-1} = \hat{x}_{k-1|k-1}\]
Atualização da incerteza: \[P_{k|k-1} = P_{k-1|k-1} + Q\]
Ganho de Kalman: \[K_k = \frac{P_{k|k-1}}{P_{k|k-1} + R}\]
Atualização com medição \(z_k\): \[\hat{x}_{k|k} = \hat{x}_{k|k-1} + K_k (z_k – \hat{x}_{k|k-1})\]\[P_{k|k} = (1 – K_k) P_{k|k-1}\]
Onde:
- \(\hat{x}\): estimativa do estado
- P: incerteza da estimativa
- Q: variância do ruído do processo
- R: variância do ruído de medição
- K: ganho de Kalman
Exemplo de Código em C (Kalman 1D)
typedef struct {
float x; // Estado estimado
float p; // Incerteza da estimativa
float q; // Variância do processo
float r; // Variância da medição
float k; // Ganho de Kalman
} KalmanFilter;
void initKalman(KalmanFilter *kf, float q, float r, float p, float initial_value) {
kf->q = q;
kf->r = r;
kf->p = p;
kf->x = initial_value;
}
float updateKalman(KalmanFilter *kf, float measurement) {
// Predição
kf->p = kf->p + kf->q;
// Atualização
kf->k = kf->p / (kf->p + kf->r);
kf->x = kf->x + kf->k * (measurement - kf->x);
kf->p = (1 - kf->k) * kf->p;
return kf->x;
}
Análise
O filtro de Kalman é altamente eficiente, com custo computacional linear, sendo perfeitamente viável em microcontroladores de 32 bits (como Cortex-M). Sua força está em sua capacidade de combinar medições ruidosas com previsões baseadas em modelos, gerando uma estimativa mais precisa do que qualquer medição individual. Ele também pode ser estendido para sistemas multivariados (Kalman Multidimensional) e sistemas não-lineares (Filtro de Kalman Estendido).
Aplicações Típicas
- Fusão de sensores (Ex: acelerômetro + giroscópio + magnetômetro)
- Rastreamento de posição e velocidade (GPS com odometria)
- Controle de sistemas com estados não diretamente observáveis
- Estimativas adaptativas de variáveis físicas em fontes chaveadas (tensão, corrente, temperatura)
Filtro de Kalman Estendido (Extended Kalman Filter – EKF)
O Filtro de Kalman Estendido (EKF) é uma extensão do Filtro de Kalman tradicional voltada a sistemas não-lineares. Em vez de assumir que o sistema e o modelo de medição são lineares, o EKF utiliza uma aproximação local por meio da linearização com séries de Taylor, aplicando a lógica do Kalman sobre uma versão linearizada do sistema.
Problema Resolvido
Muitos sistemas físicos reais possuem comportamentos não-lineares: medição de ângulos, sensores de corrente baseados em campo magnético (como Hall), sistemas com dinâmica de rotação ou filtros para sensores de posição em robótica. O Filtro de Kalman tradicional não pode lidar corretamente com não-linearidades. O EKF permite aplicar as ideias do Kalman em sistemas que possuem modelos descritos por funções arbitrárias.
Estrutura Matemática (Resumo)
Dado um sistema modelado por: \[x_k = f(x_{k-1}, u_{k-1}) + w_{k-1}\]\[z_k = h(x_k) + v_k\]
Onde:
- \(f(\cdot)\): modelo de transição de estado (não-linear)
- \(h(\cdot)\): modelo de observação (não-linear)
- w e v: ruídos de processo e medição (gaussianos)
A linearização é feita por meio das matrizes Jacobianas:
- \(F_k = \frac{\partial f}{\partial x}\), avaliada em \(\hat{x}_{k-1}\)
- \(H_k = \frac{\partial h}{\partial x}\), avaliada em \(\hat{x}_{k|k-1}\)
Ciclo do EKF
- Predição: \[\hat{x}_{k|k-1} = f(\hat{x}_{k-1}, u_{k-1})\] \[\[P_{k|k-1} = F_k P_{k-1} F_k^T + Q\]
- Atualização: \[K_k = P_{k|k-1} H_k^T (H_k P_{k|k-1} H_k^T + R)^{-1}\]\[\hat{x}_{k} = \hat{x}_{k|k-1} + K_k (z_k – h(\hat{x}_{k|k-1}))\]\[P_k = (I – K_k H_k) P_{k|k-1}\]
Exemplo de Aplicação: Estimativa de Ângulo com Sensor de Giro
// Modelo simplificado do EKF aplicado a sensor de ângulo com giroscópio
float x = 0; // ângulo estimado
float p = 1;
float q = 0.01; // ruído do processo
float r = 0.1; // ruído da medição
float ekf_update(float z, float gyroRate, float dt) {
// Predição
x += gyroRate * dt; // f(x) = x + w*dt
p += q;
// Jacobiano H = 1 para h(x) = x (medição direta)
float k = p / (p + r); // Kalman Gain
x += k * (z - x); // Atualização
p = (1 - k) * p;
return x;
}
Análise
O EKF é uma solução poderosa, mas exige maior capacidade computacional devido ao cálculo de derivadas (Jacobianas) e multiplicações matriciais. Sua precisão depende fortemente da qualidade das aproximações lineares — erros de modelagem ou suposições ruins podem degradar a estimativa. Ainda assim, o EKF é amplamente usado em sistemas embarcados modernos com suporte matemático básico (por exemplo, ARM Cortex-M4 com FPU).
Aplicações Típicas
- Navegação de robôs móveis (composição entre odometria e GPS)
- Estimativa de atitude (roll/pitch/yaw) com IMU em drones
- Rastreamento de posição em braços robóticos com sensores não-lineares
- Previsão de corrente em inversores com sensores indutivos
Filtro de Partículas (Particle Filter)
O Filtro de Partículas, também conhecido como Filtro de Monte Carlo, é um método de estimação baseado em probabilidade que utiliza conjuntos de amostras (partículas) para representar a distribuição de probabilidade de um estado. Ele é especialmente útil para sistemas altamente não-lineares e não-gaussianos, onde técnicas como o Filtro de Kalman Estendido se tornam imprecisas ou instáveis.
Problema Resolvido
Muitos sistemas embarcados modernos operam em ambientes ruidosos e incertos, com múltiplas fontes de erro e modelos complexos — como mapeamento e localização (SLAM), rastreamento visual ou fusão de sensores com ruídos assimétricos. Nesses casos, não é possível assumir uma única média e variância (como no Kalman), sendo necessário representar a estimativa como uma distribuição completa. O filtro de partículas resolve isso ao simular muitas hipóteses (partículas) e atualizá-las com base nas evidências.
Princípio de Funcionamento
Cada partícula representa uma possível estimativa do estado. A cada iteração:
- Propagação (Predição):
Cada partícula é atualizada segundo o modelo de movimento (com ruído). - Atualização de Peso:
Cada partícula é ponderada com base na probabilidade de gerar a medição observada. - Reamostragem:
Partículas com maior peso têm mais chances de serem mantidas; partículas com baixo peso são descartadas.
O estado estimado é a média ponderada das partículas.
Exemplo Simplificado (1D) em C
#include <stdlib.h>
#include <math.h>
#define NUM_PARTICLES 100
typedef struct {
float x;
float weight;
} Particle;
Particle particles[NUM_PARTICLES];
void init_particles(float initial_guess) {
for (int i = 0; i < NUM_PARTICLES; i++) {
particles[i].x = initial_guess + ((rand() % 100) / 100.0f - 0.5f); // ruído inicial
particles[i].weight = 1.0f / NUM_PARTICLES;
}
}
float gaussian(float mu, float sigma, float x) {
float coeff = 1.0f / sqrtf(2.0f * M_PI * sigma * sigma);
float expo = expf(-0.5f * ((x - mu) * (x - mu)) / (sigma * sigma));
return coeff * expo;
}
void update_particles(float control_input, float measurement, float process_noise, float measurement_noise) {
float weight_sum = 0.0f;
// Predição e atualização de peso
for (int i = 0; i < NUM_PARTICLES; i++) {
// modelo de movimento: x = x + u + ruído
particles[i].x += control_input + ((rand() % 100) / 100.0f - 0.5f) * process_noise;
// probabilidade da medição atual com base na posição da partícula
particles[i].weight = gaussian(particles[i].x, measurement_noise, measurement);
weight_sum += particles[i].weight;
}
// Normalização dos pesos
for (int i = 0; i < NUM_PARTICLES; i++) {
particles[i].weight /= weight_sum;
}
// Reamostragem (simples)
Particle new_particles[NUM_PARTICLES];
for (int i = 0; i < NUM_PARTICLES; i++) {
float r = (float)rand() / RAND_MAX;
float sum = 0.0f;
for (int j = 0; j < NUM_PARTICLES; j++) {
sum += particles[j].weight;
if (sum >= r) {
new_particles[i] = particles[j];
break;
}
}
}
// Atualiza o conjunto
for (int i = 0; i < NUM_PARTICLES; i++) {
particles[i] = new_particles[i];
}
}
float estimate() {
float est = 0.0f;
for (int i = 0; i < NUM_PARTICLES; i++) {
est += particles[i].x * particles[i].weight;
}
return est;
}
Análise
O Filtro de Partículas oferece uma capacidade superior de lidar com múltiplas hipóteses, ruídos não-gaussianos e observações ambíguas. Entretanto, seu custo computacional é elevado, exigindo muitas amostras e operações de reamostragem. Ainda assim, com otimizadores e simplificações, ele pode ser implementado em sistemas embarcados ARM Cortex-M com uso eficiente de memória e tempo. O principal desafio é o ajuste correto da modelagem probabilística.
Aplicações Típicas
- Navegação e Localização (SLAM) em robótica e drones
- Rastreamento visual de objetos com câmeras embarcadas
- Sistemas biomédicos com sinais altamente ruidosos
- Inferência probabilística em dispositivos IoT com múltiplos sensores
Filtro de Wiener
O Filtro de Wiener é uma técnica de filtragem estatística projetada para produzir uma estimativa ótima de um sinal desejado com base em suas correlações com o ruído e com o próprio sinal. É amplamente usado em aplicações que exigem restauração de sinais, como recuperação de áudio, imagem e sinais digitais degradados por canais ruidosos. No contexto embarcado, pode ser aplicado a sinais de sensores em que a estatística do ruído é relativamente conhecida ou estimável.
Problema Resolvido
Sinais reais são frequentemente corrompidos por ruído aditivo que pode ser modelado estocasticamente. Enquanto os filtros de média móvel e Kalman trabalham com aproximações pontuais ou suposições simplificadas, o Filtro de Wiener é ótimo no sentido de minimizar o erro quadrático médio (MSE) entre o sinal real e a saída filtrada. Ele é ideal para situações onde se conhece ou pode estimar a estatística (auto e cruz-correlações) do sinal e do ruído.
Estrutura Matemática (Wiener 1D)
O filtro de Wiener tem como solução ótima (discreta e causal): \[H(\omega) = \frac{S_{xx}(\omega)}{S_{xx}(\omega) + S_{nn}(\omega)}\]
onde:
- \(H(\omega)\): resposta em frequência do filtro
- \(S_{xx}(\omega)\): densidade espectral de potência do sinal
- \(S_{nn}(\omega)\): densidade espectral de potência do ruído
Na forma discreta e implementável, pode ser expresso como: \[y[n] = \sum_{k=0}^{N-1} h[k] \cdot x[n – k]\]
Os coeficientes h[k] são obtidos resolvendo um sistema de equações baseado nas autocorrelações do sinal e na função cruzada entre entrada e saída desejada.
Exemplo de Código em C (Forma simplificada com estimativa empírica)
#include <stdint.h>
#include <string.h>
#define N 8 // tamanho do filtro
void estimate_wiener_coeffs(const float *signal, const float *desired, float *coeffs, int len) {
float R[N][N] = {0}; // matriz de autocorrelação
float P[N] = {0}; // vetor de correlação cruzada
// Construir R e P
for (int i = 0; i < len - N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
R[j][k] += signal[i + j] * signal[i + k];
}
P[j] += desired[i] * signal[i + j];
}
}
// Resolver sistema linear R * h = P (poderia usar Gauss-Jordan ou LU)
// Aqui simplificado como uma solução direta apenas para casos didáticos
for (int i = 0; i < N; i++) {
coeffs[i] = P[i] / (R[i][i] + 1e-6f); // simplificação para exemplo
}
}
float apply_wiener_filter(const float *input, const float *coeffs) {
float output = 0.0f;
for (int i = 0; i < N; i++) {
output += coeffs[i] * input[i];
}
return output;
}
Nota: Este exemplo é didático. Em aplicações reais, o sistema R⋅h=PR \cdot h = PR⋅h=P deve ser resolvido com métodos numéricos estáveis (ex: decomposição de Cholesky ou métodos iterativos).
Análise
O Filtro de Wiener é ótimo em contextos onde se conhece a estatística do sinal e ruído, mas é limitado por sua dependência desses parâmetros. Sua implementação completa pode ser pesada para microcontroladores de baixo desempenho, mas versões simplificadas, ou estimativas precomputadas, são perfeitamente viáveis em sistemas embarcados com uso constante de sinais similares.
Aplicações Típicas
- Recuperação de áudio embarcado (remoção de ruído de fundo)
- Filtragem de sinais digitais em telecomunicações embarcadas
- Processamento de imagem embarcada (ex: remoção de borrões ou granulação)
- Detecção de falhas em sensores com comportamento repetitivo (ex: sensores industriais)
Ao longo dos capítulos anteriores, exploramos uma ampla gama de filtros aplicáveis ao processamento de sinais em sistemas embarcados, desde técnicas simples baseadas em médias até algoritmos probabilísticos e estatísticos avançados. Cada filtro oferece vantagens e limitações, dependendo da natureza do sinal, do ruído presente e dos recursos computacionais disponíveis.
Comparação Geral dos Filtros
Filtro | Complexidade | Tipo | Vantagem Principal | Limitação Principal | Aplicação Típica |
---|---|---|---|---|---|
Média Móvel | Baixa | Linear | Simples e fácil de implementar | Suaviza transientes | Leitura de sensores analógicos simples |
Exponencial | Muito baixa | Linear (IIR) | Pouco uso de memória, boa resposta | Menos eficaz com ruídos impulsivos | Filtragem de sinais em controle de motor |
Média Ponderada | Baixa | Linear | Ajustável ao contexto | Precisa de cuidado na escolha dos pesos | Interfaces com usuário (joysticks, etc.) |
Mediano | Média | Não-linear | Robusto a picos e outliers | Mais pesado, introduz atraso em sinais finos | Sensores ultrassônicos, visão embarcada |
Kalman | Média | Probabilístico | Otimização estatística com baixo custo | Exige bom modelo de ruído | Estimativa de posição, velocidade, IMUs |
Kalman Estendido (EKF) | Alta | Não-linear | Estima estados em sistemas não-lineares | Custo computacional, sensível a modelagem | Navegação robótica, fusão sensorial |
Filtro de Partículas | Muito alta | Estocástico | Lida com múltiplas hipóteses e ambiguidade | Muito pesado computacionalmente | SLAM, rastreamento em visão embarcada |
Filtro de Wiener | Alta | Ótimo estatístico | Minimiza erro quadrático médio | Requer estatísticas conhecidas | Restauração de sinais, áudio, imagem |
Recomendações Práticas
- Se o seu sistema embarcado for simples e tiver baixa potência computacional, comece com filtros como média móvel, exponencial ou mediano.
- Se você precisa de suavização adaptativa e preditiva, e possui sensores com ruído gaussiano, o Filtro de Kalman é altamente recomendado.
- Em sistemas com modelos não-lineares complexos (ex: giroscópio + acelerômetro), o Filtro de Kalman Estendido é a solução natural.
- Quando o sistema apresenta múltiplas hipóteses simultâneas ou incertezas complexas, como em navegação ou SLAM, o Filtro de Partículas se destaca, desde que haja recursos computacionais adequados.
- Para aplicações onde você conhece a estatística do ruído e sinal, e quer obter a melhor estimativa possível com base nessa modelagem, o Filtro de Wiener é a escolha teórica ideal.
Encerramento
Filtros são ferramentas essenciais no arsenal do engenheiro de sistemas embarcados. Dominar seus fundamentos, limitações e aplicações permite construir sistemas mais robustos, confiáveis e eficientes, independentemente da área de atuação — automação, robótica, IoT, biomédica ou aeroespacial.