Mapper une plage numérique sur une autre

Les maths n’ont jamais été ma force à l’école 🙁

int input_start = 0; // The lowest number of the range input. int input_end = 254; // The lowest number of the range input. int output_start = 500; // The lowest number of the range output. int output_end = 5500; // The largest number of the range ouput. int input = 127; // Input value. int output = 0; 

Comment puis-je convertir la valeur d’entrée en valeur de sortie correspondante de cette plage?

Par exemple, une valeur d’entrée de “0” correspond à une valeur de sortie de “500”, une valeur d’entrée de “254” correspond à une valeur de sortie de “5500”. Je n’arrive pas à comprendre comment calculer une valeur de sortie si une valeur d’entrée est égale à 50 ou 101.

Je suis sûr que c’est simple, je ne peux pas penser maintenant 🙂

Edit: J’ai juste besoin de nombres entiers, pas de fractions ni quoi que ce soit.

Oublions les maths et essayons de résoudre ceci intuitivement.

Premièrement, si nous voulons mapper des nombres en entrée compris dans la plage [ 0 , x ] à la plage en sortie [ 0 , y ], il nous suffit de redimensionner la balance de manière appropriée. 0 va à 0, x à y , et un nombre t ira à (y/x)*t .

Réduisons donc votre problème au problème plus simple ci-dessus.

Une plage d’entrée de [ input_start , input_end ] a input_end - input_start + 1 nombres. Donc, cela équivaut à une plage de [ 0 , r ], où r = input_end - input_start .

De même, la plage de sortie est équivalente à [ 0 , R ], où R = output_end - output_start .

Une entrée input est équivalente à x = input - input_start . Ceci, à partir du premier paragraphe, se traduira par y = (R/r)*x . Ensuite, nous pouvons traduire la valeur y dans la plage de sortie d’origine en ajoutant output_start : output = output_start + y .

Cela nous donne:

 output = output_start + ((output_end - output_start) / (input_end - input_start)) * (input - input_start) 

Ou d’une autre manière:

 /* Note, "slope" below is a constant for given numbers, so if you are calculating a lot of output values, it makes sense to calculate it once. It also makes understanding the code easier */ slope = (output_end - output_start) / (input_end - input_start) output = output_start + slope * (input - input_start) 

Maintenant, ceci étant C et la division en C tronquée, vous devriez essayer d’obtenir une réponse plus précise en calculant les choses en virgule flottante:

 double slope = 1.0 * (output_end - output_start) / (input_end - input_start) output = output_start + slope * (input - input_start) 

Si vous voulez être encore plus correct, vous ferez un arrondi au lieu de la troncature dans la dernière étape. Vous pouvez le faire en écrivant une simple fonction round :

 #include  double round(double d) { return floor(d + 0.5); } 

Ensuite:

 output = output_start + round(slope * (input - input_start)) 

Arduino a cette carte intégrée.

Exemple:

 /* Map an analog value to 8 bits (0 to 255) */ void setup() {} void loop() { int val = analogRead(0); val = map(val, 0, 1023, 0, 255); analogWrite(9, val); } 

Il a également l’implémentation sur cette page:

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

Le point crucial ici est de faire la division entière (ce qui inclut l’arrondi) au bon endroit. Jusqu’à présent, aucune des réponses n’a donné raison aux parenthèses. Voici la bonne façon:

 int input_range = input_end - input_start; int output_range = output_end - output_start; output = (input - input_start)*output_range / input_range + output_start; 

la formule est

f (x) = (x – entrée_start) / (entrée_end – entrée_start) * (sortie_end – sortie_start) + sortie_start

Je vais relier ce post ici: https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/ car cela m’a beaucoup aidé lorsque j’essaie de trouver cela intuitivement. Une fois que vous comprenez ce que dit le message, il est facile de trouver ces formules vous-même. Notez que j’avais l’habitude de lutter avec de telles questions aussi. (Je n’ai pas d’affiliation – je l’ai trouvé très utile)

disons que vous avez la plage [input_start..input_end] , commençons par la normaliser de telle sorte que 0 soit input_start et 1, input_end . C’est une technique simple pour rendre le problème plus facile.

Comment fait-on cela? nous allons, nous devrons décaler tout ce qui rest de input_start, de telle sorte que si input x est input_start , il devrait donner zéro.

alors, disons que f(x) est la fonction qui effectue la conversion.

 f(x) = x - input_start 

essayons:

 f(input_start) = input_start - input_start = 0 

fonctionne pour input_start .

à ce stade, cela ne fonctionne pas encore pour input_end , car nous ne l’avons pas mis à l’échelle.

Réduisons simplement la longueur de la plage, puis la plus grande valeur (input_end) sera mappée à un.

 f(x) = (x - input_start) / (input_end - input_start) 

ok, essayons avec input_end .

f (input_end) = (input_end - input_start) / (input_end - input_start) = 1

génial, semble fonctionner.

d’accord, étape suivante, nous allons en fait l’adapter à la plage de sortie. C’est aussi simple que de simplement multiplier avec la longueur réelle de la plage de sortie, en tant que telle:

 f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) 

maintenant, en fait, nous avons presque terminé, nous devons simplement le déplacer vers la droite pour que 0 commence à partir de output_start.

 f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start 

Essayons-le rapidement.

 f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start 

vous voyez que la première partie de l’équation est à peu près multipliée par zéro, annulant ainsi tout, vous donnant

 f(input_start) = output_start 

Essayons également input_end .

 f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start 

qui à leur tour finira comme:

 f(input_end) = output_end - output_start + output_start = output_end 

comme vous pouvez le constater, il semble maintenant être correctement mappé.

 output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start 

Cela permet de déterminer proportionnellement “dans quelle mesure” se situe la plage d’entrée. Il applique ensuite cette proportion à la taille de la plage de sortie pour déterminer en termes absolus à quelle distance de la plage de sortie devrait se trouver la sortie. Il ajoute ensuite le début de la plage de sortie pour obtenir le numéro de sortie réel.