Skip to content Skip to navigation Skip to collection information

OpenStax-CNX

You are here: Home » Content » Programmazione di Artefatti Interattivi » Segnali nel tempo: soglie e filtri

Navigation

Recently Viewed

This feature requires Javascript to be enabled.
 

Segnali nel tempo: soglie e filtri

Module by: Davide Rocchesso. E-mail the author

Summary: Nell'elaborazione di segnali catturati da sensori c'è necessità di effettuare alcune operazioni ricorrenti, quali il filtraggio o la sogliatura.

Isteresi e soglie

L'isteresi è quella proprietà dei sistemi che li fa reagire con un certo ritardo alle forze ad essi applicate. Ad esempio, all'atto di sedersi su una poltrona imbottita, la relazione tra forza e compressione del cuscino può essere di forma isteretica, ed evidenza di ciò si può avere dall'impronta lasciata nel momento in cui ci si rialza. Nel design dell'interazione, l'isteresi viene introdotta deliberatamente per ritardare le azioni del sistema rispetto all'accadere di eventi. Per esempio, il click del mouse in una certa area può attivare un menu, la cui scomparsa viene però ritardata rispetto all'uscita da quella regione, in modo da consentire all'utente di esplorare le voci del menu anche con percorsi del mouse imperfetti. Nei regolatori automatici, quale è ad esempio il termostato per la regolazione di temperatura, è spesso presente un elemento isteretico per evitare commutazioni spurie, ad esempio dovute ai rimbalzi degli interruttori. Il termostato, in particolare, attiva il bruciatore quando la temperatura scende al di sotto di una soglia (threshold) A A, ma non lo spegne fintantoché la temperatura non raggiunge una seconda soglia B>A B A . Quindi, l'accensione e spegnimento del bruciatore dipendono dalla storia del segnale di temperatura. Ciò previene sequenze rapide di accensione/spegnimento per oscillazioni di temperatura intorno alla soglia. Nella sua forma più stilizzata, un sistema con isteresi è bistabile. Cioè caratterizzato da due stati stabili. Quindi, per programmare un interruttore con isteresi è sufficiente utilizzare una variabile boolean acceso e due soglie basso e alto:



	  if (acceso) {
	     if (signal < basso) {
	        // operazioni di spegnimento
	        acceso = false;
	     }
	  }
	  else //spento
	     if (signal > alto) {
	        // operazioni di accensione
	        acceso = true;
	     }

	

Exercise 1

Si scriva un programma Processing che disegni la curva della pressione acustica catturata dal microfono. A basse pressioni la curva sia disegnata in verde. Quando la pressione acustica supera una soglia superiore la curva deve diventare di colore rosso, e tornare ad essere verde quando torna al di sotto di una soglia inferiore.

Solution

Una soluzione che fa uso della libreria audio Minim è la seguente:

import ddf.minim.*;
 
AudioInput in;
int WIDTH=400, HEIGHT=200;
int x;
int level, prevLevel;
color colorLine=color(0,255,0);
boolean acceso=false;
int basso=80;
int alto=120;
Minim minim;
 
void setup()
{
  size(WIDTH, HEIGHT);
  minim = new Minim(this);
  // get a line-in from Minim: mono, 512 sample buffer
  // default sampling rate is 44100, default bit-depth is 16
  in = minim.getLineIn(Minim.MONO, 512);
  
}
 
void draw()
{
  if (x==0) {
    background(0);
    stroke(255,0,0); line(0,HEIGHT-alto,WIDTH,HEIGHT-alto);
    stroke(0,255,0); line(0,HEIGHT-basso,WIDTH,HEIGHT-basso);
  }
  stroke(colorLine);
  level = int(in.left.level()*HEIGHT*10);
  line(x, HEIGHT - prevLevel, (x+1)%WIDTH, HEIGHT - level);
  x = (x+1)%WIDTH;
  prevLevel = level;
  if (acceso) {
	     if (level < basso) {
                colorLine = color(0, 255, 0);
	        acceso = false;
	     }
    }
  else //spento
            {
	     if (level > alto) {
	        colorLine = color(255, 0, 0);
	        acceso = true;
	     }
  }
}
 
