Esercizio 19realizzazione in C di un filtro con coefficienti maggiori di 1 a virgola fissa (tema d'esame febbraio 2026)
In questa pagina 5
Testo (tema d'esame febbraio 2026, problema P3). Si deve calcolare (il filtro dell'esercizio 17) con un processore a virgola fissa a 32 bit. Si chiede di: (a) rappresentare i coefficienti , , su 16 bit nella notazione che minimizza l'errore; (b) scrivere l'espressione in linguaggio C che realizza l'algoritmo, assumendo in formato frazionario 0.16 U (Q16) e in formato 4.12 U; (c) il valore massimo di che non causa overflow nel calcolo; (d) verificare il comportamento con un gradino unitario.
Teoria usata: Realizzare un filtro o un regolatore a virgola fissaRealizzare in C un filtro a virgola fissa vuol dire scegliere per ogni dato il formato (coefficienti $<1$ in 0.16 U, coefficienti $>1$ in 1.15, 4.12, 5.11 S...), moltiplicare con aritmetica a 32 bit ($16\times16\to32$) e riportare il prodotto al formato di arrivo con uno shift a destrascorrimento dei bit verso destra: equivale a dividere per una potenza di 2; per sommare due prodotti con scale diverse si fa lo shift prima di sommare. Con $a+b=2^{16}$ il filtro $y=\big(a,y_{k-1}+b,(u\ll4)\big)\gg16$ non va in overflow in un uint32_t. Nel codice il formato di ogni variabile va dichiarato in un commento; la funzione $\sin x\approx x-\frac{x^3}6+\frac{x^5}{120}$ mostra come si approssima una funzione con polinomi a coefficienti in virgola fissa.Realizzare un filtro o un regolatore a virgola fissa →, Operazioni in virgola fissa - somma, prodotto e riallineamentoIn virgola fissa il processore opera sugli interi e non sa dov'è la virgola: tocca al programmatore. Regola 1: si sommano solo dati con lo stesso formato (stesso $m$). Regola 2: il prodotto di $n_1.m_1$ per $n_2.m_2$ ha $m_1+m_2$ bit frazionari e il doppio dei bit: va riallineato con uno shift a destra di $m_2$ posizioni (per riportarlo a $m_1$) o preso dalla parte alta. Con la normalizzazione frazionaria $1.15$ il prodotto è $2.30$ e basta uno shift a sinistra di 1 prima di prendere la parte alta. I fattori di scala si scelgono per evitare overflow e perdita di risoluzione.Operazioni in virgola fissa - somma, prodotto e riallineamento →, Rappresentare un valore reale in virgola fissa - formato ottimo ed errorePer rappresentare un reale $x$ su $W$ bit a virgola fissa si sceglie il formato che minimizza l'erroresceglie la rappresentazione per cui la differenza tra il valore rappresentato e quello vero è la più piccola possibile: il maggior numero di bit frazionari $m$ compatibile con l'intervallo ($n=W-m$ bit interi, con U se $x\ge0$, con S se $x<0$). Poi $C=\mathrm{round}(x\cdot2^m)$, scritto in esadecimale (per un negativo, in complemento a 2), e l'errore $\varepsilon=\frac{C}{2^m}-x$, positivo se in eccesso, ha modulo $\le2^{-(m+1)}$. Se invece è dato l'errore massimo, i bit minimi si ricavano da $2^{-(m+1)}\le\varepsilon_{max}$.Rappresentare un valore reale in virgola fissa - formato ottimo ed errore →.
(a) Coefficienti
- : positivo e minore di 1: 0.16 U. (errore ; con troncamento si avrebbe ).
- : positivo, : 4.12 U. ().
- : negativo, : serve il segno: 5.11 S (segno + 4 bit interi + 11 frazionari, intervallo ). (esatto).
(b) Espressione in C
Bit frazionari dei prodotti. è in 4.12 (); in 0.16 ().
- : bit frazionari. Per portare il prodotto a 12 bit frazionari si fa .
- : ; : . Per sommare i due prodotti li si porta alla stessa scala spostando a destra di 1 bit ( passa da 12 a 11 bit frazionari): ha bit frazionari come . La somma dei due ha 27 bit frazionari; per arrivare a 12 si fa .
// a16: 0.16 U (uint16_t); b0_16: 4.12 U (uint16_t); b1_16: 5.11 S (int16_t)
// x, x0: 0.16 U; y, y0: 4.12 U (uint32_t)
y = ((a16 * y0) >> 16) + ((((b0_16 >> 1) * x) + (b1_16 * x0)) >> 15);
y0 = y; x0 = x;Il calcolo è su 32 bit: a16*y0 con e sta in un uint32_t; per il termine con segno si usa int32_t (cast di b1_16 e x0 a int32_t prima del prodotto: , ancora nei limiti di int32_t). Il primo prodotto non va in overflow ().
(c) Valore massimo di
Il prodotto con vale al massimo: l'uscita è in 4.12 U, intervallo : serve . Ma in 0.16 U è comunque minore di 1 (): (fondo scala), nessun overflow. (La risposta del testo: .)
Attenzione: per un gradino che scende da 1 a 0 l'uscita ha valore al primo campione (), negativo: con in formato senza segno si avrebbe un avvolgimento. Nell'uso reale va usata una variabile con segno (4.12 S o 5.11 S) se l'ingresso può diminuire; il testo ipotizza ingressi crescenti.
(d) Verifica con un gradino
Si applica da (, ):
| esadecimale | valore | valore teorico | |
|---|---|---|---|
| 0 | 12,1995 | 12,2 | |
| 1 | 9,959 | 9,96 | |
| 2 | 8,166 | 8,168 | |
| 21 | 1,1001 | 1,1033 | |
| 22 | 1,0793 | 1,0826 |
I valori coincidono con quelli teorici a meno di (errori di arrotondamento, soprattutto del termine e dei troncamenti degli shift). Il filtro entra nel del valore finale a come previsto ( è quasi al limite).
Errori comuni
- Rappresentare in formato senza segno: il codice letto come 5.11 U vale , non .
- Sommare con 28 bit frazionari e con 27 senza riallineare.
- Dimenticare il cast a 32 bit prima del prodotto (in C il prodotto di due
uint16_tè unintcon segno e può andare in overflow). - Applicare lo shift di 16 a tutti i termini senza controllare quanti bit frazionari ha ciascun prodotto.
Versione ripasso
Testo. Realizzare in C, a virgola fissa a 32 bit, con in 0.16 U e in 4.12 U (febbraio 2026).
- Coefficienti: 0.16 U
0xCCCD; 4.12 U0xC333; 5.11 S0xA000. - Allineamento: : 28 bit frazionari (); e : 27 bit ():
y=((a16*y0)>>16)+((((b0_16>>1)*x)+(b1_16*x0))>>15); - Massimo: e : ; gradino che scende: (serve il segno).
- Verifica:
C331(12,1995),9F58(9,959),82AA(8,166), . - Errori: senza segno; scale diverse sommate; prodotto senza cast; shift uniforme (Realizzare un filtro o un regolatore a virgola fissaRealizzare in C un filtro a virgola fissa vuol dire scegliere per ogni dato il formato (coefficienti $<1$ in 0.16 U, coefficienti $>1$ in 1.15, 4.12, 5.11 S...), moltiplicare con aritmetica a 32 bit ($16\times16\to32$) e riportare il prodotto al formato di arrivo con uno shift a destrascorrimento dei bit verso destra: equivale a dividere per una potenza di 2; per sommare due prodotti con scale diverse si fa lo shift prima di sommare. Con $a+b=2^{16}$ il filtro $y=\big(a,y_{k-1}+b,(u\ll4)\big)\gg16$ non va in overflow in un
uint32_t. Nel codice il formato di ogni variabile va dichiarato in un commento; la funzione $\sin x\approx x-\frac{x^3}6+\frac{x^5}{120}$ mostra come si approssima una funzione con polinomi a coefficienti in virgola fissa.Realizzare un filtro o un regolatore a virgola fissa →).