Faire une interpolation avec un ESP32c3 [résolu]

Bonjour,

Je voudrais avoir une transformation d'une valeur lue vers une valeur calculée permettant d'amplifier les zones lues vers les extrémités et décaler le milieu.

Valeurs lues : 0 25 50 75 100
Valeurs calculées 0 45 70 80 100

J'ai pensé à utiliser la bibliothèque InterpolationLib mais je ne comprends rien à l'exemple interpolation.ino et je n'ai pas trouvé de tuto sur le web

Quelqu'un peut-il me donner un coup de main svp ?

quand on parle d'interpolation il faut définir ce que vous attendez entre les points connus - ça peut être une fonction affine par morceaux (on met des droites)

ou une interpolation bilinéaire (une courbe qui passe par tous les points)

et cette courbe peut prendre différentes forme

➜ vous voulez quelle approche ?

Un petit coup d'Excel :

Une interpolation par un polynôme de degré 3 fonctionne très bien : il te reste à créer une fonction qui calcule ce polynôme. L'équation est en rouge ci-dessus. Ta courbe est en trait plein, l'interpolation en pointillés.

Attention, pour x=0, il te fournit une valeur de -0.2857 : si tu veux exactement 0, il faut le forcer.

Sinon python est pratique pour résoudre ce genre de chose:

import numpy as np
X = np.array([0, 25, 50, 75, 100])
Y = np.array([0, 45, 70, 80, 100])
coefficients = np.polyfit(X, Y, deg=4)  # Polynôme de degré 4
poly_function = np.poly1d(coefficients)
print("Équation polynomiale :", poly_function)

➜ 0.000002133 x4 - 0.0002667 x3 - 0.005333 x2 + 2.067 x - 4.449e-14

C'est plus précis !

si on demande à Python3 un polynôme du 3ème degré il dit

0.00016 x3 - 0.03143 x2 + 2.543 x - 0.2857

➜ il est à peu près d'accord avec excel :slight_smile:

J'ai déchainé les matheux !

Vous ne voulez pas de la bibliothèque ? Ni m'expliquer comme l'utiliser ?

Car dans arduino je n'ai jamais rentré des polynomes du 3ème degré...

En plus j'ai donné des valeurs de 0 à 100, en réalité d'un côté j'ai une valeur de 0 à 4096 (analogRead sur esp) et de l'autre une lecture d'une AS500 qui mesure la course et donc qui doit avoir des limites à calibrer en fonction de l'usage. Je ne vois pas l'intérêt de faire un map avant ou après l'interpolation autant l'intégrer au départ.
Comment vous obtenez cette belle équation ?

@J-M-L t'a donné les lignes Python pour le générer.
Il te suffit de changer les valeurs dans les vecteurs du début, pour aller de 0 à 4096 au lieu de 0 à 100.

C'est pas ça, mais je ne la connais pas, cette méthode est plus simple.

:wink:

je ne l'ai jamais utilisée mais ça n'a pas l'air compliqué

essayez cela pour avoir une interpolation linéaire (fonction affine)

#include "InterpolationLib.h"

double xValues[] = {0, 25, 50, 75, 100};
double yValues[] = {0, 45, 70, 80, 100};
const int numValues = sizeof xValues / sizeof * xValues;

void interpoler(double x) {
  Serial.print(x);
  Serial.print("\t=> ");
  Serial.println(Interpolation::Linear(xValues, yValues, numValues, x));
}

void setup() {
  Serial.begin(115200);
  interpoler(0);
  interpoler(10);
  interpoler(25);
  interpoler(30);
  interpoler(75);
}

void loop() {}

➜ vous verrez dans le terminal série

0.00	=> 0.00
10.00	=> 18.00
25.00	=> 45.00
30.00	=> 50.00
75.00	=> 80.00

et si vous remplacez la fonction d'interpolation par ConstrainedSpline au lieu de linéaire

  Serial.println(Interpolation::ConstrainedSpline(xValues, yValues, numValues, x));

vous aurez

0.00	=> 0.00
10.00	=> 20.16
25.00	=> 45.00
30.00	=> 51.26
75.00	=> 80.0

vous disposez de toutes ces 5 possibilités:

double Step(double xValues[], double yValues[], int numValues, double pointX, double threshold = 1);
double Linear(double xValues[], double yValues[], int numValues, double pointX, bool trim = true);
double SmoothStep(double xValues[], double yValues[], int numValues, double pointX, bool trim = true);
double CatmullSpline(double xValues[], double yValues[], int numValues, double pointX, bool trim = true);
double ConstrainedSpline(double xValues[], double yValues[], int numValues, double pointX, bool trim = true);

