0% ont trouvé ce document utile (0 vote)
37 vues41 pages

Cours sur les Processeurs de Traitement du Signal (DSP)

Transféré par

Near
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Thèmes abordés

  • Gestion des boucles par blocag…,
  • Accumulateurs,
  • Délai de génération,
  • Optimisation du calcul,
  • Codage en Qk,
  • Codage en virgule flottante,
  • Traitement en temps réel,
  • Dynamique des données,
  • Optimisation des algorithmes,
  • Gestion des pointeurs
0% ont trouvé ce document utile (0 vote)
37 vues41 pages

Cours sur les Processeurs de Traitement du Signal (DSP)

Transféré par

Near
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Thèmes abordés

  • Gestion des boucles par blocag…,
  • Accumulateurs,
  • Délai de génération,
  • Optimisation du calcul,
  • Codage en Qk,
  • Codage en virgule flottante,
  • Traitement en temps réel,
  • Dynamique des données,
  • Optimisation des algorithmes,
  • Gestion des pointeurs

DSP : Digital Signal Processors

Cours

Sylvain Montagny

[email protected]

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.

Ports d’entrées / sorties

Filtre Système de traitement Filtre


anti CAN numérique CNA de
repliement (Processeur, FPGA…) reconstruction

Analogique Analogique
Mémoire

Numérique

Figure 1 : Chaine de traitement 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.

Exemple : Un signal sonore [0 – 20 kHz] doit être échantillonné à 8khz :

■ Dessiner le spectre du signal avant l'échantillonnage


■ Choisir la fréquence de coupure du filtre anti-repliement
■ Dessiner le spectre du signal après le filtre anti-repliement
■ Dessiner le spectre du signal après le CAN
■ Choisir la fréquence de coupure du filtre de reconstruction
■ Dessiner le spectre du signal après le filtre de reconstruction

Les filtres anti-repliement et les filtres de reconstruction sont (bien sûr) obligatoirement
analogique.

1.1.2 Avantage du traitement numérique


Le traitement numérique possède de nombreux avantages :

| 2
■ Il peut être fait en multitâche
■ Il n'est pas contraint aux variations des valeurs de composants analogiques

1.2 Le filtrage numérique


1.2.1 Fonction de transfert et équation récurrente
La forme d'un filtre numérique FIR avec N coefficient est la suivante :

ℎ(𝑧𝑧) = 𝑏𝑏0 + 𝑏𝑏1 . 𝑧𝑧 −1 + ⋯ + 𝑏𝑏𝑁𝑁−1 . 𝑧𝑧 −(𝑁𝑁−1)


La forme d'un filtre numérique IIR est la suivante (le nombre de coefficient du filtre est q+1+p) :

𝑏𝑏0 + 𝑏𝑏1 . 𝑧𝑧 −1 + ⋯ + 𝑏𝑏𝑞𝑞 . 𝑧𝑧 −𝑞𝑞


ℎ(𝑧𝑧) =
1 + 𝑎𝑎1 . 𝑧𝑧 −1 + ⋯ + 𝑎𝑎𝑝𝑝 . 𝑧𝑧 −𝑝𝑝

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

𝐻𝐻𝐹𝐹𝐹𝐹𝐹𝐹 (𝑧𝑧) = 0,21 + 0,47. 𝑧𝑧 −1 + 0,47. 𝑧𝑧 −2 + 0,21. 𝑧𝑧 −3


0,98 + 0,29. 𝑧𝑧 −1 + 0,29. 𝑧𝑧 −2 + 0,98. 𝑧𝑧 −3
𝐻𝐻𝐼𝐼𝐼𝐼𝐼𝐼 (𝑧𝑧) =
1 − 0,57. 𝑧𝑧 −1 + 0,42. 𝑧𝑧 −2 + 0,05. 𝑧𝑧 −3
La réponse en fréquence du filtre HFIR(z)est donnée par le spectre de la Figure 2, et celui du
filtre HIIR(z) par le spectre de la Figure 3.

Figure 2 : Réponse en fréquence du filtre FIR

| 3
Figure 3 : Réponse en fréquence du filtre IIR

1.2.2 Schéma de fonctionnement d'un filtre numérique


La représentation graphique d'un filtre numérique FIR est représentée à la Figure 4. Les coefficients
seront maintenant sont appelés "coeff".

ech(n) ech(n-1) ech(n-2)


Z-1 Z-1 Z-1

coeff 0 coeff 1 coeff 2 coeff q

Round output(n)

Figure 4 : Représentation graphique d'un filtre FIR

En vous aidant de la Figure 4 , donner le schéma de la représentation graphique du filtre HFIR(z) et


HIIR(z) présentés au chapitre 1.2.1.

On caractérise la complexité d'un filtre numérique par le nombre de cellules multiplication /


accumulation qu'il contient. Combien de cellules multiplication / accumulation contiennent les
filtres FIR et IIR précédents ? Quel est le rapport entre le nombre de cellule et le nombre de
coefficients ?

1.2.3 Actions à réaliser et objectifs