void stop()
{
  // always stop Minim
  minim.stop();
  super.stop();
}

	    

Exercise 2

Si modifichi il codice di Exercise 1 in modo da ottenere la curva di livello di un noise gate. Quando il livello scende al di sotto della soglia verde, si applica uno smorzamento che gradualmente forza il segnale ad essere inudibile. Quando il livello supera la soglia rossa, si applica una amplificazione che riporta il segnale al livello originale.

Solution

Nella soluzione seguente il segnale viene abbattuto, quando scende al di sotto della soglia inferiore, mediante moltiplicazioni successive per un coefficiente gDown, il cui valore (sempre minore di uno) viene impostato in base al tempo desiderato di smorzamento ed al frame rate. Lo smorzamento si considera esaurito quando il segnale di ingresso viene ad essere moltiplicato per 0.01 0.01. Analogamente, al superamento della soglia superiore, il moltiplicatore viene riportato a uno mediante moltiplicazioni successive per il coefficiente gUp, di valore sempre maggiore di uno.

import ddf.minim.*;
 
AudioInput in;
int WIDTH=400, HEIGHT=200;
int x;
int level, prevLevel, levelG;
color colorLine=color(0,255,0);
boolean acceso=false;
int basso=30;
int alto=50;
float damp=1.0;
float gain = 1.0;
Minim minim;

float decayTime = 10.0; // in seconds
float raiseTime = 2.0;
float gDown = pow(10,-2/frameRate/decayTime);
float gUp = pow(10,2/frameRate/raiseTime);

 
void setup()
{
  println("gDown = " + gDown + "gUp = " + gUp);
  size(WIDTH, HEIGHT);
  minim = new Minim(this);
  // get a line-in from Minim: mono, 512 sample buffer
  // default sampling rate is 44100, default bit-depth is 16
  in = minim.getLineIn(Minim.MONO, 512);
  
}
 
void draw()
{
  if (x==0) {
    background(0);
    stroke(255,0,0); line(0,HEIGHT-alto,WIDTH,HEIGHT-alto);
    stroke(0,255,0); line(0,HEIGHT-basso,WIDTH,HEIGHT-basso);
  }
  stroke(colorLine);
  level = int(in.left.level()*HEIGHT);  
  gain = gain*damp;
  //println(gain);
  if (gain > 1.0) gain = 1.0;
  if (gain < 0.01) gain = 0.01;
  levelG = int(level*gain);
  line(x, HEIGHT - prevLevel, (x+1)%WIDTH, HEIGHT - levelG);
  x = (x+1)%WIDTH;
  prevLevel = levelG;
  if (acceso) {
	     if (level < basso) {
                colorLine = color(0, 255, 0);
                damp = gDown;
	        acceso = false;
	     }
    }
  else //spento
            {
	     if (level > alto) {
	        colorLine = color(255, 0, 0);
                damp = gUp;
	        acceso = true;
	     }
  }
}
 
void stop()
{
  // always stop Minim
  minim.stop();
  super.stop();
}

	    

Gli esempi di sogliatura, isteresi, e gating visti nel caso dell'elaborazione del segnale audio sono di utilità generale per qualsiasi flusso di segnale proveniente da un sensore e, in particolare, anche nell'elaborazione di segnale video.

Filtri

