relatorio livia

15
Cálculo de FFT usando Hardware-in-the- Loop Lívia Lisandro Judice Godoy - 110073797 1 INTRODUÇÃO 1.1 OBJETIVO O objetivo deste projeto é utilizar o software de simulação PSIM© para simular um circuito inversor de Eletrônica de Potência e fazer o cálculo da DFT (Transformada Discreta de Fourier) que serve para analisar o espectro de harmônicos da onda - da tensão senoidal de saída deste circuito utilizando-se um algoritmo de FFT (Transformada Rápida de Fourier). O algoritmo da FFT será implementado no controlador dsPIC33F64MC802 da Microchip©, que receberá os dados da forma de onda de saída do inversor, enviados pelo PSIM© utilizando o bloco DLL (Dynamic Link Library). Neste bloco serão configurados a abertura e fechamento das portas e a forma de transmissão desses dados, feita via comunicação serial. 1.2 HARDWARE-IN-THE-LOOP (HIL) A simulação em Hardware-in-the-loop (HIL) é uma técnica usada no desenvolvimento e teste de sistemas complexos em tempo real, substituindo os testes com o protótipo físico, ou porque o mesmo não se encontra pronto ou pra evitar danos materiais ou mesmo por redução de custos. A complexidade da planta a ser controlada é adiciona à plataforma de teste adicionando-se uma representação matemática dos sistemas dinâmicos relacionados a ela, que são as plantas de simulação. O sistema testado interage com essa planta de simulação. A HIL é um tipo de simulação em tempo real, com a diferença de que se adiciona um componente real no loop de simulação, que pode, por exemplo, ser um ECU (“Electronic Control Unit”). O objetivo da HIL é prover todos os estímulos elétricos necessários para que o ECU entenda que o protótipo está conectado ali. Portanto, a simulação (circuito inversor de Eletrônica de Potência) deve ser composta de todos os detalhes da planta e de um ECU que, neste caso, será o controlador dsPIC33F64MC802 da Microchip©. 1.3 DYNAMIC LINK LIBRARY (DLL) O bloco DLL do PSIM© é uma biblioteca dinâmica que permite que o usuário escreva um código em C- C++, compile-o e linke-o ao PSIM©. Esse bloco recebe os valores do PSIM© como entradas, realiza os cálculos previstos e manda o resultado de volta pro PSIM© a cada time step de simulação. Porém, quando as entradas do bloco DLL são conectadas a elementos discretos, como o zero-order hold ou o unit delay, o bloco só é chamado nos intervalos de amostragem discretos.

Upload: livia-lisandro

Post on 18-Jan-2016

76 views

Category:

Documents


2 download

DESCRIPTION

microproc

TRANSCRIPT

Page 1: Relatorio Livia

Cálculo de FFT usando Hardware-in-the-Loop Lívia Lisandro Judice Godoy - 110073797

1 INTRODUÇÃO

1.1 OBJETIVO O objetivo deste projeto é utilizar o software de simulação PSIM© para simular um circuito inversor de

Eletrônica de Potência e fazer o cálculo da DFT (Transformada Discreta de Fourier) – que serve para

analisar o espectro de harmônicos da onda - da tensão senoidal de saída deste circuito utilizando-se um

algoritmo de FFT (Transformada Rápida de Fourier). O algoritmo da FFT será implementado no

controlador dsPIC33F64MC802 da Microchip©, que receberá os dados da forma de onda de saída do

inversor, enviados pelo PSIM© utilizando o bloco DLL (Dynamic Link Library). Neste bloco serão

configurados a abertura e fechamento das portas e a forma de transmissão desses dados, feita via

comunicação serial.

1.2 HARDWARE-IN-THE-LOOP (HIL) A simulação em Hardware-in-the-loop (HIL) é uma técnica usada no desenvolvimento e teste de

sistemas complexos em tempo real, substituindo os testes com o protótipo físico, ou porque o mesmo

não se encontra pronto ou pra evitar danos materiais ou mesmo por redução de custos. A complexidade

da planta a ser controlada é adiciona à plataforma de teste adicionando-se uma representação

matemática dos sistemas dinâmicos relacionados a ela, que são as plantas de simulação. O sistema

testado interage com essa planta de simulação.

A HIL é um tipo de simulação em tempo real, com a diferença de que se adiciona um componente real

no loop de simulação, que pode, por exemplo, ser um ECU (“Electronic Control Unit”). O objetivo da HIL

é prover todos os estímulos elétricos necessários para que o ECU entenda que o protótipo está

conectado ali. Portanto, a simulação (circuito inversor de Eletrônica de Potência) deve ser composta de

todos os detalhes da planta e de um ECU que, neste caso, será o controlador dsPIC33F64MC802 da

Microchip©.

1.3 DYNAMIC LINK LIBRARY (DLL) O bloco DLL do PSIM© é uma biblioteca dinâmica que permite que o usuário escreva um código em C-

C++, compile-o e linke-o ao PSIM©. Esse bloco recebe os valores do PSIM© como entradas, realiza os

cálculos previstos e manda o resultado de volta pro PSIM© a cada time step de simulação. Porém,

quando as entradas do bloco DLL são conectadas a elementos discretos, como o zero-order hold ou o

unit delay, o bloco só é chamado nos intervalos de amostragem discretos.

Page 2: Relatorio Livia

1.4 FAST FOURIER TRANSFORM (FFT) A Transformada de Fourier é uma transformada integral que passa um sinal do domínio do tempo para o

domínio da frequência, reconstruindo-o adicionando-se uma ou mais senoides puras de amplitude, fase

e frequência apropriada. Para uma função f=f(t) contínua ela é dada por:

(1)

Para o uso em processamentos digitais, como é o caso deste trabalho, são utilizados sinais discretos no

tempo, que possuem um número finito de pontos. Para isso é usada a Transformada Discreta de Fourier

(DFT), que define uma representação discreta no domínio da frequência.

Sendo uma sequência de N números complexos, tomadas no sinal, pode-se transformá-la

numa sequência periódica de N números complexos de diferentes frequências.

(2)

Onde cada tem a amplitude e fase da componente senoidal da função . A frequência da senoide é

ciclos por segundo e a amplitude e fase são dadas por:

(3) (4)

Esse cálculo pode ser bastante lento na prática, então geralmente é usada a Transformada Rápida de

Fourier (FFT), que é um algoritmo para calcular a Transformada Discreta de Fourier (DFT), tornando-se

possível a leitura das frequências relacionadas a essa onda. Ela pode ser usada quando o tamanho N da

sequência é uma potência de 2. A diferença de complexidade é bastante considerável: enquanto a DFT

requer N² operações, a FFT requer apenas NlogN operações.

Existem diversos algoritmos usados para calcular a FFT de um sinal. No desenvolvimento deste trabalho

será usado o algoritmo de Cooley-Tukey, que expressa uma DFT de tamanho em duas DFT’s

menores de tamanhos e recursivamente. O método calcula primeiramente as componentes pares

( ) e ímpares ( ) do sinal e posteriormente combina os dois

resultados para produzir a sequência completa. Substituindo na equação (2):

O fator

multiplica os dados e é chamado de “twiddle factor”:

Onde o primeiro somatório é a DFT da parte par de e o segundo da parte ímpar. Como a DFT é

periódica, e . Portanto, a equação acima torna-se:

(5)

Page 3: Relatorio Livia

Mas o “twiddle factor” também pode ser escrito como:

Então, a parte de

na equação (5) torna-se:

e

Pode-se, portanto, expressar uma DFT de tamanho N em duas DFT’s de tamanho N/2.

2 PROJETO

2.1 CÓDIGO PARA GERAR A DLL O primeiro passo foi escrever o programa da DLL de forma que esteja pronto para realizar a

comunicação serial. Isso foi feito inicialmente tomando como base o exemplo “general_dll_block_test3”