En regardant le schéma d'un filtre numérique, nous pouvons noter les actions à réaliser. Nous
prenons l'exemple d'un filtre FIR avec N coefficients.

| 4
while ( 1 ) {
■ Récupération d'un nouvel échantillon (CAN) et stockage en mémoire

for ( i = 0 ; i < N ; i ++ ) { // Boucle N fois


■ Lectures des deux opérandes : échantillon et coefficient
■ Multiplication des deux opérandes : coefficient * échantillon
■ Accumulation
■ Gestion des pointeurs pour l'accès aux prochains échantillons et coefficients
■ Gestion de la boucle for : incrémentation de i, test de sa valeur et rebouclage
}
■ Envoi du résultat du calcul sur le CNA
■ Vieillissement des échantillons
■ Gestion de la boucle infinie while(1)
}

Figure 5 : Algorithme de réalisation d'un filtre numérique FIR

Objectifs d'un processeur de traitement du signal :

■ Récupérer le nouvel échantillon (CAN) en temps caché (DMA)


■ Réaliser chaque itération de la boucle for en 1 cycle, soit N cycles pour un filtre à N coeff.
■ Réaliser le vieillissement des échantillons rapidement : Buffer linéaire ou circulaire
■ Envoyer le résultat (CNA) en temps caché (DMA)

1.3 Le vieillissement des échantillons pour le filtrage numérique


Soit le filtre numérique FIR suivant :

𝑜𝑜𝑜𝑜𝑜𝑜𝑜𝑜𝑜𝑜𝑜𝑜(𝑛𝑛) = 𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐0 . 𝑒𝑒𝑒𝑒ℎ(𝑛𝑛) + 𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐1 . 𝑒𝑒𝑒𝑒ℎ(𝑛𝑛 − 1) + ⋯ + 𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑐𝑁𝑁−1 . 𝑒𝑒𝑒𝑒ℎ(𝑁𝑁 − 1)


A chaque période d'échantillonnage, un nouvel échantillon arrive et doit être stocké dans le tableau.
Il faut alors faire vieillir les autres échantillons.

On considère les tableaux d'échantillons et de coefficients comme le montre la Figure 6.

@ du tableau Echantillons Coefficients

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

1.3.1 Buffer linéaire


Dans le cas de l'utilisation d'un buffer linéaire, tous les échantillons du tableau "Echantillons" sont
décalés vers le bas d'une position, puis le nouvel échantillon est positionné dans la case qui s'est
libérée en haut du tableau. La Figure 7 représente le tableau d'échantillon juste après le décalage et
l'arrivée du nouvel échantillon.

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

// Stockage dans le tableau d'échantillon


// Réinitialiser output a 0.
// A COMPLETER

// Calcul du filtre numérique (cas du Buffer Linéaire)


// A COMPLETER

//Envoi du résultat sur le CNA


HAL_SAI_Transmit(&output);

// Vieillissement du Buffer linéaire : décalage


// A COMPLETER
}

1.3.2 Buffer circulaire


Dans le cas d'un buffer circulaire, le nouvel échantillon remplace uniquement le plus ancien. Les
figures suivantes représentent le tableau d'échantillon au temps T = t (Figure 8), c’est-à-dire avant
l'apparition du nouvel échantillon et T = t + 1 (Figure 9), c’est-à-dire lorsque le nouvel échantillon a
été injecté dans le tableau en remplacement du plus ancien.

| 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.

@ du tableau Echantillons Coefficients


0 … coeff0

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

Au prochain cycle, le nouvel échantillon remplacera echN-2, etc…

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.

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

// Stockage dans le tableau d'échantillon


// Réinitialiser output a 0.
// A COMPLETER

// Calcul du filtre numérique (cas du Buffer Circulaire)


// A COMPLETER

| 7
// Vieillissement du Buffer circulaire : MAJ de l'index
// A COMPLETER

//Envoi du résultat sur le CNA


HAL_SAI_Transmit(&output);
}
}

1.3.3 Avantage et inconvénient des buffer linéaires et circulaires


D'après les codes que vous avez écrit dans le cas d'un buffer linéaire et dans le cas d'un buffer
circulaire, nous pouvons faire le résumé suivant :

Vieillissement des échantillons Calcul du filtre


Buffer Linéaire Complexe Simple
Buffer circulaire Simple Complexe

2 Représentation numérique du signal


Afin de bien coder les algorithmes de traitement du signal, il est indispensable de bien comprendre:

■ Le codage des nombres


■ Les calculs réalisés à l'intérieur du processeur

2.1 Codage des nombres entiers


2.1.1 Le codage des entiers non signés
N −1
A chaque chiffre est affecté un poids exprimé en puissance de 2 : Nombre = ∑b 2
i =0
i
i
, b étant la

valeur binaire (0 ou 1) du poids concerné et N le nombre de bits du Nombre.

Exemple : ( 101 ) 2 = 1.2 2 + 0.21 + 1.2 0 = ( 5 )10

Donner la plage de codage des nombres entiers non signés en fonction du nombre de bit N

