// Les 2 tables ci dessous peuvent être recréée en modifiant le parametre RANGEMAX
// pour actualiser le contenu, decommenter la ligne sui suit
#define REBUILD
#define RANGEMAX 61 // nombre max de période de 10ms pour etablir un couple nbON / nbTOTAL
uint8_t tabPulseSinusTotal[101]= { 2,
61,43,33,25,40,33,57,37,11,20, 55,25,23,57,40,25,53,61,21, 5,
19,59,61,25, 8,23,37,25,31,20, 29,47,61,59,40,25,27,29,59, 5,
61,19,51,59,40,37,17,25,51, 4, 51,25,17,37,40,59,51,19,61, 5,
59,29,27,25,40,59,61,47,29,20, 31,25,37,23, 8,25,61,59,19, 5,
21,61,53,25,40,57,23,25,55,20, 11,37,57,33,40,25,33,43,61, 2
};
uint8_t tabPulseSinusOn[101] = { 0,
1, 1, 1, 1, 2, 2, 4, 3, 1, 2, 6, 3, 3, 8, 6, 4, 9,11, 4, 1,
4,13,14, 6, 2, 6,10, 7, 9, 6, 9,15,20,20,14, 9,10,11,23, 2,
25, 8,22,26,18,17, 8,12,25, 2, 26,13, 9,20,22,33,29,11,36, 3,
36,18,17,16,26,39,41,32,20,14, 22,18,27,17, 6,19,47,46,15, 4,
17,50,44,21,34,49,20,22,49,18, 10,34,53,31,38,24,32,42,60, 2
};
#define LED 2
void setup() {
Serial.begin(115200);
#ifdef REBUILD
remakeTableRatioMultiSin();
#endif
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
Serial.printf("Ready\n");
Serial.print("LED on gpio ");Serial.println(LED);
}
int i = 0; // index de l'action [ici on reste avec l'action 0]
int k =0; // pourcentage d'ouverture de 0 a 100
uint32_t startAt = millis();
uint8_t PulseTotal[1] = {tabPulseSinusTotal[0]};
uint8_t PulseOn[1] = {tabPulseSinusOn[0]};
uint8_t PulseComptage[1] = {0};
void loop() {
if (k > 100) k = 0; // parcours de 0% a 100% puis recommence
if (PulseTotal[i] > 0) {
int on_count = PulseOn[i];
int total = PulseTotal[i];
int pos = PulseComptage[i] >= total ? 0 : PulseComptage[i];
// lbe debut REPARTITION DES ON
int pair_count = on_count / 2;
int reste = on_count % 2;
bool is_on = false;
// Répartition des paires ON (2 cycles consécutifs)
for (int p = 0; p < pair_count; p++) {
int start = (p * total) / pair_count;
if (pos == start || pos == start + 1) {
is_on = true;
break;
}
}
// Placement du dernier ON si impair, dans une position libre
if (!is_on && reste == 1) {
for (int j = 0; j < total; j++) {
bool already_used = false;
for (int p = 0; p < pair_count; p++) {
int start = (p * total) / pair_count;
if (j == start || j == start + 1) {
already_used = true;
break;
}
}
if (!already_used) {
if (pos == j) {
is_on = true;
}
break;
}
}
}
digitalWrite(LED , is_on ? HIGH : LOW);
PulseComptage[i]++;
if (PulseComptage[i] >= total) {
PulseComptage[i] = 0;
// Délai aléatoire non bloquant entre 0 et 10 µs pour decaler temporellement la sequence suivante pour reduire les harmoniques du secteur
uint32_t delayStart = micros();
uint32_t randomDelay = random(0, 11); // 0 à 10 inclus
while (micros() - delayStart < randomDelay) ; // boucle active non bloquante max 10 µs
}
}
//fin de la repartition
delay(10); // simul durée d'un demi sin
// if (k > tabPulseSinusTotal[k]) posit = 0;
if (millis() - startAt > 2000) { // boucle de avant de passer a l'index suivant
Serial.println(k);
k++;
PulseTotal[i] = tabPulseSinusTotal[k];
PulseOn[i] = tabPulseSinusOn[k];
startAt = millis();
}
}
#ifdef REBUILD
// choix de ce qui est imprimé en sortie
#define showtable
#define printvarsequence
// actualise tabPulseSinusTotal[] et tabPulseSinusOn[] avec les paramatres
// sequence:
// impose index 0 comme 0/2, impose index 100 comme 2/2
// calcul les meilleurs couple ON/TOT pour les cas impaire (index 1 va evidement être 1/RANGEMAX et index 99 (RANGEMAX-1)/RANGEMAX)
// pour les cas paires, on utilise comme cible la mediane des valeurs pour les nombres impaire adjacent
// on a 1 qui est 1/61=0.0163934 et 3 qui est a 1/33=0.0303030, on cherche le meilleur couple pour tomber sur (0.0163934+0.303030)/2=0.023348
void remakeTableRatioMultiSin() {
tabPulseSinusOn[0] = 0; tabPulseSinusTotal[0] = 2;
tabPulseSinusOn[100] = 2; tabPulseSinusTotal[100] = 2;
for (int P = 1; P <= 99; P = P + 2) { // Boucle principale pour P allant de 0% à 100% de 2 en 2
tabPulseSinusTotal[P] = 0xFF;
tabPulseSinusOn[P] = 0xFF;
double R = (double)P / 100.0; // Ratio cible (en nombre a virgule)
if (P % 2 == 0) R = (((double)tabPulseSinusOn[P-1] / (double)tabPulseSinusTotal[P-1]) + ((double)tabPulseSinusOn[P+1] / (double)tabPulseSinusTotal[P+1])) / 2.0;
int meilleur_N = 0xFF;
int meilleur_D = 0xFF;
double erreur_min = 1.0; // erreur la plus petite avec le couple N/T comparé a P
for (int D = 1; D <= RANGEMAX; D++) {
double N_ideal = R * D; // Calcul du numérateur idéal
int N_candidats[2];
N_candidats[0] = (int)floor(N_ideal); // Partie entière inférieure
N_candidats[1] = (int)ceil(N_ideal); // Partie entière supérieure
for (int i = 0; i < 2; i++) { // essai le nombre entier idéal juste avant et juste après
int N = N_candidats[i];
if (N >= 1 && N <= RANGEMAX) { // Contrainte 1: Plage [0, ...]
if ((N % 2 == 0) || (D % 2 != 0)) { // Contrainte 2: Parité
double ratio_actuel = (double)N / D; // Calcul de l'erreur absolue
double erreur = fabs(ratio_actuel - R);
if (erreur < erreur_min) { // Mise à jour si l'erreur est plus petite
erreur_min = erreur;
meilleur_N = N;
meilleur_D = D;
}
}
}
}
}
tabPulseSinusTotal[P] = meilleur_D;
tabPulseSinusOn[P] = meilleur_N;
P = 0; // on a traité le cas 99%, on recommence avec les combinaisons paires (le for va ajouter 2 au démarrage )
}
#ifdef showtable
for (int i = 0; i <=100; i++) {
double delta = i == 0 ? 0 : 100.0*(1.*tabPulseSinusOn[i]/tabPulseSinusTotal[i]-1.*tabPulseSinusOn[i-1]/tabPulseSinusTotal[i-1]);
Serial.printf("%03d : %02d/%02d = %8.4f | step %f\n", i, tabPulseSinusOn[i], tabPulseSinusTotal[i], 100.0*tabPulseSinusOn[i]/tabPulseSinusTotal[i], delta);
}
#endif
#ifdef printvarsequence
// texte pour variable 'en dur sans refaire les calculs
Serial.printf("\nuint8_t tabPulseSinusTotal[101]= {");
for (int i = 0; i <= 100; i++) {
Serial.printf("%2d",tabPulseSinusTotal[i]);
if (i != 100) Serial.printf(","); else Serial.printf("\n};\n");
if (i % 10 == 0) Serial.printf(" ");
if (i % 20 == 0 && i != 100) Serial.printf("\n ");
}
Serial.printf("\nuint8_t tabPulseSinusOn[101] = {");
for (int i = 0; i <= 100; i++) {
Serial.printf("%2d",tabPulseSinusOn[i]);
if (i != 100) Serial.printf(","); else Serial.printf("\n};\n");
if (i % 10 == 0) Serial.printf(" ");
if (i % 20 == 0 && i != 100) Serial.printf("\n ");
}
#endif
}
#endif // rebuild