disponível na biblioteca de exemplos do PSIM©.

Após uma análise do exemplo “MOD1DLL” encontrado em (2), ficou clara a necessidade de se adicionar

a estrutura COMMTIMEOUTS ao projeto do DLL, que contém os parâmetros de intervalo para a

comunicação. A parte ReadIntervalTimeout especifica o tempo máximo (em ms) permitido entre a

chegada de dois caracteres na linha de comunicação. A ReadTotalTimeoutMultiplier especifica o

multiplicador (em ms) usado para calcular o intervalo total para operações de leitura. Para cada uma

este valor é multiplicado pelo número de bytes a serem lidos. A ReadTotalTimeoutConstant especifica a

constante (em ms) usada para calcular o intervalo total para operações de leitura. Para cada uma este

valor é adicionado ao produto do ReadTotalTimeoutMultiplier e do número de bytes a serem lidos. A

WriteTotalTimeoutMultiplier especifica o multiplicador (em ms) usado para calcular o intervalo total

para operações de escrita. Para cada uma, este valor é multiplicado pelo número de bytes a serem

escritos. A WriteTotalTimeoutConstant especifica a constante (em ms) usada para calcular o intervalo

total para operações de escrita. Para cada uma este valor é adicionado ao produto do

WriteTotalTimeoutMultiplier e do número de bytes a serem escritos.

O envio de dados pelo PSIM© é feito de acordo com os parâmetros definidos no bloco zero-order hold,

que faz com que a DLL só seja chamada em intervalos discretos de amostragem. Para calcular o passo

(parâmetro de intervalo), foi utilizado o Teorema da Amostragem.

O Teorema da Amostragem diz que um sinal analógico que tem maior frequência Fm, limitado em Banda,

que foi amostrado (ou seja, convertido em uma função discreta), pode ser recuperado a partir de uma

sequência infinita de amostras, se a taxa de amostragem for maior que 2Fm amostras por segundo.

Porém, se um sinal contiver uma componente exatamente em Fm Hertz, e amostras espaçadas de

exatamente 1/(2Fm) segundos, não se consegue recuperar totalmente o sinal

É necessário também definir as funções relativas a comunicação serial. Uma explicação sobre essa

aplicação no DLL do PSIM© está disponível em (3) e (4). Para isso, foram definidos os vetores e

protótipos de função que servem para enviar e receber dados. Na escrita, foi usada a variável auxTx

para receber os dados em 16 bits e passá-los para inteiro, a bufferTx para dividi-los em duas partes e

Page 4: Relatorio Livia

transmiti-los em 8 bits. Na leitura dos dados recebidos, os dados em 8 bits são concatenados para 16

bits usando a variável auxRx.

Esses dados são manipulados no bloco DLL do PSIM© pelas funções OPENSIMUSER, RUNSIMUSER e

CLOSESIMUSER. A função OPENSIMUSER é executada no início da simulação e serve para abrir a porta

serial e configurá-la de acordo com o padrão do sistema operacional. A RUNSIMUSER é a função que, de

fato, vai ler e escrever os dados transferidos. Já a CLOSESIMUSER só é executada no final da simulação e

serve para fechar a porta serial. A configuração das portas também foi feita de acordo com o exemplo

encontrado em (3).

O código desenvolvido está disponível no Anexo [1].

2.2 CÓDIGO DO MPLABX PARA HIL Como já mencionado, o microprocessador utilizado é o dsPIC33F64MC802 da Microchip©. O código que

roda no dsPIC foi desenvolvido em linguagem C, no ambiente de desenvolvimento MPLAB IDE,

utilizando o compilador MPLAB C30 da Microchip.

O código inicia na função Main () com a configuração dos PORTS de I/O e inicialização das variáveis. Os

periféricos são configurados e iniciados com a função uart_init (), inicia a comunicação UART a 9600 bps,

8 bits de dados, sem paridade e 1 bit de parada.

Após os dados serem recebidos pelo dsPIC, o cálculo da FFT é feito pela função FFTComplexIP (), que