2.1.2 Le codage des entiers signés


Les nombres signés utilisent une représentation en Complément A2 qui possède des propriétés
beaucoup plus intéressantes qu'une représentation signe/valeur absolue.
N −2
Nombre = −bN −1.2 N −1 + ∑ bi 2i
i =0

Exemple : ( 101 ) CPLA2 = - 1.2 2 + 0.21 + 1.2 0 = ( - 3 )10

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.

2.2 Codage des nombres réels


La représentation des nombres réels doit répondre à deux exigences contradictoires :

■ 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

2.2.1 Le codage en virgule fixe


Le codage en virgule fixe représente un nombre réel en partant d'un nombre entier signé en
complément A2. On rajoute simplement dans la représentation une virgule virtuelle permettant de
séparer la partie entière et la partie décimale.

■ Soit N le nombre de bit total de la représentation


■ Soit k le nombre de bit de la partie décimal
■ Soit m le nombre de bit de la partie entière

m-1 1 0 -1 -2 -k
-2 2 2 2 2 2

bm-1 bm-2 bm-3 b1 b0 b-1 b-2 b-k+1 b-k

Nombre codé en C à 2

Figure 10 : Représentation d'un nombre réel en virgule fixe


m−2
Nombre = −bm −1.2m −1 + ∑b 2
i=−k
i
i

| 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

2.2.2 Le codage en virgule flottante


La notation en virgule flottante est très similaire à la notation scientifique en base 10. En base 10,
nous fixons un nombre de bits significatif, puis nous représentons le nombre sous la forme :

Nombre = mantisse.10exp osant

Note : Dans la notation scientifique en base 10 : 1 ≤ mantisse < 10 .

Donner la représentation scientifique en base 10 des nombres suivants si on garde 3 digits


significatifs pour la mantisse.

■ 98.895
■ 10.1
■ 0.01298
■ -128000

| 10
En binaire, la représentation est similaire mais en base 2 :

Nombre = mantisse.2 exp osant

Note : Dans la notation scientifique en base 2 : 1 ≤ mantisse < 2 .

■ La mantisse est un nombre réel codé sur M bits en virgule fixe


■ L'exposant est un nombre entier signé codé sur E bits en complément A2.

dE-1 dE-2 d1 d0 cM-1 cM-2 c1 c0

Exposant Mantisse

Figure 11 : Représentation binaire d'un nombre en virgule flottante

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.

2.3 L'erreur de quantification


L'erreur de quantification est l'erreur entre la valeur réelle du nombre et la valeur codée en binaire.
On considère l'erreur de quantification comme un bruit qui est rajouté au signal. Les principales
conséquences de l'erreur de quantification sur les filtres numériques sont :

■ Au mieux, un non-respect du gabarit du filtre numérique


■ Au pire, le filtre peut même devenir instable

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

2.3.1 Cas de la représentation en virgule fixe


Donner l'erreur relative maximale pour des petits nombres (autour de 0,01298) et des grands
nombres (autour de 98,895) dans le cas d'une représentation en virgule fixe Q0 sur 8 bits. Remplir
les colonnes ɛabsolue max, et ɛrelative max du Tableau 1 dans le cas de la représentation en virgule fixe.

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

Figure 12 : Evolution de l'erreur relative en fonction du nombre (en virgule fixe)

2.3.2 Cas de la représentation en virgule flottante


Donner l'erreur relative maximale pour des petits nombres (autour de 0,01298) et des grands
nombres (autour de 98,895) dans le cas d'une représentation en virgule fixe flottante 4 bits pour
l'exposant et 4 bits pour la mantisse). Remplir les colonnes ɛabsolue max, et ɛrelative max du Tableau 1 dans
le cas de la représentation en virgule fixe.

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

Valeur du signal d'entrée

Figure 13 : Evolution de l'erreur relative en fonction du nombre (en virgule flottante)

2.4 Relation entre le codage des nombres et le type de variable


Il y a une relation directe entre le codage des nombres et le type de variable utilisé en langage C.

Dans le tableau suivant, donner les plages de valeurs de chacune des variables.

Nom du type Signification Codage Plage de valeur

char Entier signé 8 bits -128 à 127

unsigned int Entier non signé 32 bits 0 à 232-1

int Entier signé 32 bits -231 à 231-1

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

Figure 14 : Les différents types de variables utilisés en langage C

| 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.

3.1.1 DSP à virgule fixe


Ces processeurs ne possèdent pas d'unité arithmétique pour les nombres flottants. Cela ne signifie
pas qu'ils ne peuvent pas réaliser des calculs en flottant, mais ces calculs font appel à des librairies
logicielles de gestion des nombres flottants. Le temps de calcul est très ralenti et l'occupation
mémoire du programme est augmentée.

Avantages :

■ L'architecture du processeur est plus simple


■ Le processeur consomme moins
■ Le processeur est moins cher

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.

Il est important de savoir qu'énormément de microcontrôleurs ne possèdent pas de gestion de


l'arithmétique flottante appelée FPU (Floating Point Unit). Cependant la majorité des processeurs
en possède une.