Nella maggior parte delle applicazioni che trattano flussi di segnale provenienti da sensori, c'è la necessità di addolcire (smoothing) il profilo dei segnali stessi, in modo da evitare picchi improvvisi e rumore a rapida variabilità. Ciò si può fare con i filtri. Il più semplice filtro di smoothing è il filtro di media , il quale restituisce ad ogni istante il valor medio tra due campioni temporalmente contigui del segnale di ingresso. Interpretando i segnali nel dominio delle frequenze, l'operazione di smoothing corrisponde ad un filtraggio passa-basso, cioè ad una attenuazione delle frequenze elevate. Infatti, le variazioni repentine corrispondono a componenti di frequenza elevata. Le capacità di smoothing del filtro di media sono limitate, e per ottenere degli smoothing più decisi (maggiore attenuazione delle alte frequenze) bisogna fare medie pesate di un numero maggiore di campioni del segnale di ingresso. Un filtro molto utile allo scopo è il filtro del secondo ordine simmetrico. Qualunque sia l'ordine del filtro, la sua realizzazione come media pesata di campioni del segnale di ingresso può essere effettuata convenientemente appoggiandosi alla realizzazione a buffer circolare. In questo caso, la lettura avverrà da un certo numero di celle contigue a quella puntata da OUT, queste letture saranno pesate per i coefficienti del filtro, e il puntatore IN coinciderà con il puntatore OUT.

Exercise 3

Si modifichi il codice di Exercise 1 pre-filtrando il segnale di livello con un filtro del secondo ordine simmetrico.

Solution

Nel codice qui proposto si possono sperimentare diversi livelli di smoothing, variando i valori di a0 e a1. Più questi valori sono vicini, maggiore è l'entità dello smoothing. Per non alterare con il filtraggio l'ampiezza generale del segnale è opportuno che il doppio di a0, sommato ad a1, dia come risultato 1 1.

import ddf.minim.*;
 
AudioInput in;
int WIDTH=400, HEIGHT=200;
int x;
int level, prevLevel;
color colorLine=color(0,255,0);
boolean acceso=false;
int basso=80;
int alto=120;
Minim minim; 

float GAIN = 10;
int BUFLEN = 5;
float[] buffer = new float[BUFLEN];
int bufPoint=2, bufPoint1=1, bufPoint2=0; 
float a0 = 0.3, a1 = 0.4; //smoothing
//float a0 = 0, a1 = 1; // no smoothing
void setup()
{
  size(WIDTH, HEIGHT);
  minim = new Minim(this);
  // get a line-in from Minim: mono, 512 sample buffer
  // default sampling rate is 44100, default bit-depth is 16
  in = minim.getLineIn(Minim.MONO, 512);
  
}
 
void draw()
{
  if (x==0) {
    background(0);
    stroke(255,0,0); line(0,HEIGHT-alto,WIDTH,HEIGHT-alto);
    stroke(0,255,0); line(0,HEIGHT-basso,WIDTH,HEIGHT-basso);
  }
  stroke(colorLine);
  buffer[bufPoint] = in.left.level();
  level = int((a0*buffer[bufPoint] + a1*buffer[bufPoint1] + a0*buffer[bufPoint2])*GAIN*HEIGHT);
  bufPoint = (bufPoint+1)%BUFLEN;   bufPoint1 = (bufPoint1+1)%BUFLEN;   bufPoint2 = (bufPoint2+1)%BUFLEN;
  line(x, HEIGHT - prevLevel, (x+1)%WIDTH, HEIGHT - level);
  x = (x+1)%WIDTH;
  prevLevel = level;
  if (acceso) {
	     if (level < basso) {
                colorLine = color(0, 255, 0);
	        acceso = false;
	     }
    }
  else //spento
            {
	     if (level > alto) {
	        colorLine = color(255, 0, 0);
	        acceso = true;
	     }
  }
}
 
void stop()
{
  // always stop Minim
  minim.stop();
  super.stop();
}

Come si può dedurre dalla sperimentazione proposta in Exercise 3, prendendo medie pesate di pochi campioni di segnale l'effetto di smoothing non è macroscopico. Per avere un filtraggio più radicale bisogna usare filtri di ordine elevato (elaborazione di molti campioni di segnale) ovvero ricorrere a filtri ricorsivi.

Un filtro è un oggetto che, preso un segnale di ingresso, produce un segnale di uscita. Quando la produzione di un campione del segnale di uscita si ottiene elaborando campioni precedenti del segnale di uscita stesso (oltre che del segnale di ingresso) si dice che il filtro è ricorsivo. La ricorsività consente filtraggi radicali a complessità modeste. Ad esempio, il filtro del primo ordine rappresentato dall'equazione alle differenze