pertence à biblioteca DSP Library, assim como as três funções citadas a seguir. A seguir, os dados – que

já se encontram no domínio da frequência – são organizados pela função BitReverseComplex () e,

posteriormente, o sinal complexo é convertido para real através da função SquareMagnitudeCplx ().

Feito isso, a função VetorMax () retorna o índice da frequência de maior espectro, que é utilizado para

se calcular a frequência de maior espectro do sinal, que será lido no computador. Essas funções fazem

parte da DSP Library, que é chamada no código principal. A função transmite_dados () envia os dados

das 64 frequências para o computador, são enviados primeiramente a parte inteira, depois a parte

decimal e 3 bytes para controle da comunicação. O PSIM lê os dados e analisa os espectros de

frequência.

O código desenvolvido está disponível no Anexo [2].

3 SIMULAÇÃO

O circuito do inversor está mostrado na Figura 1. O controle foi feito utilizando-se a técnica de

modulação PMW de forma discreta, para otimizar o processamento do dsPIC.

Page 5: Relatorio Livia

Figura 1. Circuito inversor no PSIM

Para utilizar a DLL, como já mencionado no primeiro item, foi adicionado ao circuito o bloco DLL

disponível na biblioteca do PSIM©. A entrada do bloco é a tensão na qual será analisado o espectro e a

saída e essa forma de onda analisada.

Para criar a biblioteca dinâmica, foi criado no Microsoft Visual Studio um novo projeto formato DLL em

branco e adicionar nele o código fonte em C, como foi mostrado no item 2.1. Aberto o código fonte, foi

feito o debug, que gerou o arquivo .dll, posteriormente copiado para a pasta de simulação do onde

estava o circuito. O bloco DLL foi, finalmente, editado, com a extensão do arquivo.

4 CONCLUSÃO

Todo o trabalho de densenvolvimento de códigos tanto para o DLL do PSIM quanto para o MPLab foi

feito, faltando apenas a parte final de leitura dos dados no PSIM, que não foi feita.

Por isso, os resultados de simulação não se encontram neste trabalho.

Page 6: Relatorio Livia

5 BIBLIOGRAFIA

http://www.mat.uel.br/matessencial/superior/pdfs/tfourier.pdf (1)

http://www.powersimtech.com/download/VC2010_Express.zip(2)

http://www.psim-europe.com/openload2.php?doc=Tutorial-Using_SCI_for_Real-

Time_Monitoring_in_TI_F28335_Target.pdf (3)

http://www.psim-europe.com/openload2.php?doc=Help_Embedded_Software_Block.pdf (4)

http://conservancy.umn.edu/bitstream/140662/1/Rajavel_Tamil_July2012.pdf (5)

Page 7: Relatorio Livia

6 ANEXOS

6.1 CÓDIGO DA DLL // TestBlock3.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include <math.h> #include <stdlib.h> #include <stdio.h> #include <assert.h> #include "psimutil.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // Simulation Functions DCB PortDCB; HANDLE hPort; COMMTIMEOUTS CommTimeouts; int i; unsigned int auxTx = 0; unsigned int auxRx = 0; char bufferTx[2 + 1] = {0}; char bufferRx[2 + 1] = {0}; int countRx = 0; DWORD dwNumBytesWritten; DWORD dwBytesTransferred; extern "C" __declspec(dllexport) void OPENSIMUSER(const char *szId, const char * szNetlist, void ** ptrUserData, int *pnError, LPSTR szErrorMsg, void * pPsimParams); extern "C" __declspec(dllexport) void RUNSIMUSER(double t, double delt, double *in, double *out, void ** ptrUserData, int *pnError, LPSTR szErrorMsg); extern "C" __declspec(dllexport) void CLOSESIMUSER(const char *szId, void ** ptrUserData);

Page 8: Relatorio Livia

extern "C" __declspec(dllexport) void OPENSIMUSER(const char *szId, const char * szNetlist, void ** ptrUserData, int *pnError, LPSTR szErrorMsg, void * pPsimParams) { /* Openning Port ------------------------------------------------------------*/ // Open the serial port. hPort = CreateFile( "COM8" , GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); /* Configuring Port ---------------------------------------------------------*/ PortDCB.DCBlength = sizeof (DCB); GetCommState(hPort, &PortDCB); PortDCB.BaudRate = 9600; // Current baud PortDCB.ByteSize = 8; // Number of bits/byte, 4-8 ------------- PortDCB.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2 -------------------- PortDCB.Parity = NOPARITY; // 0-4=no,odd,even,mark,space ----------- SetCommState (hPort, &PortDCB); // Configuring Timeout -------------------------------------------------------- GetCommTimeouts (hPort, &CommTimeouts); CommTimeouts.ReadIntervalTimeout = 500; CommTimeouts.ReadTotalTimeoutMultiplier = 500; CommTimeouts.ReadTotalTimeoutConstant = 100; CommTimeouts.WriteTotalTimeoutMultiplier = 500; CommTimeouts.WriteTotalTimeoutConstant = 100; SetCommTimeouts (hPort, &CommTimeouts); } __declspec(dllexport) void RUNSIMUSER(double t, double delt, double *in, double *out, void ** ptrUserData, int *pnError, LPSTR szErrorMsg) { /* Writing ----------------------------------------------------------------*/ for(i=0; i<1; i++) // indice do looping eh referente a quantidade de entradas do bloco dll { auxTx = (unsigned int) (in[i]); // 12 bits resolucao bufferTx[1] = auxTx & 0xFF; bufferTx[0] = (auxTx >> 8) & 0xFF; WriteFile (hPort, bufferTx, 2, &dwNumBytesWritten, NULL); } /* Reading ------------------------------------------------------------------*/ ReadFile(hPort, bufferRx, 2, &dwBytesTransferred, NULL); auxRx = ((bufferRx[0] & 0x00FF) << 8) | (bufferRx[1] & 0x00FF); out[0] = (double) auxRx; /* ReadFile(hPort, bufferRx, 2, &dwBytesTransferred, NULL); auxRx = ((bufferRx[1] & 0x00FF) << 8) | (bufferRx[0] & 0x00FF); out[1] = (double) auxRx; ReadFile(hPort, bufferRx, 2, &dwBytesTransferred, NULL);

Page 9: Relatorio Livia

auxRx = ((bufferRx[1] & 0x00FF) << 8) | (bufferRx[0] & 0x00FF); out[2] = (double) auxRx; */ } __declspec(dllexport) void CLOSESIMUSER(const char *szId, void ** ptrUserData) { /* Closing Port -------------------------------------------------------------*/ CloseHandle(hPort); }

6.2 CÓDIGO DO MPLABX

/*** PROJETO DE MICROCONTROLADORES LÍVIA LISANDRO JUDICE GODOY UFRJ - 2014.1 O CÓDIGO A SEGUIR: - Analisa o espectro de frequencia atraves da Transformada Rapida de Fourier - FFT - Indica a frequencia com maior espectro e seu modulo - Envia o espectro de frequencia para o PSIM atraves da UART - Dados da FFT: Pontos: 128; 128 amostragens no tempo transformarao em 128 pontos de frequencia fs: 7,68 kHz; taxa de amostragem fo: 60 Hz; passo entre as frequencias */ //------------------ Inclui funções auxiliares ------------------------- #include "dsp.h" #include "p33Fxxxx.h" #include "fft.h" #include <timer.h> #include <outcompare.h> #include <uart.h> #include <stdio.h> #include "def.h" //---------------------- Define constantes ------------------------------- #define display PORTB //----------------- Declaração de variaveis globais----------------------------------- fractional sinal_Entrada [128]= { //vetor que ira armazenar os dados de entrada, declarados para simulacao. tb testa o programa. 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001,

Page 10: Relatorio Livia

0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x8001, 0x8001, 0x8001}; unsigned char *TXPtr; unsigned int n, buffer, buffercheio, dado, buffer16; float tempFloat, modulo; int picoFrequenciaBin = 0; unsigned long picoFrequencia = 0; fractional *temp3_pnt, tempFrac; // Entrada do sinal para a FFT declarada na memoria Y fractcomplex sinalComplexo[PONTOS_FFT]__attribute__ ((section (".ydata, data, ymemory"),aligned (PONTOS_FFT * 2 *2))); // ------------- Declara constantes ------------------------- // declara vetor dos coeficientes Twiddle da FFT na memoria de programa // Define 128 constantes "twiddle" da FFT: WN (kn) = exp [-(j*2*pi*k*n)/N] const fractcomplex twiddleFactors[] __attribute__ ((space(prog), aligned (PONTOS_FFT*2)))= { 0x7FFF, 0x0000, 0x7FD9, 0xF9B8, 0x7F62, 0xF374, 0x7E9D, 0xED38, 0x7D8A, 0xE707, 0x7C2A, 0xE0E6, 0x7A7D, 0xDAD8, 0x7885, 0xD4E1, 0x7642, 0xCF04, 0x73B6, 0xC946, 0x70E3, 0xC3A9, 0x6DCA, 0xBE32, 0x6A6E, 0xB8E3, 0x66D0, 0xB3C0, 0x62F2, 0xAECC, 0x5ED7, 0xAA0A, 0x5A82, 0xA57E, 0x55F6, 0xA129, 0x5134, 0x9D0E, 0x4C40, 0x9930, 0x471D, 0x9592, 0x41CE, 0x9236, 0x3C57, 0x8F1D, 0x36BA, 0x8C4A, 0x30FC, 0x89BE, 0x2B1F, 0x877B, 0x2528, 0x8583, 0x1F1A, 0x83D6, 0x18F9, 0x8276, 0x12C8, 0x8163, 0x0C8C, 0x809E, 0x0648, 0x8027, 0x0000, 0x8000, 0xF9B8, 0x8027, 0xF374, 0x809E, 0xED38, 0x8163, 0xE707, 0x8276, 0xE0E6, 0x83D6, 0xDAD8, 0x8583, 0xD4E1, 0x877C, 0xCF04, 0x89BE, 0xC946, 0x8C4A, 0xC3A9, 0x8F1D, 0xBE32, 0x9236, 0xB8E3, 0x9592, 0xB3C0, 0x9931, 0xAECC, 0x9D0E, 0xAA0A, 0xA129,

Page 11: Relatorio Livia

0xA57E, 0xA57E, 0xA129, 0xAA0A, 0x9D0E, 0xAECC, 0x9931, 0xB3C0, 0x9592, 0xB8E3, 0x9236, 0xBE32, 0x8F1D, 0xC3A9, 0x8C4A, 0xC946, 0x89BE, 0xCF04, 0x877C, 0xD4E1, 0x8583, 0xDAD8, 0x83D6, 0xE0E6, 0x8276, 0xE707, 0x8163, 0xED38, 0x809E, 0xF374, 0x8027, 0xF9B8 } ; //----------------- Declara funcoes ------------------------------------------ void delayms (); void delayus (); void barg1 (); void envia_mensagem(char *pointer); //----------------- funcoes externas --------------------------------- // calcula a magnitude quadrada do vetor complexo extern void SquareMagnitudeCplx(int, fractcomplex*, fractional*); buffer++; //incrementa numero de amostragem if(buffer >= PONTOS_FFT) //confere se buffer de entrada esta cheio { buffer = 0; buffercheio = 1; DisableIntT1 ; //desabilita interrupcao do timer para executar os calculos da FFT } IFS0bits.T1IF = 0; /* limpa flag de interrupcao do timer */ void uart_init () //inicia modulo de comunicacao UART2, 9600,8,0,1 { unsigned int U2MODEvalue, U2STAvalue, baud; CloseUART2(); //fecha porta UART2 ConfigIntUART2 (UART_RX_INT_DIS & UART_RX_INT_PR5 & UART_TX_INT_DIS & UART_TX_INT_PR3); //configura interrupcoes UART2------ desabilitado interrupcoes baud = 191; //30 MIPS MHz e 9600 bps U2MODEvalue = UART_EN & UART_IDLE_CON & UART_RX_TX & UART_DIS_WAKE & UART_DIS_LOOPBACK & UART_DIS_ABAUD & UART_NO_PAR_8BIT & UART_1STOPBIT; U2STAvalue = UART_INT_TX_BUF_EMPTY & UART_TX_PIN_NORMAL & UART_TX_ENABLE & UART_INT_RX_3_4_FUL & UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR ;

