Cours sur les Processeurs de Traitement du Signal (DSP)
Thèmes abordés
Cours sur les Processeurs de Traitement du Signal (DSP)
Thèmes abordés
Cours
Sylvain Montagny
04 79 75 86 86
1 LE TRAITEMENT DU SIGNAL NUMERIQUE ............................................................................................ 2
1.1 LA CHAINE DE TRAITEMENT ....................................................................................................................... 2
1.2 LE FILTRAGE NUMERIQUE ......................................................................................................................... 3
1.3 LE VIEILLISSEMENT DES ECHANTILLONS POUR LE FILTRAGE NUMERIQUE .............................................................. 5
2 REPRESENTATION NUMERIQUE DU SIGNAL ......................................................................................... 8
2.1 CODAGE DES NOMBRES ENTIERS ................................................................................................................ 8
2.2 CODAGE DES NOMBRES REELS ................................................................................................................... 9
2.3 L'ERREUR DE QUANTIFICATION ................................................................................................................ 11
2.4 RELATION ENTRE LE CODAGE DES NOMBRES ET LE TYPE DE VARIABLE ............................................................... 13
3 LES PROCESSEURS DE TRAITEMENT DU SIGNAL ................................................................................. 14
3.1 LES DEUX TYPES DE PROCESSEUR .............................................................................................................. 14
3.2 L'UNITE ARITHMETIQUE ET LOGIQUE (UAL) ............................................................................................... 15
3.3 LE PIPELINE ......................................................................................................................................... 15
3.4 LA GESTION DES BOUCLES....................................................................................................................... 18
3.5 LES BUS D'ACCES AUX MEMOIRES ............................................................................................................. 20
3.6 RESUME ............................................................................................................................................. 21
4 REALISATION DES CALCULS DANS LE PROCESSEUR ............................................................................ 21
4.1 L’ADDITION DES NOMBRES ENTIERS .......................................................................................................... 21
4.2 ADDITION EN VIRGULE FIXE ..................................................................................................................... 22
4.3 MULTIPLICATION EN ENTIERS SIGNES ........................................................................................................ 23
4.4 MULTIPLICATION EN VIRGULE FIXE ........................................................................................................... 24
4.5 ETUDE D'UN CAS CONCRET : FILTRE FIR .................................................................................................... 27
5 PROGRAMMATION D'UN FILTRE NUMERIQUE................................................................................... 32
5.1 TRAITEMENT EN TEMPS REEL / TRAITEMENT PAR BLOC ................................................................................. 32
5.2 OPTIMISATION DU CALCUL ..................................................................................................................... 32
5.3 UTILISATION DE CMSIS DSP .................................................................................................................. 35
6 SOLUTIONS DES EXERCISES ................................................................................................................ 37
| 1
1 Le traitement du signal numérique
1.1 La chaine de traitement
1.1.1 Les différents étages
La chaine de traitement de l'information peut être représentée par la Figure 1.
Analogique Analogique
Mémoire
Numérique
Le filtre anti-repliement sert à supprimer les hautes fréquences du signal de façon à respecter le
théorème de Shannon pour l'échantillonnage qui sera réalisé par le CAN.
Le filtre de reconstruction sert à supprimer les hautes fréquences du signal qui sont apparues lors
de l'échantillonnage : le spectre est dupliqué à l'infini d'une période équivalente à la fréquence
d'échantillonnage.
Les filtres anti-repliement et les filtres de reconstruction sont (bien sûr) obligatoirement
analogique.
| 2
■ Il peut être fait en multitâche
■ Il n'est pas contraint aux variations des valeurs de composants analogiques
Soit les deux filtres numériques suivants. Trouvez leurs fonctions récurrentes respectives,
c’est-à-dire l'expression de l'échantillon de sortie en fonction des échantillons d'entrées
précédents (FIR) ou des échantillons d'entrées et de sorties précédents (IIR).
| 3
Figure 3 : Réponse en fréquence du filtre IIR
Round output(n)
| 4
while ( 1 ) {
■ Récupération d'un nouvel échantillon (CAN) et stockage en mémoire
X
0 ech0 coeff0
1 ech1 coeff1
2 ech2 coeff2
… … …
… … Multiplication …
N-2 echN-2 coeff x ech coeffN-2
N-1 echN-1 coeffN-1
Figure 6 : Tableau d'échantillons et de coefficients
| 5
@ du tableau Echantillons
0 newEch Injection du nouvel échantillon
1 ech0
2 ech1
… ech2 Décalage vers le bas et suppression
… … du plus vieil échantillon (echN-1)
N-2 …
N-1 echN-2
Figure 7 : Réalisation d'un buffer linéaire
Compléter le code suivant pour réaliser le calcul complet du filtre numérique en langage C.
float coeff[N] = { , , ... , , };
uint16_t ech[N];
uint16_t newEch;
uint16_t output = 0;
void main(void){
while(1){
// Reception d'un echantillon depuis le CAN
HAL_SAI_Receive(&newEch);
| 6
@ du tableau Echantillons Coefficients
0 … coeff0
X
1 echN-2 coeff1
2 echN-1 coeff2
… ech0 …
ech1 …
N-2 … coeffN-2
N-1 … coeffN-1
Figure 8 : Tableau d'échantillons et de coefficients à T = t
Dans la Figure 8, l'échantillon le plus ancien est echN-1. A t = t + 1, il sera remplacé par le nouvel
échantillon nommé newEch.
X
1 echN-2 coeff1
2 newEch coeff2
… ech0 …
… ech1 …
N-2 … coeffN-2
N-1 … coeffN-1
Figure 9 : Tableau d'échantillons et de coefficients à T = t + 1
Vous devez particulièrement faire attention dans quel sens votre tableau d'échantillon fonctionne.
Dans notre cas, lorsque le tableau était vide, nous avons injecté le premier échantillon à la case N-
1. Le second à la case N-2, etc… Vous pouvez tout à fait commencer par le haut : premier échantillon
à l'adresse 0, le second à l'adresse 1, etc… Il faut simplement penser à ajuster votre calcul du filtre
numérique en conséquence lorsque vous multiplier les coefficients et les échantillons.
Compléter le code suivant pour réaliser le calcul complet du filtre numérique en langage C.
void main(void){
while(1){
// Reception d'un echantillon depuis le CAN
HAL_SAI_Receive(&newEch);
| 7
// Vieillissement du Buffer circulaire : MAJ de l'index
// A COMPLETER
Donner la plage de codage des nombres entiers non signés en fonction du nombre de bit N
Donner la plage de codage des nombres entiers signés en fonction du nombre de bit N. Donner la
représentation binaire des nombres de -4 à 3 du tableau suivant. Quelle opération binaire nous fait
passer de 3 à -4.
| 8
Nombre Codage
3 011
2 010
1 001
0 000
-1 111
-2 110
-3 101
-4 100
Cette propriété est intéressante mais devra être contrôlée. Dans certains cas, nous souhaitons une
saturation du signal au valeur max et min lorsqu'il y a un dépassement, dans d'autres cas, nous
préférons un rebouclage.
■ Précision : L'intervalle entre deux valeurs codées doit être le plus petit possible
■ Dynamique : La plage des valeurs codées doit être la plus grande possible
m-1 1 0 -1 -2 -k
-2 2 2 2 2 2
Nombre codé en C à 2
| 9
La valeur de k doit obligatoirement être connue. On appelle une représentation en Qk, la
représentation en virgule fixe avec k bits réservés pour la partie décimale. Parfois, pour
être plus explicite, la représentation est donnée en Qm.k.
Donner la plage de codage des nombres réels codés en virgule fixe en fonction de N et k.
Soit la représentation binaire suivante : 0101 1101. Quelle est sa valeur si on considère ce nombre
en représentation Q2, Q4, Q7?
■ Q2 : 23.25
■ Q4 : 5.8125
■ Q7 : 0.7265625
Soit une représentation d'un nombre réel en Q5 sur 8 bits. Donner la plus petite valeur, la plus grande
valeur, ainsi que l'erreur maximale réalisée sur le codage.
Sur 8 bits, quel format Qk faut-il choisir pour optimiser au mieux le codage d'un nombre en virgule
fixe pour les plages de nombres suivants. Donner la précision (+/-) pour chacun des codages choisis.
■ -1 ≤ Nombre <1
■ -6 ≤ Nombre ≤ -4
■ 200 ≤ Nombre ≤ 200
■ -0.1 ≤ Nombre ≤ 0
Donner la représentation en virgule fixe sur 8 bits, des nombres suivants dans un format Qk
commun.
■ 98.895
■ 0.01298
■ 98.895
■ 10.1
■ 0.01298
■ -128000
| 10
En binaire, la représentation est similaire mais en base 2 :
Exposant Mantisse
Dans le cas d'une représentation en virgule flottante avec 4 bits pour la mantisse et 4 bits pour
l'exposant, donner la représentation binaire des nombres suivants :
■ 98.895
■ 0.01298
La norme IEEE définissant la représentation en virgule flottante est très proche de celle
que nous venons de réaliser et les propriétés restent similaires.
L'erreur relative permet d'exprimer l'erreur en %. C'est le rapport entre l'erreur de quantification et
la valeur exact du nombre à coder :
ε quantification
■ ε relative (%) = x100
Nombre
Nous travaillerons sur les nombres vus précédemment (98,895 et 0,01298) codés soit en virgule fixe
(en Q0), soit en virgule flottante (4 bits pour l'exposant et 4 bits pour la mantisse). Nous allons
étudier l'erreur relative maximale lorsque nous travaillons avec des petits nombres (autour de
0,01298) et des grands nombres (autour de 98,895). Remplir les colonnes Codage, ɛabsolue et ɛrelative
du tableau suivant :
| 11
Codage Virgule Fixe
Nombre Codage ɛabsolue ɛrelative ɛabsolue max ɛrelative max
98.895 99 0.105 0.11 % +/- 0.5 0.5 %
0.01298 0 0.01298 100 % +/- 0.5 3852 %
Codage Virgule Flottante
Nombre Codage ɛabsolue ɛrelative ɛabsolue max ɛrelative max
98.895 96 2.895 2.93 % +/- 8 8.09 %
0.01298 0.01367 0.00069 5.31 % +/- 0.00098 7.52 %
Tableau 1 : Erreur absolue et relative suivant les méthodes de codage
Sur la Figure 12, donner l'évolution de cette erreur relative en fonction du nombre à coder.
Erreur
relative
Valeur max
du signal d'entrée
Valeur du nombre
Sur la Figure 12, donner l'évolution de cette erreur relative en fonction du nombre à coder.
| 12
Erreur
relative
Valeur max
du signal d'entrée
Dans le tableau suivant, donner les plages de valeurs de chacune des variables.
32 bits
float Réel signé 24 bits de mantisse -3,4 x 1038 à 3,4 x 1038
8 bits d’exposant
64 bits
double Réel signé 53 bits de mantisse -1,7 x 10308 à 1,7 x 10308
11 bits d’exposant
| 13
3 Les processeurs de traitement du signal
3.1 Les deux types de processeur
Nous avons vu au chapitre 2.2 deux façons de coder les nombres réels : le codage en virgule fixe et
le codage en virgule flottante. Ces deux méthodes sont à l'image des deux technologies de
processeurs.
Avantages :
Inconvénients :
■ L'arithmétique a virgule fixe est beaucoup plus complexe, notamment pour la gestion des
débordements et du recadrage des données. Nous étudierons ces différents aspects au
chapitre 4.2 et 4.4.
Dans un DSP à virgule fixe (qui ne possède pas d'unité d'arithmétique flottant), nous ne
devrions pas utiliser de type float car cela réduit considérablement les performances de
l'algorithme.
■ Dans un DSP à virgule flottante (FPU single precision), les calculs en float s'exécutent à la
même vitesse que les calculs avec les nombres entiers.
■ Dans un DSP à virgule flottante (FPU double precision), les calculs en double s'exécutent à
la même vitesse que les calculs avec les nombres entiers ou float.
Dans un DSP à virgule flottante Single Precision, nous ne devrions pas utiliser de type
double car cela réduit considérablement les performances de l'algorithme.
| 14
Avantages :
La programmation de l'algorithme est très simplifiée car nous n'avons pas besoin de gérer la
dynamique des données sur lesquels nous travaillons.
Inconvénients :
Round output(n)
2n+1 bits 2n+2 bits n bits
2n+q bits
Exemple : Les multiplications de 2 nombres de 16 bits donnent un résultat sur 32 bits. Les additions
successives donnent des résultats sur 33, 34, 35… bits. En conséquence, les DSP (par exemple le
TMS320C54 de chez Texas Instruments) prévoient des accumulateurs de 40 bits pour garantir la
précision.
3.3 Le pipeline
3.3.1 Objectif et fonctionnement
Contrairement à ce que nous pourrions imaginer, l'objectif n'est pas d'augmenter la vitesse de
traitement d'une instruction mais de faire en sorte que plus d'instructions soit traitées en un temps
donné.
| 15
Pour comprendre le principe, il faut analyser l'ensemble des étapes permettant de parvenir au
traitement d'une instruction. Nous prendrons l'exemple d'un processeur DSP Texas Instrument
TMS320C54.
Stage Description
P - Prefetch Incrémentation du compteur ordinal
F - Fetch Lecture du code de l’instruction en mémoire
D - Decode Décodage de l’instruction
A - Access Calcul des adresses des opérandes et du résultat
R –Read Lecture des opérandes
X – Execute Exécution de l'instruction et écriture du résultat
Figure 16 : Les 6 étages du pipeline d'un DSP TMS320C54
P F D A R X Temps
Représenter sur la Figure 17 le déroulement d'une deuxième instruction si nous considérons pour
l'instant que le processeur n'utilise pas de pipeline. En combien de cycle est réalisé chacune des
instructions ?
P F D A R X Temps
| 16
On considère maintenant un cas pratique représentant l'appelle d'une fonction (Instruction CALL)
qui constitue un saut en mémoire.
FUNCTION Instruction 10
Instruction 11
Instruction 12 // RETURN
Représenter sur la Figure 19, le chargement des instructions dans le pipeline dans le cas du
programme précédent. Mettez en évidence la vidange du pipeline.
P1 F1 D1 A1 R1 X1 Temps
Les vidanges du pipeline dues à des sauts en mémoire sont anticipées (et évitées !) avec le plus de
réussite possible si le processeur possède des prédicteurs de branchement. Un ARM cortex M3 ne
possède pas de prédicteur de branchement. Un ARM cortex M7 en possède un.
| 17
Stage Description Circuit utilisé
P - Prefetch Incrémentation du compteur ordinal Compteur ordinal
F - Fetch Lecture du code de l’instruction en mémoire Mémoire Instruction
D - Decode Décodage de l’instruction Décodeur
A - Access Calcul des adresses des opérandes et du résultat UAL
R –Read Lecture des opérandes Mémoire donnée
X – Execute Exécution de l'instruction et écriture du résultat UAL et mémoire donnée
Figure 20 : Utilisation des ressources du processeur à chaque étage du pipeline.
On imagine que le programmeur d'une l'application a utilisé la même mémoire pour les instructions
et pour les données. Quels étages du pipeline ne pourront plus se dérouler simultanément ?
Représenter sur la Figure 21 le pipeline et mettre en évidence les retards engendrés.
PROGRAM : Instruction 1
Instruction 2
Instruction 3
Instruction 4
Instruction 5
Instruction 6
Instruction 7
P1 F1 D1 A1 R1 X1 Temps
Les aléas du pipeline sont très dommageables pour la rapidité de l'exécution de l'algorithme. Il
convient donc au programmeur de vérifier que l'emplacement de l'ensemble de son code soit
pertinent vis-à-vis de l'architecture utilisée.
| 18
@ du tableau Coefficients Echantillons
0 coeff0 ech0
1 coeff1 ech1
2 coeff2 ech2
… … …
N-1 coeffN-1 echN-1
Redonner l'expression du calcul du filtre numérique en langage C en utilisant une boucle for.
Cette boucle logicielle intègre une instruction essentielle en traitement du signal, il s'agit d'une
instruction de multiplication et d'accumulation : MAC [ Multiply And Accumulate ] :
A = A + coeff * ech
MAC coeff_ptr, ech_ptr, A
L'instruction MAC n'est pas suffisante pour réaliser l'ensemble de l'algorithme. Il faut aussi :
■ Incrémenter les index des opérandes dans les tableaux (coefficients et échantillons)
■ Vérifier que la boucle est réaliser N fois
Ces actions alourdissent la boucle de traitement. Un DSP doit trouver un moyen d'optimiser la
réalisation de ces deux opérations sans pénaliser le temps d'exécution.
L'idée des architecture DSP est de dédier une nouvelle UAL très simple qui réalisera ces calculs
automatiquement sans utiliser l'UAL principale du DSP. Avec cette méthode, à chaque instruction
MAC réalisée, les pointeurs ech_ptr et coeff_ptr seront automatiquement incrémenté et prêt pour
la prochaine instruction MAC.
MAC coeff_ptr+, ech_ptr+, A
X
1 ech1 coeff1
2 ech2 coeff2
… … …
N-2 echN-2 coeffN-2
N-1 echN-1 coefN-1
| 19
Au lieu de faire une boucle de N itération qui demande d'incrémenter l'index de la boucle for et de
vérifier sa valeur, il est possible de bloquer le PC (Program Counter) afin de réaliser la même
opération N fois. Dans les DSP, cette astuce est rendue possible par la présence d'instruction
REPEAT.
REPEAT N
MAC coeff_ptr+, ech_ptr+, A
Cela nécessite la présence de buffer circulaire matériel au sein du processeur. Seul les vrais DSP
possède ce type de circuit. Les DSC (Digital Signal Controller) n'en possèdent pas. Pour les DSC,
l'utilisation des buffers circulaires est donc beaucoup moins intéressante que pour les DSP. D'autres
techniques sont donc utilisées pour essayer de s'en approcher, sans pour autant y parvenir
complètement.
Mémoire Programme
CPU
Mémoire Données
D'après les étages du pipeline présenté Figure 16 dans le processeur TMS320C54, combien d'accès
mémoire simultanées avons-nous besoin? Compléter le schéma de l'architecture de Harvard
modifiée du DSP Figure 23.
| 20
Mémoire Programme
CPU
Mémoire Données
3.6 Résumé
while ( 1 ) {
■ Récupération d'un nouvel échantillon (CAN) et stockage en mémoire
■ a : 1er opérande
■ b : 2ème opérande
■ sign( ) : Sign de l’opérante
■ r : Résultat
■ n : Nombre de bits
■ k : Nombre de bits après la virgule
| 21
■ nr = max(na,nb) + 1 (on a une éventuelle retenue)
Mais il faut savoir que si sign(a) = sign(b) alors il y a un débordement possible. En effet, le résultat
du calcul de 7 + 3 suivant est faux :
𝟏𝟏 𝟏𝟏 𝟏𝟏
0 1 1 1
0 0 1 1
1 0 1 0
On trouve -6, il faut donc bien penser au bit de retenue.
Il faut une représentation commune des nombres : ici on travaille sur 4 bits (nombre de -8 à 7). Il
faut donc anticiper un résultat sur 5 bits.
■ Aligner la virgule
■ Réaliser l’extension de signe à gauche pour la partie entière
■ Etendre le nombre de bit à droite pour la partie décimale
| 22
Pour les débordements, on se retrouve dans la même configuration que pour les nombres entiers
signé.
Exemple : Soit l'addition de a au format Q1.4 et de b au format Q2.2. Le format Qk commun est donc
Q2.4. On prend en compte la retenue possible du résultat, donc le résultat sera codé en Q3.4. Pour la
réalisation des calculs :
| 23
Exemple, réaliser le calcul de 7 x -8 = -56 en binaire (7 et 8 seront codés sur 4 bits)
Le format Qk peut être différent. La méthode consiste juste à réaliser l’extension de signe à gauche
pour la partie entière. Le reste du calcul se fait de façon classique pour une multiplication.
Exemple : Soit la multiplication de a au format Q1.4 et de b au format Q2.2. Le résultat sera codé en
Q3.6. Pour la réalisation des calculs :
Réaliser le calcul de :
Si on travaille sur deux opérandes (coefficients et échantillons sur 16 bits), le résultat du calcul est
sur 32 bits, comme nous l'avons déjà prouvé [ nr = na + nb = 32 bits ]. A la fin du calcul, le résultat
doit être recadré sur 16 bits pour pouvoir être à nouveau utilisé. Le problème est de savoir quels
bits nous devons conserver. Nous avons alors un compromis à faire :
■ Plus nous gardons des bits à droite, plus nous gardons de la précision dans le résultat, mais
plus nous avons de chance de perdre des bits significatifs.
■ Plus nous gardons des bits à gauche, plus nous gardons des bits significatifs, mais plus nous
réalisons un arrondi du résultat.
| 24
4.4.3 Multiplication avec perte de précision, cas du traitement du signal
En traitement numérique du signal, les deux opérandes sont :
■ Coefficients au format Qk
■ Echantillons au format Qk'
Le résultat est donc au format Qk+k'. Lors de l'arrondi du nombre, on cherche toujours à
revenir sur le format des échantillons, soit le format Qk'. D'une part parce que le résultat
lui-même servira d'échantillon dans les calculs suivants (cas d'un filtre IIR), d'autre part
parce que le format des échantillons qui a été récupéré par le CAN, doit être le même que
celui qui sera fourni au CNA.
31 14 0
17 bits 15 bits
Virgule virtuelle
1er cas : Nous gardons les 16 bits de poids faible de 15 à 0 en représentation Q15. Le résultat gardera
toute sa précision sans aucun arrondi, en revanche il sera complètement erroné dès lors que le
résultat sera en dehors de la plage [-1; 1[.
17 bits 15 bits
Virgule virtuelle
2ème cas : Nous gardons les 16 bits de poids fort de 31 à 16. Dans ce cas, nous faisons un très gros
arrondi du résultat car nous supprimons toutes les valeurs situées après la virgule ainsi que le
premier bit à gauche de la virgule. Il y a 2 inconvénients supplémentaires à cela :
| 25
■ Le résultat stocké est divisé par deux (dans notre exemple) par rapport à la valeur réelle,
donc il faudra à un moment donné le multiplier par 2 (dans notre exemple) avec à nouveau
un risque de débordement.
■ Le résultat n'est plus dans un format directement réutilisable car nous avons travaillé avec
des nombres en Q0 (échantillons) et Q15 (coefficients). Nous ne pouvons donc pas
l'accumuler directement comme nous souhaiterions le faire dans le cas des filtres
numériques.
17 bits 15 bits
Virgule virtuelle
3ème cas : Dans ce cas, nous allons garder les bits nous permettant d'avoir un résultat en Q0 sur 16
bits car il sera à nouveau multiplié par un Q15, etc… Il y a donc un bit de poids fort qui n'est pas pris
en compte. Il y a un risque (faible) d'un débordement puisque le bit significatif 31 n'est pas pris en
compte. Nous verrons plus tard comment il sera possible de s'affranchir de ce problème.
17 bits 15 bits
Virgule virtuelle
Exemple :
■ Soit un ADC travaillant sur 8 bits. Codage en Q7.
■ Soit des coefficients sur 8 bits Codage en Q7.
La multiplication de deux opérandes en Q15 sur 16 bits donne un résultat en Q30 sur 32 bits. Afin de
remettre le résultat en Q15, on ne conserve que les bits de 31 à 15. Nous réalisons donc un décalage
de 15 à droite du résultat.
| 26
Comme nous l'avons vu précédemment, nous laissons de côté un bit de poids fort de la
représentation. Si celui-ci est significatif, le résultat sera alors erroné. Nous allons voir dans quel cas
ce bit est significatif.
En Q15, le résultat est un nombre résultant de la multiplication de deux opérandes comprises entre
[-1 ; 1 [. Et le problème est que le résultat de cette opération est un nombre compris entre [-1 ; 1 ]
(avec le 1 compris cette fois !!!). En effet, toutes les opérandes entre [-1 ; 1[ peuvent être codées
avec un seul bit pour la partie entière, mais lorsque le résultat vaut 1, il doit nécessairement être
codé avec 2 bits pour la partie entière.
Nous devrions donc en théorie rajouter un bit dans notre représentation juste pour coder une valeur
qui est le résultat d'une seule opération possible 1 = -1 x -1. Ceci est très dommageable pour la
réalisation des calculs dans un DSP. La solution retenu est souvent de conserver la représentation
en Q15 et de détecter le débordement. Si le résultat est 1, il sera alors saturé à la valeur la plus proche
représentable en Q15, soit 0,999969482421875.
Round output(n)
Dans un filtre numérique, nous avons une série de multiplication (coefficients x échantillons), puis
une série d'accumulations successives. Les coefficients sont codés en Q15 sur 16 bits et les
échantillons sont codés en Q0.
| 27
En entrée du filtre on considérera un signal sinusoïdal de 150 Hz d'amplitude 19660 par rapport à la
pleine échelle (16 bits / 32768). Donner les 7 premières valeurs du signal d'entrée.
Nous allons essayer d'étudier les différentes valeurs en différents points du filtre numérique en
commençant par la sortie des multiplieurs.
Sorties multiplieurs
Figure 33 : Etude de la sortie des multiplieurs du filtre
A chaque échantillon, nous notons le résultat de chaque multiplieur dans un tableau. Le tableau ci-
dessous représente l'évolution pour une durée d'un peu plus d'une demie période de la sinusoïde
d'entrée.
| 28
Multiplieur 0 Multiplieur 1 Multiplieur 2 Multiplieur 3 Multiplieur 4 Multiplieur 5 Multiplieur 6
Nous pouvons remarquer que toutes les valeurs sont bien comprises sur 32 bits [-231;231-1]. Il n'y a
eu aucun débordement.
32 32 32 32
output(n)
32 32
Round 16
32
Chaque sortie du multiplieur est accumulée jusqu'à produire la valeur de la sortie. L'addition de deux
opérandes de 32 bits nous donne un résultat sur potentiellement 33 bits. Cela nécessiterait donc de
manipuler des variables plus grande (64 bits par exemple) pour les additions. Dans la pratique, cela
n'est pas toujours fait :
■ Car les coefficients du filtre sont faibles et donc le résultat de la multiplication est souvent
faible.
■ Car les résultats de la multiplication étant tantôt positif tantôt négatif, les accumulations
"s'annulent" souvent.
| 29
A chaque échantillon, nous allons noter les valeurs de chaque accumulation. La dernière valeur du
tableau correspond donc à la sortie du filtre. Le tableau ci-dessous rassemble les valeurs pour une
durée d'un peu plus d'une demie période de sinusoïde.
Comme nous l'avons déjà précisé au chapitre 3.2.2, dans les DSP, les accumulations successives se
font sur des nombres de bits supérieurs à 32 bits. Par exemple dans le DSP virgule fixe TMS320C54,
l'accumulateur est de 40 bits. Les 8 bits supplémentaires sont appelés "bits de garde".
32, 40 ou 64 bits 16
Round output(n)
| 30
39 ? 31 16 bits à conserver (bit 30 à 15) 0
17 bits 15 bits
Virgule virtuelle
On remarque donc que les bits de garde sont intéressants seulement si le résultat a eu un
débordement temporaire et qu'il revient dans des plages correctes avant le processus d'arrondi. Car
dans tous les cas, si le résultat ne peut pas être représenté sur 16 bits (dans notre exemple), l'arrondi
donnera lieu à un résultat erroné.
Imaginons un résultat sur 32 bits en Q15 : 0x 0000 0000 0101 0101 0.111 1111 1111 1111
En filtrage numérique, nous utilisons souvent la multiplication de 2 nombres en Q15, le résultat est
en Q30. Pour récupérer un résultat en Q15, on doit :
■ Soit réaliser un décalage de 15 bits à droite et récupérer les 16 bits de poids faibles.
■ Soit réaliser un décalage de 1 à gauche et récupérer les 16 bits de poids forts.
| 31
Prendre 16 bits sur les 32 bits du registre correspond à faire une troncature. Comment pourrait-on
faire pour réaliser un arrondi ?
X
1 ech1 coeff1
2 ech2 coeff2
3 ech3 coeff3
4 ech4 coeff4
5 ech5 coeff5
Figure 37 : Calcul d'un filtre numérique avec 6 coefficients
Le calcul du filtre numérique dans ce cas est très simple comme nous l'avons vu au chapitre 1.3.1.
Afin de garder l'avantage de cette simplicité, nous allons modifier la façon dont nous réalisons le
vieillissement des échantillons. Dans cette méthode l'espace réservé aux échantillons est bien plus
grand que le tableau précédemment réservé comme cela est représenté à la Figure 38.
| 32
@ du tableau Echantillons Coefficients
0 coeff0
X
1 coeff1
2 coeff2
3 coeff3
4 coeff4
5 coeff5
6
7 ech0
8 ech1
9 ech2
10 ech3
11 ech4
12 ech5
Figure 38 : Utilisation d'un traitement par bloc
A partir de là, chaque nouvel échantillon se positionnera à l'adresse 6, puis 7, puis 8, etc… du tableau
d'échantillons. Le positionnement des nouveaux échantillons est représenté Figure 39. Le nombre
total d'échantillons mis en fin de tableau est appelé un bloc.
X
1 coeff1
2 coeff2
3 coeff3
4 newEch2 coeff4
5 newEch1 coeff5
6 newEch0
7 ech0
8 ech1
9 ech2
10 ech3
11 ech4
12 ech5
Figure 39 : Positionnement des nouveaux échantillons aux adresse 6, 5, 4…
Lorsque la fin du bloc est arrivée, nous réalisons le décalage comme nous le faisions dans le cas du
buffer linéaire afin de remettre les échantillons au début du tableau. Ce décalage est couteux en
temps mais il est réalisé qu'une seule fois toutes les X itérations (X étant la taille du bloc). Le résultat
est décrit à la Figure 40.
| 33
@ du tableau Echantillons Coefficients
0 coeff0
X
1 coeff1
2 coeff2
3 coeff3
4 coeff4
5 coeff5
6
7 newEch6
8 newEch5
9 newEch4
10 newEch3
11 newEch2
12 newEch1
Figure 40 : Réinitialisation du buffer d'échantillon
Cette méthode est donc avantageuse sous certains aspects. L'inconvénient étant qu'elle nécessite
plus d'espace mémoire pour s'exécuter.
Le résumé des différents mode de vieillissement est donné sur la Figure 41.
Dans ce code, le nombre i est testé 6 fois. A chaque fois que la condition de fin n'est pas respectée,
on a un saut (rupture du pipeline) et une incrémentation de i.
| 34
5.3 Utilisation de CMSIS DSP
CMSIS est une HAL (Hardware Abstraction Layer) produit par ARM. Il s'agit d'une librairie logicielle
disponible sur tous les produits ARM indépendamment du constructeur. Parmi les librairies CMSIS
disponible, il en existe une spécifique pour le traitement du signal : CMSIS-DSP.
q15_t * pDst,
uint32_t blockSize
Parameters
Returns
none
Scaling and Overflow Behavior
The function is implemented using a 64-bit internal accumulator. Both coefficients
and state variables are represented in 1.15 format and multiplications yield a
2.30 result. The 2.30 intermediate results are accumulated in a 64-bit
accumulator in 34.30 format. There is no risk of internal overflow with this
approach and the full precision of intermediate multiplications is preserved. After
all additions have been performed, the accumulator is truncated to 34.15 format
by discarding low 15 bits. Lastly, the accumulator is saturated to yield a result in
1.15 format.
Remarks
Refer to arm_fir_fast_q15() for a faster but less precise implementation of this
function.
| 35
| 36
6 Solutions des exercises
1.2.1.Fonction de transfert et équation récurrente
𝑦𝑦(𝑛𝑛) = 0.98. 𝑥𝑥(𝑛𝑛) + 0.29. 𝑥𝑥(𝑛𝑛 − 1) + 0.29. 𝑥𝑥(𝑛𝑛 − 2) + 0.98. 𝑥𝑥(𝑛𝑛 − 3) + 0.57𝑦𝑦(𝑛𝑛 − 1)
− 0.42𝑦𝑦(𝑛𝑛 − 2) − 0.05𝑦𝑦(𝑛𝑛 − 3)
1.3.1.Buffer linéaire
float coeff[N] = { , , ... , , };
uint16_t ech[N];
uint16_t newEch;
uint16_t output = 0;
void main(void){
while(1){
// Reception d'un echantillon depuis le CAN
HAL_SAI_Receive(&newEch);
1.3.2.Buffer circulaire
float coeff[N] = { , , ... , , };
uint16_t ech[N];
uint16_t newEch;
uint16_t output = 0;
uint16_t index = N-1;
void main(void){
while(1){
// Reception d'un echantillon depuis le CAN
HAL_SAI_Receive(&newEch);
| 37
// Stockage dans le tableau d'échantillon
// Réinitialiser output a 0.
ech[index] = newEch;
output = 0;
Nombre Codage
3 011
2 010
1 001
0 000
-1 111
-2 110
-3 101
-4 100
| 38
■ -0.1 ≤ Nombre ≤ 0 Q10 avec une erreur de +/- 2-11
■ 98.895 : Exposant = 6 soit 0110, mantisse = 1.5452 soit 0110 en Q2, 96 codé
■ 0.01298 : Exposant = -7 soit 1001, mantisse = 1.6614 soit 0111 en Q2, 0.01367 codé
Mémoire Programme
CPU
Mémoire Données
| 39
4.1.1. Addition en entier non signés
𝟏𝟏 𝟏𝟏
1 1 0 0
0 1 0 1
1 0 0 0 1
Nous avons donc un bit de retenue
0 1 0 0
0 0 1 1
0 1 1 1
Calcul de 7 + 3 = 10
𝟏𝟏 𝟏𝟏 𝟏𝟏
0 0 1 1 1
0 0 0 1 1
0 1 0 1 0
0 0 0 0 1 . 0 1
1 1 0 0 0 . 0 0
1 1 0 0 1 . 0 1
Calcul de (-7,25) + (-7.25) = -14,50 (Débordement)
1 1 1
1 1 0 0 0 . 1 1
1 1 0 0 0 . 1 1
1 0 0 0 1 . 1 0
Le résultat est donc bien -14,5 sur 7 bits (6 + 1 bit)
| 40
𝟎𝟎 𝟎𝟎 𝟎𝟎 𝟎𝟎 0 1 1 1
𝟏𝟏 𝟏𝟏 𝟏𝟏 𝟏𝟏 1 0 0 0
𝟐𝟐 𝟐𝟐 𝟏𝟏
0 0 1 1 1 . . .
0 1 1 1 . . . .
1 1 1 . . . . .
1 1 . . . . . .
1 . . . . . . .
1 1 0 0 1 0 0 0
On a bien -56 codé sur 8 bits
Réaliser le calcul de -8 x -8 = 64
𝟏𝟏 𝟏𝟏 𝟏𝟏 𝟏𝟏 1 0 0 0
𝟏𝟏 𝟏𝟏 𝟏𝟏 𝟏𝟏 1 0 0 0
1 1 0 0 0 . . .
1 0 0 0 . . . .
0 1 0 0 0 0 0 0
4.4.1.Multiplication sans perte de précision
𝟏𝟏 𝟏𝟏 𝟏𝟏 𝟏𝟏 1 0 0 1
𝟎𝟎 𝟎𝟎 𝟎𝟎 𝟎𝟎 0 1 0 1
𝟏𝟏 𝟏𝟏
1 1 1 1 1 0 0 1
1 1 1 0 0 1 . .
1 1 0 1 1 1 0 1
On a donc bien -4,375 représenté en Q3 sur 8 bits.
| 41