il s'agit juste d'écrire la formule et éventuellement mettre cela dans une fonction

double interpolation(double x) {
  return 0.00016 * x * x * x  - 0.03143  * x * x + 2.543 * x - 0.2857;
}

quand vous écrivez x * x * x c'est x3

J'ai essayé cela

#include "InterpolationLib.h"

const int numValues = 5;
double xValues[5] = { 0, 15, 60, 95, 100 };
double yValues[5] = {  1,  25,  50,  75,  100 };

void setup() {
  Serial.begin(115200);
  delay(3000);
  Serial.println("==============================");
  Serial.println(__FILE__);
  for (float xValue = 0; xValue <= 100; xValue += 1)	{
      Serial.print(xValue);
      Serial.print(',');
		  Serial.println(Interpolation::SmoothStep(xValues, yValues, numValues, xValue));	}
  }

void loop(){
  }

C'est un début mais j'ai du mal avec la version IDE2 comment on copie le résultat du moniteur série ? Quand je sélectionne tout le résultat il ne copie que ce qui est sélectionné ET à l'écran

En pluche le traceur série : y a un mode d'emploi car je n'obtiens pas la même chose qu'un diagramme dans le tableur

oui le terminal série de la version 2 n'est pas génial...
utilisez un autre terminal

J'ai essayé la formule dans un tableur =0,0002A1A1A1-0,0314A1A1+2,5429A1-0,2857
Et pour de 0 à 100 j'obtiens (en gros) e 0 à 140 mais la courbe est belle

Comment vous obtenez l'équation ?

Déjà que l'utilisation d'un esp32c3 avec à chaque fois faire reset+ boot puis lâcher reset puis lâcher boot à chaque fois est pénible utiliser putty en com peux rester actif quand on lance l'upload ?

Non, Putty actif va mobiliser le port série ... qui ne sera donc pas disponible pour le téléversement

les cartes avec des ESP32-C3 comportant un adaptateur série/USB (CH340 ou autre) sont plus pratiques pour la mise au point que les cartes où seul le port USB natif est présent
image

Si ta carte n'a que l'USB natif tu peux raccorder temporairement sur RX et TX un FTDI ou équivalent pour faciliter le flashage et la mise au point

Sur le tableur Excel, depuis le temps que j'ai cessé de l'utiliser plus, je ne sais plus, sur Libre office Calc qui est le seul tableur "excellent", c'est au moment de la demande d'une courbe "de tendance" qu'il faut cocher "afficher l'équation" et aussi utile "afficher le coefficient de détermination R2" qui doit être le plus proche de 1.

Le degré max du polynôme dépend du nombre de points.
Plus ce nombre de points est élevé, plus le degré max du polynôme peut être élevé.

Si tu as plus de points, ce sont des essais à faire avec un tableur. Le bon degré du polynôme n'est pas le plus élevé possible, mais celui qui est suffisant.
En technique, le "plus" fait rarement le "moins" contrairement au vieil adage.

Merci 68tjs, c'est beau l'informatique !

Alors, je vérifie le calcul à la main :

  • si x = 100 = 102, alors x2 = 10^4 et x3 = 10^6
  • 0.0002 c'est 2 10-4 donc fois x3 ça donne 200
  • 0.0314 c'est 3.14 10-2 donc fois x2 ça donne 314
  • 2.5429 * 100 = 254.29
  • au total on a : 200 - 314 + 254.29 - 0.2857 = 140.0043

Il doit y avoir des arrondis dans les coefficients
Avec ceux de @J-M-L on obtient 160 - 314.3 + 254.3 - 0.2857 = 99.7143
C'est mieux : donc il vaut mieux prendre la formule donnée par @J-M-L au message 7 (en corrigeant le x3 en x2 :smiley: )

ah oui :slight_smile:

Merci pour les explications et la formule

Je crois que dans les programmes d'émetteur de radiocommande ils utilisent cette bibliothèque car on a une fenêtre où on peut régler 5 points. Dommage que j'ignore où trouver leur source et même si je trouvais, en extraire la bonne partie me prendrait plus de temps que de la reprogrammer tout seul.

Pour moi le sujet est plus que résolu car j'en ai appris plus que ce que je recherchais