http://arduino.cc/en/Tutorial/AnalogInputPins http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/ http://www.instructables.com/id/Arduino-is-Slow-and-how-to-fix-it/ doc atmel 328p: http://www.atmel.com/images/doc8161.pdf =====ligne de commande===== http://www.pobot.org/Arduino-en-ligne-de-commande.html http://inotool.org/ =====plot===== ===qt=== http://www.qcustomplot.com/index.php/download installation: tar -xvf QCustomPlot-source.tar.gz tar -xvf QCustomPlot.tar.gz cd qcustomplot tar -xvf ../QCustomPlot-sharedlib.tar.gz cd qcustomplot-sharedlib/sharedlib-compilation/ qmake sharedlib-compilation.pro make cd ../../examples/plots qmake plot-examples.pro make ===gnuplot=== http://www.gnuplot.info/ =====tns====== https://www.google.fr/search?client=ubuntu&channel=fs&q=fir+c+implementation&ie=utf-8&oe=utf-8&gfe_rd=cr&ei=sD7ZVJKjOYHo7Aau5oCwDg http://iowahills.com/A7ExampleCodePage.html https://sestevenson.wordpress.com/implementation-of-fir-filtering-in-c-part-1/ https://www.youtube.com/watch?v=fdCAsZkjpSg objectif appli audio filtre passe bande sur gbf- equation de récurence fournie 1° dev sous qt: on travaille sur des wav en double précision fitres simples, echo/ reverb boite génération signal (sinus amplitude et fréquence variable) filtre décimation programmation IT/timer adc 12 bits sur nucleo Solution: /* tlv5637 DAC demo Uses the tlv5637 library. For details on the sensor, see: www.ti.com/cn/lit/gpn/tlv5637 Circuit: CSB: pin 7 MOSI: pin 11 SCK: pin 13 REF: Apply 2.5 V to get output value from 0 to 5V and use REF_EXTERNAL_TLV5637 or Let open to get output value from 0 to 2V and use REF_1024MV_TLV5637 or Let open to get output value from 0 to 4V and use REF_2048MV_TLV5637 LED: pin 8 , flashes at the frequency of the generated signal OUTA: plug to a scope to observe a sinus waveform OUTB: plug to a scope to observe a triangle waveform created 14 July 20143 by Bertrand VANDEPORTAELE */ #include #include const int chipSelectPin = 3; //connect to the Chip Select of the TLV5637 //#define SIZETAB 300 #define SIZETAB 16 //corresponds to a period of approximately 625ms const int boutonPin = 9; const int ledPin = 8; int sinus[SIZETAB]; int cosinus[SIZETAB]; int cpt; //TLV5637 DAC(chipSelectPin,REF_EXTERNAL_TLV5637); TLV5637 DAC(chipSelectPin,REF_2048MV_TLV5637); const int XPin = A0; // select the input pin for the potentiometer int XValue = 0; // variable to store the value coming from the sensor const int YPin = A1; // select the input pin for the potentiometer int YValue = 0; // variable to store the value coming from the sensor //int const coef[4] = {185,-185,26577,-16013} ; // coeff a0,a2,b1,b2 codés avec 14 bits de partie décimale pour fn=1 kHz int coef[4] = {190,-190,-26202,16003} ; // coeff a0,a2,b1,b2 codés avec 14 bits de partie décimale pour fn=1 kHz int ek[3]; // e(k),e(k-1),e(k-2) int sk[3]; // s(k),s(k-1),s(k-2) unsigned int lecture ; signed long const puiss13=0x2000; // 2^13 pour test de l'arrondi void filtre(void) // ss-prg de filtrage { long int temp,temp1,temp2,temp3,temp4 ; // calcul intermediaire sur 32 bits int tmp1, tmp2 ; // calcul intermediaire sur 16 bits //P87 = 1; // visu du temps passé dans l'interruption digitalWrite(ledPin, 1); //sans DAC et ADC, la fonction prend 30us //avec DAC et ADC, la fonction prend 250us DAC.writeDACAB(sk[0]+512,ek[0] +512); ek[0] = analogRead(XPin)-512;//(ADDAT&0x3FF)-512; // valeur de l'echantillon sans valeur moyenne. lecture du resultat de la CAN // lancée lors de la derniere interruption /*if ( P24 == 0) { *CNA3 = (ek[0] +512) *4 ; // pour être sûr que tout va bien */ temp = (long int) (coef[0])*(long int)(ek[0]) // calcul sur 32 bits + (long int)(coef[1])*(long int)(ek[2]) // s(k) = a0.e(k) + a2.e(k-2) + b1.s(k-1) + b2.s(k-2) - (long int)(coef[2])*(long int)(sk[1]) - (long int)(coef[3])*(long int)(sk[2]) ; if (temp & puiss13 ) // calcul de l'arrondi sk[0] = (temp >> 14 ) + 1; // on pourrait optimiser car ensuite sk*4 lors e la conversion NA else // => on perd les 2 derniers chiffres significatifs sk[0] = (temp >> 14 ) ; if (sk[0] > 511 ) // saturation du résultat sur 10 bits sk[0] = 511 ; // rque : on pourrait garder plus de bits pour sk else if (sk[0] < -512 ) // car le résultat intermediaire temp est loin du débordement sk[0] = -512 ; // il faudrait alors saturer au moment de la conversion NA /* } else { temp1 = (long int) (coef[0])*ek[0] + coef[1]*ek[2]; // calcul sur 32 bits de b0.ek+b2.ek2 Q13.14 temp2 = (long int)(coef[2])*sk[1] + coef[3]*sk[2]; // calcul sur 32 bits de a1.sk1+a2.sk2 Q13.18 */ sk[2] = sk[1] ; // memorisations pour le prochain calcul sk[1] = sk[0] ; // sk[0] contient toujours le resultat des calculs ek[2] = ek[1] ; ek[1] = ek[0] ; // P87 = 0 ; // visu = 0 digitalWrite(ledPin, 0); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { // start serial port at 9600 bps: Serial.begin(9600); //delay(3O00); Serial.print("Bonjour"); pinMode(ledPin, OUTPUT); pinMode(boutonPin, INPUT); // start the tlv5637 library: DAC.powerOn(); DAC.speedFast(); cpt=0; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { filtre(); // delayMicroseconds(760); delayMicroseconds(250); } accès aux gpio lent avec digitalwrite: http://www.instructables.com/id/Arduino-is-Slow-and-how-to-fix-it/ pour générer signal carré sur broche 8 directement: while(1) { PORTB&=0xFE; PORTB|=1; } pour configurer un prescaler différent sur l'adc: http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/ // set up the ADC ADCSRA &= ~PS_128; // remove bits set by Arduino library ADCSRA |= PS_16; // set our own prescaler to 16 définitions des registres arduino sur machine Bvdp: /usr/lib/avr/include/avr/iom328p.h =====Génération des coefficients d'un filtre===== ===Design sous Matlab=== - Lancer fdatool - rentrer le gabarit - choisir une méthode de synthèse. - Targets->Generate C headers Ou: - Exporter ensuite le filtre vers le workspace en tant que coefficients. (File->export export) - Exécuter le script export_coeff('nom_fichier',coef_num,coef_den) pour générer nom_fichier .h avec la déclaration des tableaux num et den en double. pour un RIF export_coeff('monfiltre',Num) pour un RII export_coeff("monfiltre",Num,Den) function export_coeff(nom,num,den) % génère un fichier nom.h contenant la déclaration d'un ou deux tableaux de % double (appelés num et den !!!) % Ecrase le fichier existant sans prévenir ... error(nargchk(2, 3, nargin)) if ischar(nom) == 0 error('le nom n est pas une chaine de caractère') end fp = fopen(strcat(nom,'.h'),'w+'); if fp == -1 error('erreur creation fichier') end fprintf(fp,['// Fichier généré par export_coeff.m\n\n#define SIZEFILTER %u \n\nconst double num[SIZEFILTER] = {%.16f'],size(num,2),num(1)); % .7e doit être mieux if size(num,2)>1 for i=2:size(num,2), fprintf(fp,',%.16f',num(i)); end end fprintf(fp, '};\n'); if nargin == 3 fprintf(fp,['const double den[%u] = {%.16f'],size(den,2),den(1)); if size(den,2)>1 for i=2:size(den,2), fprintf(fp,',%.16f',den(i)); end end fprintf(fp, '};\n'); end fclose(fp); ===Visualisation module de la fonction de transfert=== fvtool(num,den) l'affichage se fait en fréquence normalisée par défaut: 1 correspond à Fech/2 exemple pour le filtre moyenne matlab n=[0.5 0.5] fvtool(n,1) relevé de la fréquence de coupure à -3db, on peut également voir les réponses temporelles et la phase. ===Implémentation arduino=== l'it de filtre RIF nécessite 300us sur les 500us dispo à 2Khz /* tlv5637 DAC demo Uses the tlv5637 library. For details on the sensor, see: www.ti.com/cn/lit/gpn/tlv5637 Circuit: CSB: pin 7 MOSI: pin 11 SCK: pin 13 REF: Apply 2.5 V to get output value from 0 to 5V and use REF_EXTERNAL_TLV5637 or Let open to get output value from 0 to 2V and use REF_1024MV_TLV5637 or Let open to get output value from 0 to 4V and use REF_2048MV_TLV5637 LED: pin 8 , flashes at the frequency of the generated signal OUTA: plug to a scope to observe a sinus waveform OUTB: plug to a scope to observe a triangle waveform created 14 July 20143 by Bertrand VANDEPORTAELE */ #include #include const int chipSelectPin = 3; //connect to the Chip Select of the TLV5637 //#define SIZETAB 300 #define SIZETAB 16 //corresponds to a period of approximately 625ms const int boutonPin = 9; const int ledPin = 8; int sinus[SIZETAB]; int cosinus[SIZETAB]; int cpt; //TLV5637 DAC(chipSelectPin,REF_EXTERNAL_TLV5637); TLV5637 DAC(chipSelectPin,REF_2048MV_TLV5637); const int XPin = A0; // select the input pin for the potentiometer int XValue = 0; // variable to store the value coming from the sensor const int YPin = A1; // select the input pin for the potentiometer int YValue = 0; // variable to store the value coming from the sensor //int const coef[4] = {185,-185,26577,-16013} ; // coeff a0,a2,b1,b2 codés avec 14 bits de partie décimale pour fn=1 kHz int coef[4] = {190,-190,-26202,16003} ; // coeff a0,a2,b1,b2 codés avec 14 bits de partie décimale pour fn=1 kHz //int ek[3]; // e(k),e(k-1),e(k-2) //int sk[3]; // s(k),s(k-1),s(k-2) unsigned int lecture ; signed long const puiss13=0x2000; // 2^13 pour test de l'arrondi const unsigned char PS_16 = (1 << ADPS2); const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0); const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1); const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); #define SIZEFILTER 41 const double tabcoef[SIZEFILTER]={ 0.016244657856333,-0.018864421488768,-0.012238782422342,-0.005085409431928,0.003969691594410, 0.012267146479049, 0.015030618183398, 0.008966346831124, -0.004682203645285,-0.019357735197421,-0.025875762043837,-0.017435787337996, 0.005471034822059, 0.033037851847265, 0.049218355348873, 0.038520192602532, -0.006112347636894,-0.078041093847378,-0.157847718052422,-0.220135476387537,0.756344281504610,-0.220135476387537,-0.157847718052422,-0.078041093847378, -0.006112347636894, 0.038520192602532, 0.049218355348873, 0.033037851847265,0.005471034822059,-0.017435787337996,-0.025875762043837,-0.019357735197421, -0.004682203645285, 0.008966346831124, 0.015030618183398, 0.012267146479049,0.003969691594410,-0.005085409431928,-0.012238782422342,-0.018864421488768, 0.016244657856333}; int tabcoefint[SIZEFILTER]; int ek[SIZEFILTER]; // e(k),e(k-1),e(k-2)... int sk[SIZEFILTER]; //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// inline void filtre_rii(void) // ss-prg de filtrage { long int temp,temp1,temp2,temp3,temp4 ; // calcul intermediaire sur 32 bits int tmp1, tmp2 ; // calcul intermediaire sur 16 bits //P87 = 1; // visu du temps passé dans l'interruption //digitalWrite(ledPin, 1); PORTB|=1; //sans DAC et ADC, la fonction filtre_rii() prend 30us //avec DAC et ADC, la fonction prend 250us DAC.writeDACAB(sk[0]+512,ek[0] +512); //prend 70us dont 35 pour les cS avec digitalwrite ek[0] = analogRead(XPin)-512;//(ADDAT&0x3FF)-512; // valeur de l'echantillon sans valeur moyenne. lecture du resultat de la CAN //prend 120us // lancée lors de la derniere interruption /*if ( P24 == 0) { *CNA3 = (ek[0] +512) *4 ; // pour être sûr que tout va bien */ temp = (long int) (coef[0])*(long int)(ek[0]) // calcul sur 32 bits + (long int)(coef[1])*(long int)(ek[2]) // s(k) = a0.e(k) + a2.e(k-2) + b1.s(k-1) + b2.s(k-2) - (long int)(coef[2])*(long int)(sk[1]) - (long int)(coef[3])*(long int)(sk[2]) ; if (temp & puiss13 ) // calcul de l'arrondi sk[0] = (temp >> 14 ) + 1; // on pourrait optimiser car ensuite sk*4 lors e la conversion NA else // => on perd les 2 derniers chiffres significatifs sk[0] = (temp >> 14 ) ; if (sk[0] > 511 ) // saturation du résultat sur 10 bits sk[0] = 511 ; // rque : on pourrait garder plus de bits pour sk else if (sk[0] < -512 ) // car le résultat intermediaire temp est loin du débordement sk[0] = -512 ; // il faudrait alors saturer au moment de la conversion NA /* } else { temp1 = (long int) (coef[0])*ek[0] + coef[1]*ek[2]; // calcul sur 32 bits de b0.ek+b2.ek2 Q13.14 temp2 = (long int)(coef[2])*sk[1] + coef[3]*sk[2]; // calcul sur 32 bits de a1.sk1+a2.sk2 Q13.18 */ sk[2] = sk[1] ; // memorisations pour le prochain calcul sk[1] = sk[0] ; // sk[0] contient toujours le resultat des calculs ek[2] = ek[1] ; ek[1] = ek[0] ; // P87 = 0 ; // visu = 0 // digitalWrite(ledPin, 0); PORTB&=0xFE; } int t=0; //pour gestion buffer circulaire //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// //////////// inline void filtreRIF(void) // ss-prg de filtrage { long int temp,temp1,temp2,temp3,temp4 ; // calcul intermediaire sur 32 bits int tmp1, tmp2 ; // calcul intermediaire sur 16 bits //P87 = 1; // visu du temps passé dans l'interruption //digitalWrite(ledPin, 1); PORTB|=1; DAC.writeDACAB(sk[0]+512,ek[t] +512); //prend 70us dont 35 pour les cS avec digitalwrite ek[t] = analogRead(XPin)-512;//(ADDAT&0x3FF)-512; // valeur de l'echantillon sans valeur moyenne. lecture du resultat de la CAN //prend 120us // lancée lors de la derniere interruption /*if ( P24 == 0) { *CNA3 = (ek[0] +512) *4 ; // pour être sûr que tout va bien */ temp=0; int i; int j=t; for (i=0;i> 14 ) + 1; // on pourrait optimiser car ensuite sk*4 lors e la conversion NA else // => on perd les 2 derniers chiffres significatifs sk[0] = (temp >> 14 ) ; if (sk[0] > 511 ) // saturation du résultat sur 10 bits sk[0] = 511 ; // rque : on pourrait garder plus de bits pour sk else if (sk[0] < -512 ) // car le résultat intermediaire temp est loin du débordement sk[0] = -512 ; // il faudrait alors saturer au moment de la conversion NA /* sk[2] = sk[1] ; // memorisations pour le prochain calcul sk[1] = sk[0] ; // sk[0] contient toujours le resultat des calculs ek[2] = ek[1] ; ek[1] = ek[0] ; */ // P87 = 0 ; // visu = 0 t=(t+1)%SIZEFILTER; // digitalWrite(ledPin, 0); PORTB&=0xFE; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { // start serial port at 9600 bps: Serial.begin(9600); //delay(3O00); Serial.print("Bonjour"); // Serial.println(3,DEC); // Serial.println(-3%4,DEC); // while(1); pinMode(ledPin, OUTPUT); pinMode(boutonPin, INPUT); // start the tlv5637 library: DAC.powerOn(); DAC.speedFast(); cpt=0; int i; // tabcoef[41]={ 0.016244657856333,-0.018864421488768,-0.012238782422342,-0.005085409431928,0.003969691594410, 0.012267146479049, 0.015030618183398, 0.008966346831124, -0.004682203645285,-0.019357735197421,-0.025875762043837,-0.017435787337996, 0.005471034822059, 0.033037851847265, 0.049218355348873, 0.038520192602532, -0.006112347636894,-0.078041093847378,-0.157847718052422,-0.220135476387537,0.756344281504610,-0.220135476387537,-0.157847718052422,-0.078041093847378, -0.006112347636894, 0.038520192602532, 0.049218355348873, 0.033037851847265,0.005471034822059,-0.017435787337996,-0.025875762043837,-0.019357735197421, -0.004682203645285, 0.008966346831124, 0.015030618183398, 0.012267146479049,0.003969691594410,-0.005085409431928,-0.012238782422342,-0.018864421488768, 0.016244657856333}; for (i=0;i Découpler la partie acquisition/commande de la partie calcul, pour pouvoir exploiter la partie calcul dans QT ajouter partie quantification dans QT ====implémentation arduino===== Pour connaître la place disponible en ram: http://playground.arduino.cc/Code/AvailableMemory int freeRam () { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } De base avec Serial, il reste de l'ordre de 1600 octets disponibles en RAM =====install arduino 1.6.0===== ouvrir une un console cd ~/Téléchargements/ wget http://arduino.cc/download_handler.php?f=/arduino-1.6.0-linux64.tar.xz tar xf download_handler.php?f=%2Farduino-1.6.0-linux64.tar.xz cd arduino-1.6.0 ./arduino Cette nouvelle version utilisera le même fichier de config ~/.arduino que la version 1.5 et ira chercher les sketchs dans ~/sketchbook La nouvelle version affiche: Le croquis utilise 450 octets (1%) de l'espace de stockage de programmes. Le maximum est de 32 256 octets. Les variables globales utilisent 9 octets (0%) de mémoire dynamique, ce qui laisse 2 039 octets pour les variables locales. Le maximum est de 2 048 octets. =====Gestion fichiers wav===== TODO: vérifier qu'on a le nécessaire pour lire les wav sinon ajouter à apt-get: sudo apt-get install libsndfile1-dev sndfile-tools http://www.mega-nerd.com/libsndfile/ http://www.mega-nerd.com/libsndfile/api.html http://www.mega-nerd.com/libsndfile/tools/ code source du chirp: http://sndfile-tools.sourcearchive.com/documentation/1.03-2/sndfile-generate-chirp_8c-source.html sndfile-generate-chirp -linear -from 100 -to 2000 11000 5 /tmp/chirp.wav sndfile-spectrogram /tmp/chirp.wav 800 800 /tmp/image.png && display /tmp/image.png sndfile-spectrogram /home/bvandepo/Bureau/IUT/qt/wav/cartoon1.wav 800 800 /tmp/image.png && display /tmp/image.png sndfile-spectrogram /home/bvandepo/Bureau/IUT/qt/wav/jonathan_chirp.wav 800 800 /tmp/image.png && display /tmp/image.png sndfile-spectrogram /home/bvandepo/Bureau/IUT/qt/wav/jonathan_chirpout.wav 800 800 /tmp/image.png && display /tmp/image.png =====Calcul du module d'un filtre numérique en C===== // coefficients fournis dans tableau num et den en double. Résultat dans tableau module en double void calc_module (unsigned int nb_pt, long unsigned int fmin,long unsigned int fmax,long unsigned int fe, double* num,double* den, short unsigned int taille_num,short unsigned int taille_den, double* module ) {double ren,imn,red,imd,freq ; for (unsigned int ind=0; ind<=nb_pt-1; ind++) { freq = fmin + ind*(double(fmax-fmin))/(double(nb_pt-1)); ren=0;imn=0;red=0;imd=0; for (unsigned int k=0; k Tests : //Pbas butter ordre 2, fc=1000, fe=100000 double n_rii[3] = {0.0009446918438402,0.0018893836876803,0.0009446918438402}; double d_rii[3] = {1.0000000000000000,-1.9111970674260730,0.9149758348014336}; //LPC10, fe=8000 double n_lpc[1] = {1.0000000000000000}; double d_lpc[10] = {-0.9066005084154077,-0.0894023777130527,-0.0737403635454538,-0.1058346286389015,-0.0805322009937170,0.7530041872610538,-0.2893637471696474,-0.0765682373294319,0.1198196170751025,-0.0831829803216555}; //PHaut FIR ordre20, fe=48000, fs=1000, fp=2000 double n_fir[21] = {-0.0242371571968972,-0.0301724044152419,-0.0361555490565042,-0.0420070672503898,-0.0475441084943809,-0.0525880968984849,-0.0569723066108962,-0.0605490435416172,-0.0631960811056043,-0.0648220319326880,0.9346296113838384,-0.0648220319326880,-0.0631960811056043,-0.0605490435416172,-0.0569723066108962,-0.0525880968984849,-0.0475441084943809,-0.0420070672503898,-0.0361555490565042,-0.0301724044152419,-0.0242371571968972}; double d_fir[1] = {1.0}; double module[1000]; // calc_module(1000,100,50000,100000,n_rii,d_rii,3,3,module); // calc_module(1000,100,4000,8000,n_lpc,d_lpc,1,10,module); calc_module(1000,100,24000,48000,n_fir,d_fir,21,1,module);