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