Traslazione di scala

>>> LINK A PAGINA AGGIORNATA <<<

  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .
  • .

 

trasformazione di scalaTraslazione di scala significa calcolare dei punti su una scala di valori corrispondenti ad altri punti su un’altra scala. Ad esempio: abbiamo una scala con valori da A a B, e un punto C compreso tra questi valori, ci interessa determinare il punto F su una scala con valori tra D ed E, tale che la posizione di F tra D ed E “corrisponda in scala” alla posizione di C tra A e B.

Cosa significa corrisponda in scala? Significa che il rapporto tra la lunghezza del segmento AC e la distanza totale AB, deve essere esattamente uguale al rapporto tra la lunghezza del segmento DF rispetto alla distanza totale DE. Questa uguaglianza rappresenta quindi la forma più generale per la traslazione di scala.

La lunghezza del segmento AC, divisa per la lunghezza totale AB, produce un numero compreso tra 0 e 1, che rappresenta la “posizione percentuale ” di C lungo il segmento AB. Il valore zero si ottiene quando C==A, il valore 1 si ottiene quando C==B. Per “essere in scala”, il punto F all’interno della lunghezza DE deve trovarsi alla stessa “posizione percentuale” di C.

Di seguito la formula inversa per calcolare F partendo dall’uguaglianza generale. I passaggi successivi permettono di semplificare la formula precalcolando le parti costanti:

trasformazione di scala

 

 

Invarianza orientamento assi

 

trasformazione di scala invariante
La traslazione generale vista finora è del tutto invariante rispetto all’orientamento degli assi (valori crescenti o decrescenti) e al segno dei valori (numeri positivi o negativi), il risultato viene sempre giusto.

 

 

Un caso classico

Uno dei casi forse più classici di traslazione di scala riguarda la conversione tra scale termometriche, ad esempio tra la scala Celsius (centigrada) e quella Farenheit.

La temperatura -40°C corrisponde alla stessa temperatura anche sulla scala Farenheit. Ma 100°C corrispondono invece a 212°F.

Quindi possiamo dire che A=-40 B=100 D=-40 E=212, e applicando il procedimento precedente otteniamo:

F = 1.8*C + 32

…che è la formula normalmente usata per convertire i gradi centigradi in gradi Farenheit.

 

 

Arduino e ‘map’

Questo è il modo in cui la funzione ‘map’ di Arduino calcola le traslazioni di scala. Si tratta esattamente della prima formula, dove: ‘in_min’ e ‘in_max’ corrispondono ai punti A e B, ‘x’ è il punto C, ‘out_min’ e ‘out_max’ sono i punti D ed E, mentre il risultato è il valore F:


