Ir ao conteúdo
  • Cadastre-se

Algoritmos para processamento digital de sinais.


Posts recomendados

Bem pessoal, vou abrir essa nova categoria publicando uma série de algoritmos (codificados em C) para funções comuns em processamento de sinais. Alguns vão rodar em PIC outros em microcontroladores um pouco mais poderosos, mas todos estão testados.

Vou iniciar postando um algoritmo eficiente para cálculo de funções trigonométricas (Seno, Cosseno, e Tangente) sem a necessidade de implementar tabelas.

Acredito que muitos vão gostar desse cara para fazer seus inversores senoidais caseiros com PIC ou mesmo um gerador de funções com saída senoidal.

Elaborei este em C mas o mesmo pode ser implementado em linguagem Assembly para otimizar ainda mais a velocidade.

O algoritmo aqui baseia-se no CORDIC que ao pé da letra vem de "Coordinate Rotation Digital Computer", e baseia se no cálculo de funções trigonométricas utilizando a rotação de um ponto (x,y), as multiplicações aqui são reduzidas a simples shifts para esquerda ou direita que podem ser executadas em 1 ciclo de máquina e com pouco processamento.

Aqui pode ser vista uma teoria melhor sobre o algoritmo CORDIC:

http://pt.wikipedia.org/wiki/CORDIC

A matemática para compreender o funcionamento desse cara é um pouco pesada, mas no código em si é muito simples e de fácil entendimento.

Abaixo vou colocar os dois arquivos o Cordic.c e Cordic.h, para os iniciantes, NÃO incluam o arquivo.c no main e sim o .h

Modo de uso:

- Esse algoritmo calcula o seno e cosseno de um valor passado no range de 0 a 90 graus com resolução de 12bits;

-Afim de evitar o uso de numeros flutuantes para esse cara operar bem em MCU de 8bits fiz um pequeno fator de escala ou seja antes de entrar com o valor de 0 a 90 pegue o e multiplique por +2048 se positivou ou de 0 a -90 multiplique por -2048, tal mutiplicação pode ser feita de forma eficiente utilizando 11 shifts para a esquerda;

-Existem duas funções doCordicSine() e doCordicCosine() nem preciso comentar quem calcula quem;

- As funções retornam um valor também entre +2048 e -2048;

- Leiam os dois arquivos pois fiz usando boas práticas de programação e ta tudo ordenadinho e no lugar;

- E como sempre tirem dúvidas a vontade:

Cordic.h:


/************************************************************************
Algoritmo Cordic básico

Autor: Felipe Neves
REV 00
************************************************************************/

#ifndef __CORDIC_H
#define __CORDIC_H 1

/************************************************************************
--INCLUDES
************************************************************************/


/************************************************************************
--DEFINES
************************************************************************/

#define RESOLUTION 12 //resolução de 12bits
#define MAXANGLE 0xC90 //+PI/2
#define MINIANGLE (~(0xC90) +1) //-PI/2
#define KCOS 1243 //Constante cosseno theta
/************************************************************************
--STRUCTS
************************************************************************/
typedef struct
{
int Real[2000];
int Imag[2000];
}Cpx;


/************************************************************************
--PROTOTIPOS
************************************************************************/

int doCordicSine (signed int wAngle); //executa função cordic
int doCordicCosine (signed int wAngle);

#endif


Cordic.c:


/************************************************************************
Algoritmo básico Cordic para geração de Seno e Cosseno

Autor: Felipe Neves
REV: 00
************************************************************************/

/************************************************************************
Arquivo: Cordic.c
Funções:
- doCordicSine()
************************************************************************/

/************************************************************************
--INCLUDES:
************************************************************************/

#include "Cordic.h" //arquivo com as definições e constantes

/************************************************************************
--Variaveis globais
************************************************************************/
extern Cpx FFT_Array; //matriz de dados para FFT

/************************************************************************
--FUNCOES
************************************************************************/


/************************************************************************
FUNCAO: doCordic ()
DESCRICAO: Executa algoritmo Cordic em 360 e salva em uma tabela

ENTRADA: wAngle
SAIDA: Nenhuma
*************************************************************************/

int doCordicSine (signed int wAngle)
{
//signed int wAngle = 0; //Angulo de partida
long dwdx, dwdy, dwda; //Vetores de rotacionamento
int wAtan[RESOLUTION] = {0x648,0x3B5,0x1F5,0xFE,0x7F,0x3F,0x1F,0x0F,0x07,
0x03,0x01,0}; //Steps do angulo Theta para multiplicação
int wSin = 0, wCos = KCOS;
int by; //loop count

for (by = 0; by < RESOLUTION ; by++)
{
dwdx = wCos >> by; //rotaciona vetor
dwdy = wSin >> by;
dwda = wAtan [by]; //recupera angulo

if(wAngle >= 0)
{
wCos = wCos - dwdy;
wSin = wSin + dwdx; //rotaciona vetores no sentido horario
wAngle = wAngle - dwda; //p´roximo angulo
}
else
{
wCos = wCos + dwdy;
wSin = wSin - dwdx; //rotaciona vetores no sentido anti -horario
wAngle = wAngle + dwda; //p´roximo angulo
}
}

return (wSin); //retorna o seno da funcao

}

/************************************************************************
FUNCAO: doCordic Cosine()
DESCRICAO: Executa algoritmo Cordic em 360 e salva em uma tabela

ENTRADA: wAngle
SAIDA: Nenhuma
*************************************************************************/

int doCordicCosine (signed int wAngle)
{
//signed int wAngle = 0; //Angulo de partida
long dwdx, dwdy, dwda; //Vetores de rotacionamento
int wAtan[RESOLUTION] = {0x648,0x3B5,0x1F5,0xFE,0x7F,0x3F,0x1F,0x0F,0x07,
0x03,0x01,0}; //Steps do angulo Theta para multiplicação
int wSin = 0, wCos = KCOS;
int by; //loop count

for (by = 0; by < RESOLUTION ; by++)
{
dwdx = wCos >> by; //rotaciona vetor
dwdy = wSin >> by;
dwda = wAtan [by]; //recupera angulo

if(wAngle >= 0)
{
wCos = wCos - dwdy;
wSin = wSin + dwdx; //rotaciona vetores no sentido horario
wAngle = wAngle - dwda; //p´roximo angulo
}
else
{
wCos = wCos + dwdy;
wSin = wSin - dwdx; //rotaciona vetores no sentido anti -horario
wAngle = wAngle + dwda; //p´roximo angulo
}
}

return (wCos); //retorna o seno da funcao

}

/****************************************************************************
Fim do arquivo Cordic.c
****************************************************************************/


Esse código foi testado nos microcontroladores: PIC e dsPIC, MSP430;

Ao pessoal que manja de DSP tragam seus algoritmos, vamos enriquecer isso aqui, na próxima vou trazer um outro brinquedo pra usar com o cordic para formarmos um sintetizador digital.

Abs.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Excecelente iniciativa da moderação/administração em criar uma área separada para microcontroladores. Parabenizo também a nobre atitude do colega Felipe_Eletronic em criar este tópico e disponibilizar o material para estudo. Não tenho conhecimento algum de programação de DSPs/FPGAs/CPLDs, mas estarei acompanhando este tópico para ver se aprendo algo heheh...

Link para o comentário
Compartilhar em outros sites

Boas pessoal, antes de publicar o código para usar como sintetizador digital, acho pertinente dar uma clareada em como fazer filtros digitais do microcontroladores, então em paralelo com os algoritmos vou publicar modos de se filtrar sinais, desde casos simples até os mais chatinhos de fazer.

De um modo geral quando falamos de filtros digitais, estes podem ser definidos como equações númericas capazes de reproduzir o comportamento de filtros mais comuns: passa-baixas, altas e passa faixas.

Entender de onde vem as equações pode ser beem cansativo, como o objetivo do tópico é prático não vou entrar em detalhes da origens das equações.

Para se entender o conceito de filtros digitais sugiro esses materiais:

http://www-sigproc.eng.cam.ac.uk/~op205/3F3_4_Basics_of_Digital_FIlters.pdf

e não poderia faltar esse:

http://www.dspguide.com/ch14/1.htm

Estão em inglês portanto deixo a obrigação por estar com o idioma em dia por conta de vocês!

Agora vamos por a mão na massa, para que esse tópico tenha sentido não teria a menor graça publicar um código simples mas para um DSP56K da freescale, o negócio é fazer a bagaça rodar num PIC capenga ou mesmo em um AVR e outras plataformas 8 bits.