Page 12: Relatorio Livia

OpenUART2(U2MODEvalue, U2STAvalue, baud); //inicia UART2 } //********************** Envia dados para o computador pela serial UART *************** void transmite_dados () { unsigned int dadotx; int a, modulo_int; float modulo_dec; //-------------------------------------------------------------------- dadotx = 252; // inicio do bloco de dados while(BusyUART2()); //aguarda fim da ultima transmissao WriteUART2(dadotx); //envia delayms(1); //-------------------------------------------------------------------- //envia parte inteira dos 64 sinais for ( a = 0; a < PONTOS_FFT/2; a++ ) //envia modulo das 64 frequencias pela serial { // Encontra o modulo de cada frequencia temp3_pnt = &sinalComplexo[0].real ; //inicializa ponteiro temp3_pnt = temp3_pnt + a; tempFrac = *temp3_pnt; tempFloat = tempFrac; tempFloat = tempFloat / 32767; // Converte fracionario para float modulo = sqrt (tempFloat); // Extrai a raiz quadrada da soma dos quadrados da parte real/imaginaria dadotx = (modulo * 100); // Escalona o sinal para enviar pela serial while(BusyUART2()); //aguarda fim da ultima transmissao WriteUART2(dadotx); //envia delayms(1); } //------------------------------------------------------------------------ dadotx = picoFrequenciaBin + 65;//envia indice de maior frequencia while(BusyUART2()); //aguarda fim da ultima transmissao WriteUART2(dadotx); //envia delayms(1); //------------------------------------------------------------------ dadotx = 253; //checa envio do bloco de dados while(BusyUART2()); //aguarda fim da ultima transmissao WriteUART2(dadotx); //envia delayms(1); //------------------------------------------------------------------ //envia parte decimal dos 64 sinais for ( a = 0; a < PONTOS_FFT/2; a++ ) //envia modulo das 64 frequencias pela serial { // Encontra o modulo de cada frequencia temp3_pnt = &sinalComplexo[0].real ; //inicializa ponteiro temp3_pnt = temp3_pnt + a; tempFrac = *temp3_pnt; tempFloat = tempFrac;

Page 13: Relatorio Livia

tempFloat = tempFloat / 32767; // Converte fracionario para float modulo = sqrt (tempFloat); // Extrai a raiz quadrada da soma dos quadrados da parte real/imaginaria modulo_int = (modulo * 100); //encontra a partem inteira do sinal modulo_dec = (modulo * 100) - modulo_int; //encontra a parte decimal do sinal dadotx = (modulo_dec * 100); //escalona para enviar pela serial if ( dadotx > 164 ) dadotx = 164; //limita parte decimal de 0 a 99 while(BusyUART2()); //aguarda fim da ultima transmissao WriteUART2(dadotx); //envia delayms(1); } //------------------------------------------------------------------ dadotx = 254; // fim do bloco de dados while(BusyUART2()); //aguarda fim da ultima transmissao WriteUART2(dadotx); //envia delayms(1); } //*********************************** MAIN int main (void) //inicio do programa { int i = 0; fractional *p_real = &sinalComplexo[0].real ; fractcomplex *p_complexo = &sinalComplexo[0] ; //-------------- Inicia pinos de I/O do dsPIC ---------------------------------- TRISB = 0xff0f; TRISFbits.TRISF0 = 0; TRISDbits.TRISD0 = 0; TRISDbits.TRISD1 = 0; //------------------ Inicia variaveis ------ n = 0; buffer = 0; buffercheio = 0; tempFloat = 0; //-----Inicia perifericos do dsPIC ----- uart_init (); //inicializa comunicacao UART

Page 14: Relatorio Livia

init_timer1 (); //inicia timer1 para interromper a 7,68 k samples //---- Envio de mensagem ao PSIM while (1) //loop infinito { if (buffercheio) //confere se chegou fim das amostragens { p_real = &sinalComplexo[0].real ; //inicializa ponteiro p_complexo = &sinalComplexo[0]; //inicializa ponteiro for ( i = 0; i < PONTOS_FFT; i++ ) //move buffer do sinal de entrada (real)para vetor da FFT { *p_real = sinal_Entrada [i] ; *p_real++; //incrementa o ponteiro } p_real = &sinalComplexo[0].real ; //inicializa ponteiro for ( i = 0; i < PONTOS_FFT; i++ ) //Escalona o vetor para o range [-0.5, +0.5] { *p_real = *p_real >>1 ; //desloca 1 bit para a direita *p_real++; } p_real = &sinalComplexo[(PONTOS_FFT/2)-1].real ; //inicializa o ponteiro para parte real do vetor p_complexo = &sinalComplexo[PONTOS_FFT-1] ; for ( i = PONTOS_FFT; i > 0; i-- ) //Converte vetor real para vetor complexo { (*p_complexo).real = (*p_real--); (*p_complexo--).imag = 0x0000; //Não possui parte imaginaria, escreve valor zero } // Cálculo da FFT - Transformada Rapida de Fourier FFTComplexIP (LOG2_ESTAGIOS_BUTTERFLY, &sinalComplexo[0], (fractcomplex *) __builtin_psvoffset(&twiddleFactors[0]), (int) __builtin_psvpage(&twiddleFactors[0]));

Page 15: Relatorio Livia

// Organiza dados da saída da FFT - Bit-reverso BitReverseComplex (LOG2_ESTAGIOS_BUTTERFLY, &sinalComplexo[0]); // Calcula a soma do quadrado das partes real e imaginária transformando vetor complexo em um vetor real. Sinal = real^2 + imaginario^2 SquareMagnitudeCplx(PONTOS_FFT, &sinalComplexo[0], &sinalComplexo[0].real); // Encontra a frequency Bin ( indice da frequencia) que possui a maior energia VectorMax(PONTOS_FFT/2, &sinalComplexo[0].real, &picoFrequenciaBin); // Calcula a frequencia em Hz com maior espectro picoFrequencia = picoFrequenciaBin*(TAXA_AMOSTRAGEM/PONTOS_FFT); // Encontra o modulo da frequencia de pico temp3_pnt = &sinalComplexo[0].real ; //inicializa ponteiro temp3_pnt = temp3_pnt + picoFrequenciaBin; tempFrac = *temp3_pnt; tempFloat = tempFrac; tempFloat = tempFloat / 32767; // Converte fracionario para float modulo = sqrt (tempFloat); // Extrai a raiz quadrada da soma dos quadrados da parte real/imaginaria //tempFloat = Fract2Float (tempFrac); //converte fracional para float, usando funcao da biblioteca DSP //modulo = sqrt (tempFloat); // Extrai a raiz quadrada da soma dos quadrados da parte real/imaginaria linha2 (11); //posiciona cursor do LCD buffer16 = modulo*100000; //ajusta valor para indicar no LCD lcdval16(); //envia modulo da frequencia para lcd linha1 (4); //posiciona cursor do LCD buffer16 = picoFrequencia; lcdval16(); //envia frequencia de pico para lcd transmite_dados (); //transmite dados pela serial UART (RS232) buffercheio = 0; EnableIntT1 ; //habilita interrupcao do timer para reiniciar amostragens } } } /* Fim */