3.1.2 DSP à virgule flottante


Ces processeurs possèdent une unité spécifique pour le calcul flottant (FPU) :

■ 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 :

■ L'architecture du processeur est plus complexe


■ Le processeur consomme plus
■ Le processeur est plus cher

3.2 L'unité arithmétique et Logique (UAL)


3.2.1 Multiplieur câblé
Nous avons vu que l'opération la plus importante pour la réalisation d'un filtre numérique était la
multiplication (associé à une accumulation). Celle-ci doit être réalisée de façon matérielle. Les
processeurs de traitement du signal possèdent donc des multiplieurs câblés.

3.2.2 Les bits de garde de l'accumulateur


■ Les multiplications de deux nombres codés sur n bits donne un résultat sur 2n bits.
■ L'addition de deux nombres de 2n bits donne un résultat sur 2n + 1 bits.

n bits n bits n bits n bits

coeff 0 (n bits) coeff 1 (n bits) coeff 2 (n bits) coeff N-1 ( n bits)


2n bits 2n bits 2n bits 2n bits

Round output(n)
2n+1 bits 2n+2 bits n bits
2n+q bits

Figure 15 : Format des nombres dans la chaine de traitement

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.2.3 Le registre à décalage


A la fin du calcul, le résultat doit être tronqué sur le format initial. Il ne faut donc garder que les bits
les plus représentatifs. Cela est fait par un registre à décalage appelé registre à barillet dans les DSP.

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

La Figure 17 représente le déroulement de ces étapes temporellement.

P F D A R X Temps

Figure 17 : Représentation temporelle des étapes d'une instruction sans pipeline

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 ?

Représenter sur la Figure 18 le déroulement de 5 autres instructions si nous considérons que le


processeur utilise maintenant un pipeline. Combien de temps mets chacune des instructions à
s'exécuter. Combien d'instructions sont exécutées à chaque cycle à partir du 6ème cycle ?

P F D A R X Temps

Figure 18 : Représentation temporelle des étapes d'une instruction avec pipeline

3.3.2 Vidange du pipeline


Dans le cas général, la prochaine instruction qui est récupérée en mémoire est celle située à
l'adresse + 1 dans la mémoire flash. C'est donc cette instruction qui sera insérée dans le pipeline.

| 16
On considère maintenant un cas pratique représentant l'appelle d'une fonction (Instruction CALL)
qui constitue un saut en mémoire.

Soit le programme suivant :


PROGRAM : Instruction 1
Instruction 2 // CALL FUNCTION
Instruction 3
Instruction 4
Instruction 5
Instruction 6
Instruction 7
Instruction 8
Instruction 9

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

Figure 19 : Exemple d'une vidange de pipeline

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.

3.3.3 Les aléas dans le pipeline


Chaque étage du pipeline utilise un certain nombre de circuit du processeur pour réaliser l'action à
laquelle il est préposé. La Figure 20 résume les circuits utilisés par chaque étage.

| 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

Figure 21 : Exemple d'aléas dans le pipeline

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.

3.4 La gestion des boucles


On considère deux tableaux représentant les échantillons ech[ ] et les coefficients coeff[ ] d'un filtre
FIR.

| 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.

3.4.1 Auto incrémentation des pointeurs d'adresses


Dans l'exemple simple que nous avons réalisé, l'incrémentation des index est de 1 à chaque
itération. Cette opération (aussi simple soit-elle) doit être réalisée avec une UAL. Elle prendra un
cycle supplémentaire dans le calcul.

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

3.4.2 Gestion des boucles par blocage du PC


On considère que l'auto incrémentation des pointeurs est active. Nous rappelons que le calcul à
effectuer est N fois une instruction MAC (filtre à N coefficients) :

@ du tableau Echantillons Coefficients


0 ech0 coeff0

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

3.4.3 Adressage circulaire (modulo)


L'utilisation de l'auto incrémentation et du blocage du PC tel que nous l'avons vu fonctionne bien
avec le buffer linéaire. En revanche, dans le cas des buffers circulaires, la répétition de N fois de
l'instruction MAC nous ferait sortir du tableau des échantillons. Il faudrait alors pouvoir faire en
sorte que le pointeur sur les échantillons réalise une opération modulo N pour revenir
automatiquement à zéro après l'index N-1.
REPEAT N
MAC coeff_ptr+, ech_ptr+%N, 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.

3.5 Les bus d'accès aux mémoires


Les DSP utilisent une architecture de Harvard avec une duplication des bus d'accès aux mémoires
programme et donnée.

Mémoire Programme
CPU

Mémoire Données

Figure 22 : Architecture de Harvard

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

Figure 23 : Architecture de Harvard modifiée dans un TMS320C54

3.6 Résumé

