I’m working on an Arduino Morse code decoder that interprets durations (positive/negative for tone on/off) into dots, dashes, and spaces. I add random noise to simulate real-world signal variance, but my comparison logic is failing to classify durations correctly — often printing "miss" even when durations should match expected ranges.
I have changed the shortest durations to be abs(durations[I]) instead of without and adjusted the noise so the max value is 1. But it does not add spaces
String abcMorse = ".- -... -.-.";
const int abcLength = 19;
int abcDurations[abcLength] = {420,-420,1260,-2940,1260,-420,420,-420,420,-420,420,-2940,1260,-420,420,-420,1260,-420,420};
void setup() {
Serial.begin(9600);
Serial.println("");
randomSeed(analogRead(0));
duration2morse(abcDurations,abcLength);
}
String duration2morse(int* durations, int length) {
const float Variability = 0.1;
int shortestDuration = 20000;
addNoise(durations, length, Variability);
for(int i=0; i < length; i++) {
if(abs(durations[i]) < shortestDuration) {
shortestDuration = abs(durations[i]);
}
}
for(int i=0; i < length; i++) {
if(durations[i] > shortestDuration * (1 - Variability) && durations[i] < shortestDuration * (1 + Variability)) {
Serial.print(".");
} else if(durations[i] > shortestDuration * (3 - Variability) && durations[i] < shortestDuration * (3 + Variability)) {
Serial.print("-");
} else if(abs(durations[i]) > shortestDuration * (3 - Variability) && abs(durations[i]) < shortestDuration * (3 + Variability)) {
Serial.print("/");
} else if(abs(durations[i]) > shortestDuration * (7 - Variability) && abs(durations[i]) < shortestDuration * (7 + Variability)) {
Serial.print(" ");
} else {
Serial.println("miss");
}
}
}
void addNoise(int* array, int length, float fraction) {
for(int i=0; i < length; i++) {
long variability = random(fraction * 100);
long plusMinus = random(0,2);
if(plusMinus == 0) {
array[i] = array[i] + variability ;
} else if(plusMinus == 1) {
array[i] = array[i] - variability;
}
}
}
Originally I did not have an abs() on meaning that it was setting the the shortest duration to a negative, causing errors further down. @IgorTandetnik pointed this out.
for(int i=0; i < length; i++) {
if(abs(durations[i]) < shortestDuration) {
shortestDuration = durations[i];
}
}
for(int i=0; i < length; i++) {
if(abs(durations[i]) < shortestDuration) {
shortestDuration = abs(durations[i]); <-- This part
}
}
The adding the abs() call, fixed most problems put I did not handle the remaining value properly. It would be more robust with using the median and doing the timing thresholds outside the for loop.
for(int i=0; i < length; i++) {
if(durations[i] > shortestDuration * (1 - Variability) && durations[i] < shortestDuration * (1 + Variability)) {
Serial.print(".");
} else if(durations[i] > shortestDuration * (3 - Variability) && durations[i] < shortestDuration * (3 + Variability)) {
Serial.print("-");
} else if(abs(durations[i]) > shortestDuration * (3 - Variability) && abs(durations[i]) < shortestDuration * (3 + Variability)) {
Serial.print("/");
} else if(abs(durations[i]) > shortestDuration * (7 - Variability) && abs(durations[i]) < shortestDuration * (7 + Variability)) {
Serial.print(" ");
} else { // <-- This does not handle the interspace between morse characters
Serial.println("miss");
}
}
So then I changed it, with the help of @IgorTandetnik. So that it properly handles the interspace between characters and so the variability scales well.
for(int i=0; i < length; i++) {
if(durations[i] > shortestDuration * (1 - Variability) && durations[i] < shortestDuration * (1 + Variability)) {
result += ".";
} else if(durations[i] > shortestDuration * (1 - Variability)*3 && durations[i] < shortestDuration * (1 + Variability)*3) {
result += "-";
} else if(abs(durations[i]) > shortestDuration * (1 - Variability) && abs(durations[i]) < shortestDuration * (1 + Variability)) {
; // <-- This does
} else if(abs(durations[i]) > shortestDuration * (1 - Variability)*3 && abs(durations[i]) < shortestDuration * (1 + Variability)*3) {
result += "/";
} else if(abs(durations[i]) > shortestDuration * (1 - Variability)*7 && abs(durations[i]) < shortestDuration * (1 + Variability)*7) {
result += " ";
} else {
Serial.println("Duration to morse Error");
}
}
I also had a slight timing issue with random, where originally I did random(0,1) which meant that it only returned 0 as it (max - 1) which returned 0, so changing to random(2) fixes this.
void addNoise(int* array, int length, float fraction) {
for(int i=0; i < length; i++) {
long variability = random(fraction * 100);
long plusMinus = random(0,1);
if(plusMinus == 0) {
array[i] = array[i] + variability ;
} else if(plusMinus == 1) {
array[i] = array[i] - variability;
}
}
}
void addNoise(int* array, int length, float fraction) {
for(int i=0; i < length; i++) {
long variability = random(fraction * 100);
long plusMinus = random(2);
if(plusMinus == 0) {
array[i] = array[i] + variability ;
} else if(plusMinus == 1) {
array[i] = array[i] - variability;
}
}
}