yn=ayn11xn y n a y n 1 1 a x n
(1)
è molto efficace come filtro di smoothing. E' importante mantenere la stabilità del filtro, cioè evitare che un segnale di ingresso limitato produca un'uscita illimitata. Nel caso del filtro ricorsivo del primo ordine, ciò è garantito se |a|<1 a 1 . Lo smoothing del segnale è giocoforza accompagnato da una certa latenza. Un segnale a gradino presentato in ingresso provoca in uscita un segnale che raggiunge asintoticamente il livello del gradino. Nel caso del filtro ricorsivo del primo ordine, la transizione è tanto più lenta quanto più a a è prossimo a 1 1. Per la precisione, il numero di campioni necessari per raggiungere il 99 per cento del valore finale è pari a n=-2loga n -2 10 a . Ad esempio, con a=0.9 a 0.9 la transizione dura circa 44 campioni. Naturalmente, la relazione a=10-2n a 10 -2 n consente di ricavare il valore del coefficiente che consente una transizione in n n campioni. Tale formula è stata usata anche per impostare i tempi di apertura e chiusura del noise gate.

Exercise 4

Si modifichi il codice di Exercise 1 pre-filtrando il segnale di livello con un filtro ricorsivo del primo ordine.

Solution

Si provino diversi valori di a nel codice qui proposto, mantenendo il vincolo di stabilità.

import ddf.minim.*;
 
AudioInput in;
int WIDTH=400, HEIGHT=200;
int x;
int level, prevLevel;
color colorLine=color(0,255,0);
boolean acceso=false;
int basso=80;
int alto=120;
Minim minim;

float GAIN = 10;
float currentLev;
float prevLev = 0;
float a = 0.95; // the closer to 1, the smoother the signal

void setup()
{
  size(WIDTH, HEIGHT);
  minim = new Minim(this);
  // get a line-in from Minim: mono, 512 sample buffer
  // default sampling rate is 44100, default bit-depth is 16
  in = minim.getLineIn(Minim.MONO, 512);
  
}
 
void draw()
{
  if (x==0) {
    background(0);
    stroke(255,0,0); line(0,HEIGHT-alto,WIDTH,HEIGHT-alto);
    stroke(0,255,0); line(0,HEIGHT-basso,WIDTH,HEIGHT-basso);
  }
  stroke(colorLine);
  currentLev = a*prevLev + (1 - a)*in.left.level(); 
  prevLev = currentLev;
  level = int(currentLev*GAIN*HEIGHT);  
  line(x, HEIGHT - prevLevel, (x+1)%WIDTH, HEIGHT - level);
  x = (x+1)%WIDTH;
  prevLevel = level;
  if (acceso) {
	     if (level < basso) {
                colorLine = color(0, 255, 0);
	        acceso = false;
	     }
    }
  else //spento
            {
	     if (level > alto) {
	        colorLine = color(255, 0, 0);
	        acceso = true;
	     }
  }
}
 
void stop()
{
  // always stop Minim
  minim.stop();
  super.stop();
}

	  

Particolare importanza rivestono i filtri ricorsivi del secondo ordine, i quali fungono da modello per la realizzazioni di risonanze. Una risonanza elementare si manifesta come oscillazione smorzata. Se i coefficienti del filtro del secondo ordine sono opportunamente scelti in modo da produrre una risposta ai limiti della stabilità, quello che si ottiene è una realizzazione dell'oscillatore, alternativa a quelle proposte in oscillazioni, ritardi, e fluttuazioni del tempo.

Collection Navigation

Content actions

Download:

Collection as:

PDF | EPUB (?)

What is an EPUB file?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Downloading to a reading device

For detailed instructions on how to download this content's EPUB to your specific device, click the "(?)" link.

| More downloads ...

Module as:

PDF | More downloads ...

Add:

Collection to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks

Module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks