Map() da lineare a logaritmico

Salve a tutti
Premetto non sono (quasi per nulla) addentro alle funzioni matematiche.
Quindi chiedo a voi esperti come si può trasformare una uscita map() da lineare a logaritmica, con una curva che all'avvicinarsi del valore massimo tenda a salire in modo più veloce verso il fondo scala.

Il valore ValExpr_1 è quanto arriva da un pin analogico in lettura

analogReadResolution(10);
RangeExpr_1 = map(ValExpr_1, 0, 1024, 0, 100);

Sostanzialmente ho necessità che da 60 in su la curva si impenni, allo stesso modo di come si comporta un potenziometro logaritmico (o logaritmico inverso che fa lo stesso, ma all'inizio del valore minimo).

Grazie

risolvere un'equazione di secondo grado
y = a.x2 + b.x + c
e trova a, b e c come
quando x = 0, y = 0
quando x = 614, y = 60
quando x = 1023, y = 100

non dovrebbe essere difficile da risolvere
(google translate ➜ http://abrobecker.free.fr/text/EquationDeParabolePassantParTroisPoints.pdf)

Ti serve esponenziale... Potresti usare un 10 alla x o x al quadrato o x al cubo...
Con Excel puoi fare tante simulazioni.
Che cosa vuoi fare esattamente?

veramente parlavo della istruzione map() e delle sul variabili interne

molto semplicemente ho necessità di smanettare su un pot digitale da 0 a 255 ma la scala deve essere logaritmica inversa.
scala 0-100 pot 0-255
da 0 fino a 3/4 (diciamo 0-75 della scala) il pot devi fare 0 - 240
da 75 a 100 deve andare da 241 fino a fondo scala (255)

Beh... Con 255 valori lineari una scala logaritmica non ci viene bene! Esistono potenziometri digitali logaritmici.
Comunque, se ti accontenti di come dici, map() non può fare ciò che desideri: devi farti tu una funzione apposita. Comunque è diverso da come avevi detto: se per x da 0 a 75 y va da 0 a 240, è
y = 3,2 * x
Se per x da 76 a 100 y va da 241 a 255, è
y = 240 + (x-75)*0,6, quindi addirittura rallenta di 5 volte!

Esistono potenziometri digitali logaritmici.

Ahimè che io sappia non esistono pot digitali logaritmici, almeno in I2C.
Sono tutti lineari.
Ancora peggio se parliamo di logaritmico inverso.
La serie che sto utilizzando è - per esempio - questa :
https://www.mouser.it/datasheet/2/609/AD5241_5242-1501681.pdf

Altri valori arrivano anche a 512 step, ma debbo in ogni caso capire come gestire il minimo del range.

proverò a fare come dici e vediamo cosa esce fuori

Simulazioni con Excel:

Nuovo Foglio di lavoro di Microsoft Office Excel.zip (8.1 KB)

➜ potresti usare due funzioni affini

int specificaMap(int valore) { // valore nell'intervallo [0, 1023] ➜ [0,100]
  if (valore >= 0 && valore <= 767)        return map(valore, 0, 767, 0, 75);       // 767 = 75% di 1023
  else if (valore > 767 && valore <= 1023) return map(valore, 767, 1023, 76, 100);
  return -1; // errore
}

Ad ogni post leggo range differenti, 0-100, 0-1024, 0-255, questo rende complicato dare una risposta.

In generale map effettua una traslazione lineare. Se i valori minimi sono entrambi zero non serve neppure scomodare map, è una retta passante per l'origine. Ho ingresso 0..1023 (letture da potenziometro?), lo voglio convertire in 0..255, basta dividerlo per 1023/255... o moltiplicarlo per 255/1023 che è la stessa cosa:

1687154564

Ora, come è stato detto, quello che viene chiesto è un esponenziale, che "appiattisce" la parte iniziale e rende "ripida" la parte finale, cosa che risulta tanto più evidente quanto maggiore è l'esponente. È sufficiente elevare il nostro valore, ma proporzionalmente ridurre anche il valore per cui moltiplicarlo:

156456154

E qui entra in gioco il range numerico gestibile dalle variabili. Con una long possiamo usare un esponente massimo di poco più di 3.1

Ad esempio se vogliamo elevare al quadrato la formula diventa:

871466541614

Un'altra cosa da considerare è che, visto l'appiattimento e la bassa risoluzione in uscita potranno esserci molti punti a zero e "lunghi gradini" di uguale valore all'inizio della curva.

@Claudio_FF : nota di servizio ... occhio ad usare le formule/immagini così in "nero" perché, chi usa il "tema" grigio scuro (ad esempio io) le legge malissimo e chi usa quello nero non le legge affatto ... :roll_eyes:

Esempio con il tema che uso io ...

L'ideale, se si usano immagini, è che NON siano .png trasparenti, ma abbiano un background a contrasto :slight_smile:

Guglielmo

Forse te la puoi cavare semplicemente aggiungendo una resistenza, come descritto qui

1 Like

Mi pareva di aver capito che l'OP avesse bisogno di una curva logaritmica (ripida all'inizio e appiattita alla fine :roll_eyes:

In effetti c'è un po' di confusione, credo dovuto al fatto che quando si parla di potenziometri logaritmici, ci si riferisce di solito a quelli per audio dove è la grandezza da controllare (la pressione sonora percepita dall'orecchio umano) ad avere un'andamento "logaritmico" mentre il valore resistivo del potenziometro è esponenziale per linearizzare la risposta dell'amplificatore.

image

I potenziometri normalmente chiamati logaritmici hanno un andamento esponenziale ( cioe’ la tensione prelevata aumenta prima lentamente e poi velocemente) o logaritmico (prima velocemente e poi lentamente) in funzione di come vengono collegati.
Analogamente l’esempio che ho postato puo’ servire per generare un andamento logaritmico o esponenziale: basta collegare la resistenza aggiunta su un ramo o sull’altro del potenziometro.

Prima cosa grazie a tutti per i vari interventi, che leggerò con calma tra un pò.
Volevo nel frattempo volevo evidenziare alcune cose:
Nel post principale parlo di logaritmico ed ho omesso "inverso". Mi scuso per questo ma in ogni caso la cosa cambia poco perchè in pratica basta "rigirare" una eventuale formula per il calcolo e si ottiene lo stesso.
Definiamo un'altra cosa : il pot digitale usato è un pot con 256 step di valori da 0 a 1MΩ : quando parlo di 1024 mi riferisco a quanto posso ottenere su un pin in lettura analogica se configuro la lettura a 10 bit, cioè analogReadResolution(10).
Naturalmente debbo rimappare la questione e passarla da 0-1024 a 0-256.
Perchè parlo di map ? Perchè potrebbe essere che il mio utilizzo non è 0-MAX ma 40%-78% e senza rimappare la vedo dura ...
Altra cosa : non voglio utilizzare resistenze esterne perchè la loro tolleranza sia a causa del tipo di costruzione sia - soprattutto - a causa del calore interno al circuito porterebbe ad alterare i valori finali, senza contare che non avrei un controllo assoluto della questione.

Infine : il pot non ha a che fare con audio : deve avere solo un range logaritmico inverso e basta. Ci interessa poco cosa vada a controllare. L'importante è che faccia il suo lavoro.

Insomma : Il discorso dovrebbe essere risolto via software, in modo che si possa gestire ANCHE (ma non necessariamente) un tipo di pot differente : magari su una cosa mi serve log, in un altra log inversa, in un altra ancora lineare come mamma l'ha fatto.

In questo caso è log inverso.
Via software posso ottenere tutto ed il contrario di tutto, senza troppe criticità.

Continuo a non capire che cosa vuoi fare e che cosa c'entri la lettura analogica a 10 bit... :frowning:

La funzione inversa del logaritmo e' l'esponenziale.
Si calcola con la funzione pow(base, exponent).

La base va dimensionata in funzione del valore che vuoi avere per il fondo scala, che, mi sembra di aver capito, e' 100.
Qui sotto trovi un esempio che ti trasforma un dato lineare in ingresso da 0 a 255 in uno esponenziale in uscita da 0 a 100

void setup()
{
  int i;
  int Exp;
  float BASE = pow(101, 1/255.0);
  
  Serial.begin(115200);

  for (i=0; i<256; i++)
  {
    Exp = pow(BASE,i) - 1;
    
    Serial.print(i); 
    Serial.print(" ");
    Serial.println(Exp);   
  }
}

void loop() 
{
}

Come e' gia' stato fatto notare:

ma questa e' una caratteristica della funzione esponenziale.

Inoltre, come e' gia' stato detto, Map trasla i valori in modo lineare, e quindi non puo' generare un'andamento esponenziale ma, se vuoi, la puoi usare prima, per limitare i valori di tuo interesse in un determinato range.

Ecco in modo specifico una gestione del pot digitale che avviene in modo LINEARE
Questo esempio - naturalmente - non è corretto sintatticamente : ha solo valore esplicativo.

// il pin 25 dell'esp32 è adibito alla lettura di un valore tra 0 e +3V3
Val_Pin = 25;
Val_1 = 0;

pinMode(Val_Pin, INPUT);

analogReadResolution(10);

// leggo il valore, che sarà da 0 a 1024
Val_1 = analogRead(Val_Pin);

// lo mappo da 0 a 100 (mi servirà per una mini meter grafico)
Range_1 = map( Val_1, 0, 1024, 0, 100);

// prendo il valore da 0 a 100 e lo trasformo ancora, ma in dato valido per il pot digitale, cioè da 0x00 a 0xFF (256 step)
ValorePot = map(Range_1, 0, 100, 0, 0xFF);


**** qui credo debba avvenire la trasformazione in un valore adatto a log inverso ****
quella di @Sulimarco o di @J-M-L ----> debbo provare


// scelgo indirizzo I2C configurato per pot digitale (vedi pdf in link in post sopra)
PotAddr = 0x2D;
Wire.beginTransmission(PotAddr);

// definisco il canale del pot
PotCh = 0x01;
Wire.write(PotCh);

// habemus papam ! Scrivo il valore che deve assumere il pot
Wire.write(ValorePot);

Wire.endTransmission();

Spero ora sia un pò più chiaro

Quindi hai valori da 0 a 1023 e devi convertirli in valori da 0 a 255 con andamento esponenziale, per esempio:

   0     0
 255    20
 512    60
 767   120
1023   255

Con il quadrato (x^2/4100) viene:

   0     0
 255    16
 512    64
 767   143
1023   255

Quadrato e cubo.zip (8.5 KB)