O primeiro código que vou deixar sem dúvida é o mais simples método de filtragem chamado de filtro de média móvel, trata-se de um filtro tipo FIR passa-baixas, pode ser interessante para executar a função de integrador ou mesmo para a retirada de ruídos em circuitos do tipo "Clapper", sua frequência de corte situa-se próxima a frequência que o sinal foi amostrado.

Falando em amostragem tenho que explicar isso aqui antes que me perguntem, existe um critério para amostragem de sinal com o conversor A/D determinado critério de Nyquist onde (não vou explicar o porque) para todo sinal com uma frequencia fx a taxa que este deve ser amostrado deve ser no Minimo 2*fx afim de evitar um fenomento conhecido como aliasing que faz com que o microcontrolador "perca" as amostras provocando distorção, falta de fidelidade do sinal entre outros.

Exemplo:

Se vamos amostrar o sinal de uma palma de um Clapper, sabe-se que sua frequência está em torno de 600Hz então nosso conversor A/D deve trabalha no minimo a 1.2KHz (ou 1.2KSPS).

Bem agora chega de conversa e vamos ao código, como sempre vamos as observações:

- Nunca incluir o arquivo .c na sua aplicação, sempre o .h

- O filtro é de 8 elementos e a divisão é feita com um simples shift;

- O parametro é um ponteiro para um buffer de 8 elementos;

- Coloquei uma rotina de atualização do buffer de dados para evitar que o pessoal faça a filtragem e esqueça de atualizar o buffer de saida e entrada;

- recomendo um estudo básico sobre ponteiros e estruturas;

ai, vão primeiro o .h:


/*********************************************************************
* ALGORITMOS DSP FORUM CdH *
* *
* Arquivo: Average_Filter.h *
* Descrição: Arquivo header de Average_Filter.C *
*********************************************************************/

/********************************************************************

--Conteúdo:
-- Externs
-- Defines
-- Structs
-- Prototipos
**********************************************************************/
#ifndef __AVERAGE_FILTER_H
#define __AVERAGE_FILTER_H 1


/*********************************************************************
--DEFINES
*********************************************************************/
#define MAXAVGFILTER 0x08 //tamanho da média do filtro
#define NUMSHIFTS 0x03 //Numero de shitfs correspondente
// a uma divisão po MAXAVGFILTER
//usem potencias de 2
/**********************************************************************
-- STRUCTS
**********************************************************************/
typedef struct
{
wIn[MAXAVGFILTER]; //buffer de entrada de dados, salvem as leituras
//do A/D aqui

wOut[MAXAVGFILTER]; //buffer de saida de dados, salvem aqui os dados
// que vão para o D/A ou PWM
}st_AverageBuffers; //tipo da estrutura

/***********************************************************************
-- EXTERNS
***********************************************************************/

extern st_AverageBuffers stFilterBuffer; //ja criei uma pra vocês usarem
/**********************************************************************
-- PROTOTIPOS
**********************************************************************/
void Average_UpdateBuffer( int *pwBuffer, int wNewSample); //atualiza buffers
void Average_Filter (st_AverageBuffers stBuffer); //filtra

/**********************************************************************
-- ENDIF
**********************************************************************/
#endif

/*********************************************************************
FIM DO ARQUIVO Average_Filter.h
*********************************************************************/

E agora o .c


/*********************************************************************
* ALGORITMOS DSP FORUM CdH *
* *
* Arquivo: Average_Filter.C *
* Descrição: Arquivo contendo funções de filtro média móvel *
*********************************************************************/

/********************************************************************
* Autor: Felipe Neves *
* *
* Historico: primeira revisão *
* *
* Funcoes: - Average_UpdateBuffer() *
* - Average_Filter() *
* *
********************************************************************/


/*******************************************************************
--INCLUDES
*******************************************************************/

#include Average_Filter.h //arquivo header

/*****************************************************************
--VARIAVEIS GLOBAIS
*****************************************************************/
st_AveragerBuffers stFilterBuffer; //buffer de filtros

/****************************************************************
--FUNCOES
****************************************************************/


/*********************************************************************
* FUNCAO: Average_UpdateBuffer() *
* DESC: Atualiza posição do buffer apontado *
* *
* Entrada : pwBuffer, wNewSample *
* Saida : Nenhuma *
*********************************************************************/
void Average_UpdateBuffer( int *pwBuffer, int wNewSample)
{
int by;
int wBufferTemporario[MAXAVGFILTER]; //buffer temporario para reordenacao
int *pwTemporário

*pwTemporario = (int *) &pwBuffer; //guarda o endereço do buffer de entrada

for ( by = 0; by < MAXAVGFILTER; by++)
{
wBufferTemporario[by] = (int)*pwBuffer++; //preenche buffer temporario
}

//reordena todo mundo, de modo que todos os elementos sejam deslocados
//para aesquerda e a posição 0 do buffer fique livre

for (by = MAXAVGFILTER; by > 0; by--)
{
wBufferTemporario[by] = wBufferTemporario[by - 1];
}

//Coloca nova amostra no buffer
wBufferTemporario[0] = wNewSample;

//atualiza buffer que passamos como parametro via ponteiro
for (by = 0; by < MAXAVGFILTER; by ++)
{
*pwTemporario++ = wBufferTemporario[by];
}
}

/*********************************************************************
* FUNCAO: Average_Filter() *
* DESC: Filtra amostras utilizando o algoritmo "average moving" *
* *
* Entrada : st_AverageBuffers stBuffer *
* Saida : Nenhuma *
*********************************************************************/
void Average_Filter (st_AverageBuffers stBuffer)
{
long int dwAccumulador = 0 ; //para usuários do CCS mudar aqui para int32
int by; //variavel de controle
int NewSample; //nova amostra

for(by = 0; by < MAXAVGFILTER; by++)
{
dwAccumulador += stBuffer.wIn[by]; //acumula valor
}

wNewSample = dwAccumulador >> NUMSHIFTS; //divide por 8

Average_UpdateBuffer(&stBUffer->Out, wNewSample); //atualiza buffer de saida
}

/**********************************************************************
FIM DO ARQUIVO Average_Filter.C
**********************************************************************/

Até a próxima e peguntem bastante!

Abs.

Link para o comentário
Compartilhar em outros sites

Cara, li todos os tópicos detalhadamente, mas como ainda sou iniciante em programação e faço isso por hobbie (não tenho qualquer curso de eletrônica, sou historiador!) fiquei boiando em algumas coisas: seu 1º tópico sobre "Algoritmos para processamento digital de sinais." para "cálculo de funções trigonométricas" onde eu por exemplo poderia utilizar este tipo de algoritmo? você disse que serviria para " inversores senoidais caseiros com PIC ou mesmo um gerador de funções com saída senoidal." Rsrs.... pode parece estúpida a pergunta, mas o que é isso mesmo e para que serve?

Link para o comentário
Compartilhar em outros sites

Opa, legal o tópico. Estou pensando em traduzir para asm para PIC e AVR esses algoritmos!

No cálculo se seno e cosseno de um ângulo arbitrário inteiro (para valores até acima de 360), segue o algoritmo:

Sabemos que a função seno é apenas uma repetição do primeiro quadrante, então só é necessário calcular valores entre 0 e 90 para obter qualquer valor da função seno, cosseno e tangente:

cos(x) = sen(x+90)

tan = sen(x) / sen(x+90)

Seno:

Considerando que a função sen() só funcione com valores entre 0 e 90:

Para valores negativos:

x = abs(x) + 180

Para que o valor nunca exceda 360 segue o algorítmo:

x = x mod 360

*mod serve para retornar o resto da divisão

Ângulo entre 0 e 90:

sen(x)

Ângulo entre 90 e 180:

sen(180 - x)

Ângulo entre 180 e 270:

-sen(x-180)

Ângulo entre 270 e 360:

-sen(360-x)

Link para o comentário
Compartilhar em outros sites

Caro mister nintendo, primeiramente atualize - se.

Como você mesmo disse são os passa - baixas, altas e faixa, mas estás a esquecer do famoso notch, e o all-pass que pode ser usado em linhas de atraso, reverb em áudio e como modificador de fase, além do mais, se estudares um pouco mais sobre filtros, verás que existem diversas topologias de filtros, métodos de análise e simualação, quer um exemplo, sabias que podemos implementar um filtro passa baixas de três formas diferentes? podem ser butterworth, chebyschev ou mesmo bessel, cada um com suas próprias caractrísticas que os tornam únicos,

- o butterworth é o famoso "carne de vaca" atende a grande parte das aplicações e tem uma boa relação entre estabilidade, margem de fase, atraso e roll-off;

- Um chebyschev vai te dar uma péssima margem de fase, mas em compensação possui um roll-off quase nulo sendo muito util onde a banda de passagem deve ser estreita;

- Ja o bessel tem a melhor margem de fase, ou seja este será o que menos vai distorcer teu sinal de entrada.

Quando criei esse tópico o objetivo é mostrar por onde estudar processamento digital de sinais, e dar exemplos de códigos para o pessoal poder ver a coisa na prática, mas no seu caso, e pela afirmação que fizestes, sugiro que antes de passar por aqui reforce seus estudos sobre filtros analógicos, topologias e afins para depois começar a usar o material que vou disponibilizar.

Aqui para você uma boa sugestão de estudo:

http://www.analog.com/library/analogDialogue/archives/43-09/EDCh%208%20filter.pdf

Excelennte artigo da Analog Devices dando um banho de conhecimento em filtros.

Então o que está esperando? Ja pros livros! Quero ver questionamentos superiores a esse que me fez (não leve a mal, é para seu bem :D)

Dúvidas, manda!

Abs.

Link para o comentário
Compartilhar em outros sites

@VTRX,

Muito boa, a minha ideia inicial era mixar as linguagens, deixar as chamadas em C e o codigo em si em assembly (sou espartano também, não esqueça :D).

Pretendo sim publicar em assembly os códigos, inclusive tenho a versao em ASM do CORDIC so que pra MSP430 e pro 56K, sugestão anotada.

@Projetos_afg,

Da uma olhada no comportamento do algoritmo cordic, ele pode lhe ser muito util pela velocidade e excelente precisao com 12bits, e utilizando apenas numeros inteiros, a matematica e meio pesada mas para fins de compreensao uma ou duas lidas na teoria vão te dar a ideia de inclusive implementar o CORDIC melhor do que esse que postei.

Estou testando o firmware do pequeno sintetizador digital, nos proximos dias irei postar aqui.

Abs, pessoal!

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Boas pessoal, estive fora nesse feriadão e só quis saber de sombra e agua fresca :D

Mas vamos atualizar o tópico, hoje eu trouxe aqui uma aplicação prática do algoritmo cordic (sim esse que está no meu primeiro post) usando um MCU da Texas Instruments, programei o trem inteiro em linguagem C para vocês observarem que mesmo assim a eficiência é grande, estou gerando uma senoide de 60Hz e 64 pontos, com ótima relação sinal/ruido, para converter a bagaça de volta para o dominio analógico usei um PWM rodando proximo aos 100KHz com 7bits de resolução e apliquei um simples filtro passa baixas (um "single-pole" RC) com corte proximo a 800Hz.

Estou anexando todos os arquivos do projeto para o pessoal que comprou a launch pad (divulgada em outros tópicos) poder reproduzir a criança, mas o pessoal que mexe com PIC nao precisa se preocupar, o código está bemm comentado e a melhor parte é que nao ha nenhum periférico monstro a aprender, é tudo coisinha básica que qualquer PIC tem, basta um timer e uma porta PWM.

Abaixo os aqruivos do projeto no meu SkyDrive(está zipado):

https://skydrive.live.com/redir.aspx?cid=60a4b40f43b52528&resid=60A4B40F43B52528!318&parid=60A4B40F43B52528!294

Abaixo a função main que mostra como gerar a senoide a partir de quatro quadrantes:



************************************************************************
* CordiCMSP430
*
* Arquivo: timer.c
* Desc: Arquivo principal do firmware que acessa os outros
************************************************************************/

/************************************************************************
* Conteudo:
* --Includes
* --Globais
* --Funcoes
************************************************************************/

/************************************************************************
* Historico:
* -Versao: Inicial
* -Motivo: Criacao
* -Autor: FSN
* -Data:
************************************************************************/

/************************************************************************
* --INCLUDES
************************************************************************/
#include <msp430.h>
#include <ti/mcu/msp430/csl/CSL.h>
#include "Cordic.h"
#include "timer.h"


/************************************************************************
* --VARIAVEIS GLOBAIS
************************************************************************/
U8 byTickFlag = 0; //flag de tempo de ponto decorrido
U16 byTicks = 0;
/************************************************************************
* --FUNCOES
************************************************************************/
/************************************************************************
* FUNCAO: OCR0_Handler()
* DESC: Tratamento da interrupcao do timer
*
* ENT: N/A
* SAI: N/A
* RET: N/A
************************************************************************/
void OCR0_Handler (void)
{
//static U16 byTicks = 0; //variavel tick counter

byTicks++; //incrementa variavel de controle
if(byTicks == SINEPOINT) //passado o tempo de ponto da senoide
{
byTicks = 0; //resseta timer
byTickFlag = 1;
}
}
/************************************************************************
* FUNCAO: SetPWM()
* DESC: Seta PWM com dutycicle correspondente
*
* ENT: wInput
* SAI: N/A
* RET: N/A
************************************************************************/
void SetPWM(U16 wInput)
{
CCR1 = (wInput >> 5)+ 60; //faz downscale e passa valor ao PWM
}
/************************************************************************
* FUNCAO: SetPWMN()
* DESC: Seta PWM com dutycicle correspondente
*
* ENT: wInput
* SAI: N/A
* RET: N/A
************************************************************************/
void SetPWMN(U16 wInput)
{
CCR1 = (wInput >> 5); //faz downscale e passa valor ao PWM
}

/************************************************************************
* FUNCAO: main()
* DESC: Funcao principal responsavel por executar outras rotinas
*
* ENT: N/A
* SAI: N/A
* RET: N/A
************************************************************************/
void main(void)
{
//U8 byPoint = 0; //ponto atual da senoide
I16 wAngle = 0; //fase da senoide
U8 byQuadrant = 1; //quadrante da senoide

CSL_init(); // Activate Grace-generated configuration

while (1)
{
switch(byQuadrant)
{
case 1 :
if(byTickFlag)
{
wAngle += OFFSET; //incrementa angulo da senoide
if(wAngle >= MAXANGLE)
{
byQuadrant++;// fez um full, então vamos ao proximo
//wAngle = MAXANGLE;
}
else //senao calcula seno
{
SetPWM(doCordic(wAngle)); //atualiza PWM
}
byTickFlag = 0; //zera flag
}
break;

case 2 :
if(byTickFlag)
{
wAngle -= OFFSET; //incrementa angulo da senoide
if(wAngle <= 0)
{
byQuadrant ++;// fez um full, então vamos ao proximo
//wAngle = 0; //faz complemento de 0
}
else //senao calcula seno
{
SetPWM(doCordic(wAngle)); //atualiza PWM
}
byTickFlag = 0; //zera flag
}
break;

case 3 :
if(byTickFlag)
{
wAngle -= OFFSET; //incrementa angulo da senoide
if(wAngle <= MINIANGLE)
{
byQuadrant ++;// fez um full, então vamos ao proximo
//wAngle = MINIANGLE; //
}
else //senao calcula seno
{
SetPWMN( 2048 - (~(doCordic(wAngle)))); //atualiza PWM
}
byTickFlag = 0; //zera flag
}
break;

case 4 :
if(byTickFlag)
{
wAngle += OFFSET; //incrementa angulo da senoide
if(wAngle >= 0)
{
byQuadrant = 1;// fez um full, então vamos ao proximo
//wAngle = 0;
}
else //senao calcula seno
{
SetPWMN( 2048 - (~(doCordic(wAngle)))); //atualiza PWM
}
byTickFlag = 0; //zera flag
}
break;
}
}
}



header desse arquivo (obrigatório):


/************************************************************************
* CordiCMSP430
*
* Arquivo: timer.h
* Desc: Header de timer.c
************************************************************************/
/************************************************************************
* Conteudo:
* --Defines
* --Externs
* --Structs
* --Prototipos
************************************************************************/

#ifndef __TIMER_H
#define __TIMER_H 1

/*************************************************************************
* --DEFINES
*************************************************************************/
#define OFFSET (MAXANGLE / 16) //incremento de angulo da senoide
#define SINEPOINT 1 //numero de ticks por ponto


typedef unsigned char U8; //define tipo para U8
typedef unsigned int U16; //define tipo para U16
typedef signed int I16; //define tipo sinalizado para U16
typedef unsigned long int U32; //define tipo para U32
/*************************************************************************
* --PROTOTIPOS
*************************************************************************/
void OCR0_Handler (void); //interrupcao de captura
void SetPWM(U16 wInput); //faz feed do PWM
void SetPWMN(U16 wInput);//feed PWM negativo
void main(void); //funcao principal do programa
/*************************************************************************
* --ENDIF
*************************************************************************/

#endif /**/


E os resultados para vocês encherem os olhos:

http://img577.imageshack.us/content_round.php?page=done&l=img577/6274/foto0305y.jpg

Mais uma:

http://imageshack.us/content_round.php?page=done&l=img214/5071/foto0306h.jpg

Estou fazendo testes finais no projeto NCO.

Duvidas mandem bala, na proxima vou postar aquele filtro de média móvel fazendo o trabalho dele.

Abs!

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Grande Felipe,

Que saudades heheheh fazia tempo que eu estava em outro mundo.... agora voltei para encher o saco dos amigos hehehehe !

Já que voce está com esse pique todo, que tal colocar um algoritmo para calcular as amplitudes das frequências em um sinal de áudio, por exemplo, para fazer um analisador de espectro ?

Por exemplo, encontrei um projeto que utiliza um AVR que utiliza um canal ADC para fazer as frequências baixas, e um outro canal ADC para as frequências altas, num total de 14 frequências. As baixas vão de 20 Hz a 1 Khz, e as altas vão de 2 até 20 Khz.

O cara fez um simples filtro passa - baixas como antialisasing, e a bagaça toda funcionou relativamente bem. Claro que como o que se quer é medir apenas as amplitudes relativas das frequências ( sem as fases ... ) o código fica bem rápido.

voce sabe de cor essa teoria toda, poderia colocar o algoritmo para fazer a DFT e explicar os parâmetros, por exemplo, numero de frequências , como fazer as amostras, etc.

Já lí muita coisa na net mas esse assunto é bem confuso, cada um que faz um projeto faz um código mais doido que o outro, seria interessante voce explicar os detalhes, pois o assunto é muito interessante !

Um abraço !

Paulo

Link para o comentário
Compartilhar em outros sites

voce sabe de cor essa teoria toda, poderia colocar o algoritmo para fazer a DFT

Grande Paulo, saudades do amigo,

enfim, sabe que você tem toda razão, estou terminando um novo post por aqui, que é a concepção de um pequeno sintetizador digital baseado em NCO assim que postar irei retomar a teoria do nosso analisador de espectro.

De modo geral é fácil calcular as amplitudes, pois a própria transformada de Fourier ja nos devolve magnitude e fase do sinal amostrado, seria apenas aplicar um fator de conversão que pode ser feito no "shift" pra ficar mais rápido.

VOu tentar realizar a FFT em assembly (a DFT não da certo, haja multiplicalçoes) e fazer um trabalho em dois lugares, um la embaixo com o MCU calculando a FFT e no lado do desktop criar uma componente em Delphi (Ou Labview) para plotar os dados.

Valeu mestre paulo, vou por essa ideia na prancheta agora!

Abs.

Link para o comentário
Compartilhar em outros sites

Já tentei aprender.... mas acabei desanimando no meio do caminho..

Se houvesse um código base, ajudaria bastante.

Guenta ai! rsrsrs!

Analisadores de espectro ou qualquer traquitana que trabalha no dominio da frequencia parece um bicho de sete cabeças. mas acreditem não é, a ideia do paulo foi sensacional vou tirar mais um projeto da gaveta, aguardem!

Abs.

Link para o comentário
Compartilhar em outros sites

Matheus, estamos aqui novamente !!!! E com algumas idéias novas sobre um outro tutorial envolvendo o PROTEUS na simulação.

Legal que agora o projeto do analisador vai dar certo !!!! É um sonho que tenho desde os tempos da QUASAR ( procure o QRT-5500 na Net e vai entender ... ) que irá virar realidade graças ao grande Felipe !!!!

Eu achei um projeto inteiro, com o hardware e o software em BASCOM-AVR e algumas rotinas de Shift em Assembler ..... era para o ATMEGA8 e tinha alguns problemas pois o ADC era overclockado e só alguns chips funcionavam direito. Mesmo sem o overclock, a velocidade de refresh era acima de 14 hertz, que quebrava bem o galho .

Refiz todo o projeto para um ATMEGA 88 com clock de 16 Mhz , e usando um display LCD comum tipo 2 x 16 funcionou direitinho. Mas o ideal seria achar um display tipo VFD , com o clock aumentado para 20 Mhz aí sim fica muito bonito ! Mas achar esses VFD's é o bicho de caro !!!!

Agora, refiz todo o hardware e o software, para utilizar matrizes de LED tipo 8x8 , bem pequenas, ficou muito bonito, e a simulação funcionou certinho no Proteus. Mas mantive toda a parte de DFT e as amostragens originais.

Confesso que mesmo escrito em Basic, não entendí o funcionamento das rotinas de DFT dele, tenho certeza de que com um algoritmo do Felipe vou conseguir fazer algo bem melhor. Se quiserem o link do projeto original eu posto aqui.

Enfim, pelo que entendí do Felipe, acho que vamos ter um projeto muito legal de gerador de frequências e analisador de espectro, tudo junto !!!!

Quero só ver isso !!!

Ha, Felipe, se ajudar, o projeto que eu ví usa duas interrupções diferentes para as amostragens, uma de baixa velocidade para as frequências baixas, e uma de alta velocidade ( 44 Khz ) para as frequências altas. Assim ele trata apenas 7 frequências em cada uma das amostragens, e fica bem mais rápido do que ele samplear tudo a 44 Khz e tratar 14 frequências diferentes usando trocentas amostras.

Um abraço, e já estou babando no aguardo !

Paulo

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Mestre Felipe,

Fiquei imaginando uma coisa : que tal criarmos uma seção sobre PWM ???

Seria algo mais ou menos ao contrário dos algorítmos de DSP, pois podemos usar o PWM para sintetizarmos formas de ondas, certo ?

Tava lendo aqui no Fórum que muita gente tem dúvida sobre o funcionamento, e são dúvidas bem conceituais, pois poucos entendem as diferença entre o FAST PWM e o Correct Phase PWM, que que voce acha ?

Um abraço !

Paulo

Link para o comentário
Compartilhar em outros sites

Mestre Paulo, curti a ideia...e como assim foge de DSP? kkkkk

Poderiamos sim tirar muitas dúvidas, em especial explicar matematicamente o que ocorre e porque obtém se diversas formas de onda...sem contar que da pra bolar diversos algoritmos de controle digital.

Legal a proposta, sugestão mais que aprovada.

Sei que estou atrasando a FFT mas apareceram projetinhos chatos de ultima hora pra fazer ee estão levando meu tempo...logo mais retomarei essa parte também

Abs.

Link para o comentário
Compartilhar em outros sites

Hahahah não falei isso de "foge do DSP ) !!!!!!! :P

É que o PWM para mim é FAZER uma forma de onda, e o DSP é LER uma forma de onda ! :D bom, voce entendeu né hihihihihi !

Eu posso dar ênfase à controle de potência com o pwm, e voce dá ênfase à criação de forma de onda com o PWM, creio que vamos atingir um bom número de dúvidas, certo ?

Não esquenta com a FFT, vai fazendo quando dar tempo !!!!

Eu estou quase terminando sobre emulação no Proteus, vou postar ele, e depois já começo a fazer sobre o PWM, ok ?

Vai mandando bala nos projetos heheheh !

Paulo

Link para o comentário
Compartilhar em outros sites

  • mês depois...

Não esquenta com a FFT, vai fazendo quando der tempo !!!!

Grande Felipe !

Quando eu falei isso acima, pensava que voce ia ter um tempo em pelo menos uns 2 meses ...... :lol::lol::lol::lol::lol::lol::lol::lol::lol:

Falando sério agora, cadê voce ???? Já estamos com saudades aqui no Fórum !!!!!!

Um abraço e bom trampo !

Paulo

Link para o comentário
Compartilhar em outros sites

Opa, fala mestre Paulo e demais como vão, estive fora por um tempinho...trabalho e mudança de casa (e ainda está uma bagunça), mas enfim estou voltando aos poucos ao forum rsrsrsrrs.

Quanto a FFT ja tenho uma versão pronta, falta apenas fazer o debug (vocês não acharam que eu ia ficar com isso parado) terminando essa parte vou soltar- ela aqui no forum com uma sugestão de projeto, para todos testarem, de acordo com o feedback vou u fazendo uma revisão do código e agrupar funções que o pessoal precisar.

Abs!

Link para o comentário
Compartilhar em outros sites

Hehehehe pois é, eu também fiquei fora um tempão, depois prá voltar e pegar o pique é difícil !

Não esquenta não, é que eu ví que voce tinha parado de responder aos tópicos, e resolví perguntar !

Vou continuando o meu tutorial enquanto voce está se "virando" com a mudança !

Um abraço !

Paulo

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...