while ( 1 ) {
■ Récupération d'un nouvel échantillon (CAN) et stockage en mémoire

for ( i = 0 ; i < N + 1 ; i ++ ) { // Boucle N +1 fois


■ Lectures des deux opérandes : échantillon et coefficient
■ Multiplication des deux opérandes : coefficient * échantillon
■ Accumulation
■ Gestion des pointeurs pour l'accès aux prochains échantillons et coefficients
■ Gestion de la boucle for : incrémentation de i, test de sa valeur et rebouclage
}
■ Envoi du résultat du calcul sur le CNA
■ Vieillissement des échantillons
■ Gestion de la boucle infinie while(1)
}

Figure 24 : Algorithme de réalisation d'un filtre numérique FIR

4 Réalisation des calculs dans le processeur


Pour la suite nous adopterons les dénominations suivantes :

■ 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

4.1 L’addition des nombres entiers


4.1.1 Addition en entier non signés
Exemple sur 4 bits. Réaliser le calcul de 12 + 5 = 17 en binaire

| 21
■ nr = max(na,nb) + 1 (on a une éventuelle retenue)

En traitement du signal, on utilise très rarement le codage en unsigned. Nous ne traiterons


plus ce cas par la suite.

4.1.2 Addition de 2 entiers signés de signes opposés


Si sign(a) != sign(b) alors il n’y a pas de débordement possible.

■ Faire le test avec -8 + x 𝑥𝑥 ∈ [0,7]


■ Faire le test avec 7 + x 𝑥𝑥 ∈ [−8, −1]

Dans ces cas, on peut s’affranchir de s’occuper du bit de retenu.

Le nombre maximum de bits du résultat est donc : nr = max(na , nb)

4.1.3 Addition de 2 entiers signés de même signe


Tout d'abord un calcul simple sans débordement : 4 + 3 = 7

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.

Réaliser le calcul de 7 + 3 = 10 en binaire en retrouvant cette fois le bon résultat.

Le nombre maximum de bits du résultat est donc : nr = max(na , nb) + 1


On utilisera toujours le cas général en anticipant le bit de retenu dans le calcul, comme
c'est le cas dans le processeur.

4.2 Addition en virgule fixe


Le nombre de bits des opérandes a et b doit être identique (na = nb). Il faut aussi choisir un format
Qk commun pour le calcul : on positionne la virgule de façon à ce qu’elle soit alignée :

■ 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é.

4.2.1 Deux opérandes de signes opposés


Si sign(a) != sign(b) alors il n’y a pas de débordement possible.

4.2.2 Deux opérandes de même signe


Si sign(a) = sign(b) alors il y a un débordement possible.

Le nombre maximum de bits du résultat est donc : nr = max(na,nb) + 1


Si a est en Qk et b en Qk’ alors le résultat est en Qmax(k ; k’)

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 :

■ On étend l'opérande a de 2 bits vers la gauche (extension de signe)


■ On étend l'opérande b de 1 bit vers la gauche (extension de signe) et 2 bits vers la droite.
𝒂𝒂𝟎𝟎 𝒂𝒂𝟎𝟎 𝑎𝑎0 . 𝑎𝑎−1 𝑎𝑎−2 𝑎𝑎−3 𝑎𝑎−4
𝒃𝒃𝟏𝟏 𝑏𝑏1 𝑏𝑏0 . 𝑏𝑏−1 𝑏𝑏−2 𝟎𝟎 𝟎𝟎
𝑟𝑟2 𝑟𝑟1 𝑟𝑟0 . 𝑟𝑟−1 𝑟𝑟−2 𝑟𝑟−3 𝑟𝑟−4
Figure 25 : Exemple d'une addition de deux nombres codés en virgule fixe

Réaliser le calcul de 1,25 + (-8) = -5,75 (Pas de débordement)

Réaliser le calcul de (-7,25) + (-7.25) = -14,50 (Débordement)

4.3 Multiplication en entiers signés


Le nombre maximum de bit du résultat est nr = na + nb

■ En vert (gras) on a les bits de l’extension de signe des calculs intermédiaires


■ En rouge (gras), on a les retenues

Exemple : -4 x 6 = -24 ( les opérandes -4 et 6 sont codés sur 4 bits


𝟏𝟏 𝟏𝟏 𝟏𝟏 𝟏𝟏 1 1 0 0
𝟎𝟎 𝟎𝟎 𝟎𝟎 𝟎𝟎 0 1 1 0
𝟏𝟏 𝟏𝟏 𝟏𝟏
1 1 1 1 1 0 0 .
1 1 1 1 0 0 . .
1 1 1 0 1 0 0 0
On a bien -24 codé sur 8 bits.

| 23
Exemple, réaliser le calcul de 7 x -8 = -56 en binaire (7 et 8 seront codés sur 4 bits)

Exemple, réaliser le calcul de -8 x -8 = 64 en binaire (-8 et -8 seront codés sur 4 bits)

4.4 Multiplication en virgule fixe


La valeur du nombre de bit du résultat est la même que pour les multiplications des nombres signés.
En effet nr = na + nb. Mais ce qui nous intéresse c'est l'emplacement de la virgule après le calcul.

4.4.1 Multiplication sans perte de précision


On considère dans ce cas que tous les chiffres après la virgules seront conservés. Il n'y aura donc pas
de recadrage du résultat.

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 :

■ On étend l'opérande a de 4 bits vers la gauche (extension de signe)


■ On étend l'opérande b de 5 bits vers la gauche (extension de signe)

𝑎𝑎0 𝑎𝑎0 𝑎𝑎0 𝑎𝑎0 𝑎𝑎0 𝑎𝑎−1 𝑎𝑎−2 𝑎𝑎−3 𝑎𝑎−4


𝑏𝑏1 𝑏𝑏1 𝑏𝑏1 𝑏𝑏1 𝑏𝑏1 𝑏𝑏1 𝑏𝑏0 𝑏𝑏−1 𝑏𝑏−2
𝑟𝑟3 𝑟𝑟2 𝑟𝑟1 𝑟𝑟−1 𝑟𝑟−2 𝑟𝑟−3 𝑟𝑟−4 𝑟𝑟−5 𝑟𝑟−6

Réaliser le calcul de :

■ a : -3,5 en Q1 sur 4 bits


■ b : 1,25 en Q2 sur 4 bits

Le nombre de bits après la virgule du résultat est égale à kr = ka + kb

4.4.2 Multiplication avec perte de précision : cas général


Dans le calcul d’un filtre numérique, le format de donnée doit être recadré dans le type d’origine.
Certes, ce recadrage se produit le plus tard possible, mais il doit de toute façon intervenir.

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.

Reprenons une étude de cas complète autour d'un exemple :

■ Soit un ADC travaillant sur 16 bits [ -32768 ; 32767 ]. Codage en Q0


■ Soit des coefficients sur 16 bits en Q15
La multiplication des deux nombres donne une représentation en Q15 sur 32 bits.

31 14 0

17 bits 15 bits

Virgule virtuelle

Figure 26 : Résultat d'une opération de deux opérandes Q16.0 x Q16.15 en Q32.15

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[.

31 16 bits à conserver (bit 15 à 0) 0

17 bits 15 bits

Virgule virtuelle

Figure 27 : Conservation des 16 bits de poids faibles

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.

31 16 bits à conserver (bit 31 à 16) 0

17 bits 15 bits

Virgule virtuelle

Figure 28 : Conservation des 16 bits de poids forts

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.

31 16 bits à conserver (bit 30 à 15) 0

17 bits 15 bits

Virgule virtuelle

Figure 29 : Solution retenue

Exemple :
■ Soit un ADC travaillant sur 8 bits. Codage en Q7.
■ Soit des coefficients sur 8 bits Codage en Q7.

Donner le format du résultat et l'opération pour y parvenir.

4.4.4 Cas particulier de la multiplication en Q7, Q15 et Q31.


Par exemple, le codage Q15 sur 16 bits est très courant en traitement du signal. Il ne s'agit que d'un
cas particulier de ce que nous avons vu précédemment. Les mêmes propriétés existent pour le
format en Q7 sur 8 bits et Q31 sur 32 bits

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.

Codage binaire en Q15 sur 16 bits :

Nombre en décimal Nombre en binaire


-1 1000 0000 0000 0000
0 0000 0000 0000 0000
0,999969482421875 0111 1111 1111 1111
Figure 30 : Codage des nombres en Q16.15.

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.

4.5 Etude d'un cas concret : Filtre FIR

ech(n) ech(n-1) ech(n-2)


Z-1 Z -1 Z-1

coeff 0 coeff 1 coeff 2 coeff N-1

Round output(n)

Figure 31 : Représentation graphique d'un filtre FIR

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.

Le filtre que nous étudierons aura le gabarit suivant :


% sampling frequency: 2000 Hz
% 0 Hz - 400 Hz / gain = 1
% 800 Hz - 1000 Hz / gain = 0
nbrCoeff = 7;
coeff = [ -2097 -1622 9736 18369 9736 -1622 -2097 ];

Donnez les valeurs réelles des coefficients de ce filtre numérique

| 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.

Figure 32 : Signal d'entrée du filtre numérique

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.

4.5.1 Etude de la sortie des multiplieurs


La multiplication de deux nombres sur 16 bits donne une représentation en 32 bits.

ech(n) ech(n-1) ech(n-2)


Z-1 Z-1 Z-1
16 16 16

coeff 0 coeff 1 coeff 2 Coeff N-1


16 16 16
32 32
32

Multiplieur 0 Multiplieur 1 Multiplieur N-1

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

Figure 34 : Valeurs des sorties des multiplieurs du filtre numérique

Nous pouvons remarquer que toutes les valeurs sont bien comprises sur 32 bits [-231;231-1]. Il n'y a
eu aucun débordement.

4.5.2 Etude de la sortie des additionneurs

32 32 32 32

output(n)
32 32
Round 16
32

Accumulateur 0 Accumulateur 1 Accumulateur N-1

Figure 35 : Etude de la sortie des accumulateurs

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.

Accumulateur 0 Accumulateur 1 Accumulateur 2 Accumulateur 3 Accumulateur 4 Accumulateur 5 Accumulateur 6

Figure 36 : Valeur des résultats d'accumulation successives du filtre


Donner la valeur maximal atteinte par le filtre et sa marge par rapport au débordement.
Cette méthode empirique n'est bien sûr pas valable pour s'assurer qu'aucun débordement n'aura
lieu.

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".

4.5.3 Arrondi du résultat


Quel que soit le format du résultat des accumulations (32, 64, 40 bits…) la dernière étape consiste
toujours à stocker le résultat dans le format d'origine (ici 16 bits). Cet arrondi amènera
nécessairement à une erreur supplémentaire sur le résultat.

32, 40 ou 64 bits 16
Round output(n)

Dans notre cas, nous récupérerons toujours les bits 30 à 15 du résultat :

| 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é.

4.5.4 Arrondi Versus Troncature


Lors du codage en virgule fixe, il est toujours intéressant d’arrondir le nombre plutôt que de le
tronquer.

Exemple : Codage de 2,95 en Q1

On code donc la valeur entière de 2,95 x 2 =5,9

■ Si on tronque > 5 > 0101 soit la valeur 2,5 en Q1


■ Si on arrondi > 6 > 0110 soit la valeur 3 en Q1

Il est donc intéressant d’arrondir le nombre avant codage :


On ajoute la moitié du digit de poids faible (soit 0,5 pour un nombre entier en décimal)
Donc on code la valeur (2,95 x 2) + 0,5 =6,4 tronquée soit 6, soit la valeur 3 en Q1

4.5.5 Arrondi d’un nombre binaire


Dans le paragraphe précédent, nous avons compris qu'il était nécessaire de ne conserver que les
bits 30 à 15 pour le résultat (cas des coefficients codés en Q15 ). Cela implique de réaliser un décalage
du résultat de 15 bits vers la droite. En réalité, lorsque nous réalisons ce type d'opération, nous ne
réalisons pas un arrondi mais une troncature, alors que nous venons de démontrer que c'est
justement l'arrondi qui est le plus intéressant.

Imaginons un résultat sur 32 bits en Q15 : 0x 0000 0000 0101 0101 0.111 1111 1111 1111

■ Le résultat par troncature serait de : 0x0000 0000 1010 1010


■ Le résultat par arrondi serait de : 0x0000 0000 1010 1011, ce qui est plus proche de
la vraie valeur.

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 ?

Exemple sur 4 bits en Q3 : 0,75 x 0,625 = 0,46875

Le résultat sur 8 bit en binaire est : 00.01 1110,

■ si on fait une troncature, on a 0.011 soit 0,375 (erreur de x %)


■ si on fait un arrondi, on a 0.100 soit 0,5 (erreur de x %)

L’arrondie se fait encore en additionnant la moitié du bit de poids faible et en tronquant.


Donc on ajoute ici 1<<(k-1)

5 Programmation d'un filtre numérique


5.1 Traitement en temps réel / traitement par bloc
5.1.1 Traitement en temps réel
Le traitement en temps réel nécessite qu'une exécution de l'algorithme soit lancée à chaque période
d'échantillonnage. L'avantage de ce type de traitement est que le délai de génération de
l'échantillon de sortie est faible (1 période d'échantillonnage). Si le délai est une forte contrainte
alors cette solution est la bonne. Néanmoins, comme nous le verrons plus loin cela a une forte
tendance à augmenter la charge de calcul du processeur pour les DSC. Les vrais DSP ne sont pas (ou
peu) affectés.

5.1.2 Traitement par bloc


Comme nous l'avons vu au chapitre 1.3.3, le réalisation de buffer circulaire augmente la complexité
de la boucle de calcul du filtre numérique. En effet, nous avons à chaque itération un test vérifiant
le dépassement du pointeur sur le tableau des échantillons. L'intérêt du buffer circulaire est donc
très réduit, voire nul dans ce cas. Nous allons voir comment le traitement par bloc permet
d'améliorer ce phénomène.

5.2 Optimisation du calcul


5.2.1 Amélioration du vieillissement des échantillons
Nous prendrons comme exemple un filtre FIR de 6 coefficients (N = 6).

@ du tableau Echantillons Coefficients


0 ech0 coeff0

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.

@ du tableau Echantillons Coefficients


0 coeff0

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.

Vieillissement des Calcul du filtre Occupation


échantillons mémoire
Buffer Linéaire Complexe Simple Taille du filtre
Buffer circulaire Simple Complexe Taille du filtre
Buffer par bloc Simple sauf 1 fois tous les X Simple Taille du filtre
échantillons. X étant la taille +
du bloc Taille du bloc
Figure 41 : Résumé des méthodes de vieillissement des échantillons

5.2.2 Loop unrooling


La traduction signifierait "développement des boucles". On cherche toujours à éviter le test des fins
de boucles réalisé à chaque itération. Si nous reprenons le cas de la Figure 37. Le code est le suivant
:
for ( i = 0 ; i < N ; i++) { // 6 itérations
output += coeff[ i ] * ech[ i ];
}

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.

Ceci pourrait être transformé en :


for ( i = 0 ; i < N/3 ; i++) { // 2 itérations
output += coeff[ i ] * ech[ i ];
output += coeff[ i + 1] * ech[ i + 1 ];
output += coeff[ i + 2] * ech[ i + 2 ];
}
Dans ce code, le nombre i est testé 2 fois. La condition de fin n'est pas respectée une fois : on a un
seul saut (rupture du pipeline) et une incrémentation de i. Néanmoins, il y a une incrémentation
supplémentaire de i pour chaque ligne de la boucle.

| 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.

void arm_fir_q15 ( const arm_fir_instance_q15 * S,

const q15_t * pSrc,

q15_t * pDst,

uint32_t blockSize

Parameters

[in] S points to an instance of the Q15 FIR filter structure

[in] pSrc points to the block of input data

[out] pDst points to the block of output data

[in] blockSize number of samples to process

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.21. 𝑥𝑥(𝑛𝑛) + 0.47. 𝑥𝑥(𝑛𝑛 − 1) + 0.47. 𝑥𝑥(𝑛𝑛 − 2) + 0.21. 𝑥𝑥(𝑛𝑛 − 3)

𝑦𝑦(𝑛𝑛) = 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);

// Stockage dans le tableau d'échantillon


// Réinitialiser output a 0.
ech[0] = newEch;
output = 0;

// Calcul du filtre numérique (cas du Buffer Linéaire)


for (uint32_t i = 0 ; i < N ; i++){
output = output + ech[i] * coeff[i];
}

//Envoi du résultat sur le CNA


HAL_SAI_Transmit(&output);

// Vieillissement en Buffer linéaire


for (uint32_t i = N-1 ; i > 0; i--){
ech[i] = ech[i-1];
}
}
}

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;

// Calcul du filtre numérique (cas du Buffer Circulaire)


for (uint32_t i = index ; i < (index + N) ; i++){
output = output + ech[i%N] * coeff[i-index];
}

// Vieillissement du Buffer circulaire : MAJ de l'index


if(index == 0
index = N-1;
else
index--;

//Envoi du résultat sur le CNA


HAL_SAI_Transmit(&output);
}
}

2.1.1.Le codage des entiers non signés

0 ≤ 𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁 < 2𝑁𝑁


2.1.2.Le codage des entiers signés

−2𝑁𝑁−1 ≤ 𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁𝑁 < 2𝑁𝑁−1

Nombre Codage
3 011
2 010
1 001
0 000
-1 111
-2 110
-3 101
-4 100

2.2.1.Le codage en virgule fixe

(−2 N −1 ).2 − k ≤ Nombre ≤ (2 N −1 − 1).2 − k


■ Q2 : 23.25
■ Q4 : 5.8125
■ Q7 : 0.7265625

Q5 sur 8 bits : − 4 ≤ Nombre ≤ 3.96875 avec une précision de +/- 0.015625

■ -1 ≤ Nombre <1 Q7 avec une erreur de +/- 2-8


■ -6 ≤ Nombre ≤ -4 Q4 avec une erreur de +/- 2-5
■ 200 ≤ Nombre ≤ 200 Q-1 avec une erreur de +/- 20

| 38
■ -0.1 ≤ Nombre ≤ 0 Q10 avec une erreur de +/- 2-11

Codage de nombre en Q0 sur 8 bits :

■ 98,895 en Q0 : 1100 0011, 99 codé


■ 0,01298 en Q0 : 0000 0000, 0 codé

2.2.2.Le codage en virgule flottante

■ 98.895 = 9.89 x 101


■ 10.1 = 1.01 x 101
■ 0.01298 = 1.29 x 102
■ -128000 = -1.28 x 105

■ 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é

2.3.1.Cas de la représentation en virgule fixe

2.4.Relation entre le codage des nombres et le type de variable

Nom du type Signification Codage Plage de valeur


char Entier signé 8 bits -128 à 127
unsigned int Entier non signé 32 bits 0 à 232-1
int Entier signé 32 bits -231 à 231-1
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

3.5.Les bus d'accès aux mémoires

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

4.1.2. Addition de 2 entiers signés de signes opposés

4.1.3. Addition de 2 entiers signés de même signe

Tout d'abord un calcul simple sans débordement : 4 + 3 = 7

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

4.2.1. Deux opérandes de signes opposés

4.2.2.Deux opérandes de même signe

Calcul de 1,25 + (-8) = -5,75 (Pas de débordement)

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)

4.3. Multiplication en entiers signés

Réaliser le calcul de 7 x -8 = -56 en binaire

| 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.

4.5. Etude d'un cas concret : Filtre FIR


// Valeurs entières // Valeurs réelles

coeff = [ -2097 coeff = [ 0.06402587891


-1622 -0.0494995172
9736 0.297119406
18369 0.5605773926
9736 0.297119406
-1622 -0.0494995172
-2097 0.06402587891
]; ];

Les 7 premières valeurs du signal d'entrée sont :

0 / 8926 / 15906 / 19419 / 18699 / 13902 / 6076 / -3076

| 41

Vous aimerez peut-être aussi