long map(long x, long in_min, long in_max, long out_min, long out_max)
{
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Si può anche scrivere una equivalente “float map”, magari con le costanti precalcolate per rendere più veloci le conversioni:


float k1 = (out_max - out_min) / (in_max - in_min);
float k2 = out_min - (in_min * k1);

float fmap(float x)
{
    return x*k1 + k2;
}

 

 

Grafici

Un altro utilizzo comune delle traslazioni di scala si trova nella rappresentazione di grafici a video. Un’area grafica rettangolare è formata da un certo numero di punti (pixel), generalmente il primo punto in alto a sinistra ha coordinate x=0,y=0, mentre l’ultimo punto in basso a destra ha coordinate x=wid-1,y=hei-1 (dove ‘wid’ e ‘hei’ sono la larghezza e l’altezza in pixel dell’area grafica).

I valori di un grafico invece dipendono dal “dominio del problema”, cioè da quello a cui il grafico si riferisce, possono essere galloni, microsecondi, tonnellate di banane o paperdollari, tutte grandezze riguardanti un ambito ben preciso, ma sicuramente non attinenti con i pixel.

La traslazione di scala serve per trasformare i valori delle grandezze da rappresentare, in coordinate interne all’area grafica. Ad esempio se vogliamo tracciare una funzione trigonometrica in un’area di 256×192 pixel, rappresentando in orizzontale i gradi (da 0 a 360) e in verticale il valore della funzione (da -1 a +1), ci troviamo davanti al seguente “progetto”:

area graficaIn pratica i valori dei gradi da 0 a 360 vanno convertiti in coordinate x da 0 a wid-1, mentre i valori della funzione da -1 a +1 vanno convertiti in coordinate y da hei-1 a 0 (le coordinate y crescono verso il basso, quindi il valore più basso da rappresentare si troverà alla coordinata y più grande).

Il seguente programma Python traccia la funzione sin(2x)*cos(7x) in un canvas 256×192 pixel creato con la libreria grafica tk:


try:    import tkinter as tk
except: import Tkinter as tk
from math import sin, cos, radians

#dimensioni canvas grafico
wid = 256
hei = 192

#coordinate relative grafico
xmin = 0
xmax = 360
ymin = -1
ymax = 1

#calcolo costanti di conversione
xK1 = (wid - 1.) / (xmax - xmin)
xK2 = -(xK1 * xmin)
yK1 = (1. - hei) / (ymax - ymin)
yK2 = hei - 1 - yK1*ymin

#funzioni di conversione
def xmap(n):
    return int(round(xK1*n + xK2))

def ymap(n):
    return int(round(yK1*n + yK2))

#programma principale
root = tk.Tk();
canv = tk.Canvas(
    root,
    highlightthickness=0,
    bg='navy',
    width=wid,
    height=hei
    )
canv.pack(expand=1)

#calcolo punti, coppie x,y
minf = xmin
maxf = xmax
punti = wid
step = (maxf - minf) / (punti - 1.)
data = []
for punto in range(punti):
    x = minf + step*punto
    y = sin(radians(x*2)) * cos(radians(7*x))
    data.append((x, y))
    
#conversione in pixel    
data = [(xmap(x), ymap(y)) for x, y in data]

#tracciamento curva
canv.create_line(*data, fill='yellow')

root.mainloop()

grafico funzionePrima vengono calcolati tutti i punti (coppie x,y) nel dominio del problema (gradi e valori -1..+1). Poi vengono passati alle funzioni ‘xmap’ e ‘ymap’ che traslano la scala ottenendo i valori corrispondenti in coordinate dei pixel. Infine viene chiamato il metodo ‘create_line’ del canvas, che in un colpo solo traccia l’intera curva dalla sequenza di coordinate (una grande comodità di tk).

 

 

 

Scala logaritmica

 

trasformazione scala logaritmicaPuò essere necessario rappresentare dei valori su una scala logaritmica. In tal caso la procedura generale di traslazione è identica, ma i limiti minimo e massimo in “ingresso” e i valori da convertire, vanno prima trasformati nel loro logaritmo (questo riguarda anche l’eventuale calcolo delle costanti).

 

 

 

 

 

Il programma seguente è predisposto per rappresentare in modo logaritmico sia la scala verticale che quella orizzontale (basta impostare a True le costanti ylog o xlog):


try:    import tkinter as tk
except: import Tkinter as tk
from math import log

#dimensioni canvas grafico
wid = 256
hei = 192

#coordinate relative grafico
xmin = 0.1
xmax = 1000
ymin = -2
ymax = 4
xlog = False
ylog = False

#calcolo costanti di conversione
if xlog:
    xK1 = (wid - 1.) / (log(xmax) - log(xmin))
    xK2 = -(xK1 * log(xmin))
else:
    xK1 = (wid - 1.) / (xmax - xmin)
    xK2 = -(xK1 * xmin)
if ylog:
    yK1 = (1. - hei) / (log(ymax) - log(ymin))
    yK2 = hei - 1 - yK1*log(ymin)
else:
    yK1 = (1. - hei) / (ymax - ymin)
    yK2 = hei - 1 - yK1*ymin

#funzioni di conversione
def xmap(n):
    if xlog:
        return int(round(xK1*log(n) +xK2))
    else:
        return int(round(xK1*n + xK2))
def ymap(n):
    if ylog:
        return int(round(yK1*log(n) + yK2))
    else:
        return int(round(yK1*n + yK2))

#programma principale
root = tk.Tk();
canv = tk.Canvas(
    root,
    highlightthickness=0,
    bg='#D0D0D0',
    width=wid,
    height=hei
    )
canv.pack(expand=1)

#tracciamento assi verticali
for n in (.1, .2, .3, .4, .5, .6, .7, .8, .9, 
          1, 2, 3, 4, 5, 6, 7, 8, 9,
          10, 20, 30, 40, 50, 60, 70, 80, 90,
          100, 200, 300, 400, 500, 600, 700, 800, 900, 1000):
    x = xmap(n)
    canv.create_line(x, 0, x, hei, fill='gray')

#calcolo punti, coppie x,y
minf = xmin
maxf = xmax
punti = wid
step = (maxf - minf) / (punti - 1.)
data = []
for punto in range(punti):
    x = minf + step*punto
    y = log(x, 10)
    data.append((x, y))
    
#conversione in pixel    
data = [(xmap(x), ymap(y)) for x, y in data]

#tracciamento curva
canv.create_line(*data, fill='red')

root.mainloop()

Rappresentazione di un logaritmo in base dieci nel range x da 0.1 a 1000. Nel primo grafico la scala orizzontale è lineare, nel secondo logaritmica (un logaritmo su una scala logaritmica appare come una retta, più o meno inclinata a seconda della base).

grafico scala linearegrafico scala logaritmica

 

 

 

(12/8/2018)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *