Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When using the duration parameter of tone, the sound will be distorted #193

Open
qwqoffice opened this issue Apr 12, 2024 · 12 comments
Open

Comments

@qwqoffice
Copy link

I added the duration parameter to the tone function:
tone(Buzzer, 932, 150);
The sound sounds a bit strange.
But when I don't use pulseSensor.begin(), the sound is normal
What is the problem?

@biomurph
Copy link
Contributor

@qwqoffice
Please tell us what hardware you are using to read PulseSensor?
Also, what computer OS you are using and what version of Arduino IDE are you using?
Please share your code, so We can try to replicate your bug.
If you can make a quick video, which doesn't have to look good, just show the PulseSensor and record sound with the PulseSensor running and not running?

@qwqoffice
Copy link
Author

@qwqoffice Please tell us what hardware you are using to read PulseSensor? Also, what computer OS you are using and what version of Arduino IDE are you using? Please share your code, so We can try to replicate your bug. If you can make a quick video, which doesn't have to look good, just show the PulseSensor and record sound with the PulseSensor running and not running?

I am using Arduino UNO R3 board, with ATMEGA328P-PU, and a passive buzzer for tone.
Windows11, Arduino IDE Version: 2.3.2
here is my code:

#include <PulseSensorPlayground.h>
#define THRESHOLD 700

PulseSensorPlayground pulseSensor;
const int PULSE_INPUT = A3;
const int Buzzer = 9;

void setup() {
  pulseSensor.analogInput(PULSE_INPUT);
  pulseSensor.setThreshold(THRESHOLD);
  pulseSensor.begin();
}

void loop() {
  // Tone
  if (pulseSensor.sawStartOfBeat()) {
    tone(Buzzer, 932, 150);
  }
}

It sounds like there's some noise.

98ca6a1932454e17755544c6f173e427.mp4

And then, I deleted the initialization code for pulsesensor, and add tone code in loop, the sound is right, code here:

#include <PulseSensorPlayground.h>
#define THRESHOLD 700

PulseSensorPlayground pulseSensor;
const int PULSE_INPUT = A3;
const int Buzzer = 9;

void setup() {
}

void loop() {
  // Tone
  if (pulseSensor.sawStartOfBeat()) {
    tone(Buzzer, 932, 150);
  }

  tone(Buzzer, 932, 150);
  delay(500);
}
dcaafb5541257af0c34d95a3271cf2e2.mp4

I noticed a note in the PulseSensor_Speaker example:

NOTE: Do not set the optional duration of tone! That is blocking!

Is it related to this? I want the sound to play for a longer time and sound like a monitor in a hospital, just like the second video

@biomurph
Copy link
Contributor

@qwqoffice
Thank you for the short videos and the code you are using.
First, I would say that you should try the code that is in our example Speaker sketch.
It turns on the tone when pulseSensor.sawStartOfBeat() returns true, and uses the tone command without the duration parameter.
Then, it turns the tone off when pulseSensor.isInsideBeat() returns false using the noTone(pin) command.

Please try following the example that we have and see if that still gives you the noisy beep?

Second, it is clear that you are using a 'knock-off' PulseSensor. Our PulseSensor comes with a 24" cable with Red, Black, Purple wire colors. Also, our PulseSensor kit comes with a clear vinyl sticker to place on the front face to keep skin oils and sweat from interfering with the electronics.
Please purchase your hardware from the original makers of PulseSensor. We provide code support for free, and free hardware support only to legit customers of PulseSensor.

@qwqoffice
Copy link
Author

@biomurph
I tried the PulseSensor_Speaker example, due to the sound stopping too quickly, I moved my fingers away and closer to the sensor to extend the sound, result:

WeChat_20240416034445.mp4

As you said, my sensor is indeed a a 'knock-off' PulseSensor, but when I completely disconnected the sensor, the problem still exists, proving that the problem is not related to whether a original makers of PulseSensor is used or not. My following code calls a 10 second tone after the sensor initialization:

#include <PulseSensorPlayground.h>
#define THRESHOLD 700

PulseSensorPlayground pulseSensor;
const int PULSE_INPUT = A3;
const int Buzzer = 9;

void setup() {
  pulseSensor.analogInput(PULSE_INPUT);
  pulseSensor.setThreshold(THRESHOLD);
  pulseSensor.begin();
  tone(Buzzer, 932, 10000);
}

void loop() {
}

And It does not require the connection of sensor, the noise still exists:

902e186773c1bc8588ff866cb159fd49.mp4

We provide code support for free, and free hardware support only to legit customers of PulseSensor.

My English is weak and I don't understand the meaning. Does it mean that code support also requires the use of original makers of PulseSensor?
If you can provide code support, then please continue reading.

I also tried other frequencies for the tone, such as 2000, 3000, 4000. There is a significant difference in sound when calling and not calling the sensor initialization code.
I suspect that calling analogRead within a timer interrupt may be causing this issue. Because I also tried not using the PulseSensorPlayground library, directly creating a timer and using analogRead and tone in the callback, the sound becomes distorted. However, when analogRead and tone are called in the loop without using a timer, the sound does not distort.

using timer code:

#include <TimerOne.h>

void setup() {
  Timer1.initialize(20000);
  Timer1.attachInterrupt(timerTone);
  tone(9, 932, 10000);
}

void timerTone(void) {
  int Signal = analogRead(A3);
}

void loop() {
}
254e2c5efca2c65cc29e910ed4b0691b.mp4

not using timer, loop instead:

void setup() {
  tone(9, 932, 10000);
}

void loop() {
  int Signal = analogRead(A3);
}
db38874119c8344186b2fc3129d6ec58.mp4

@qwqoffice
Copy link
Author

@biomurph
Through the oscilloscope, I can see that the distorted sound waveform frequency is fluctuating,

6e46db7ac32500ad6e180811a160fccf.mp4

while the normal sound waveform frequency remains stable.

66189dca694acd14e157ab28ead6e28f.mp4

@biomurph
Copy link
Contributor

@qwqoffice
We will help you with your software issues, but if a problem arises from the 'clone' hardware we can't support because we don't know what that hardware is made of.

The tone() command in Arduino makes extensive use of hardware timer interrupts in order to generate the tone, as well as turning off the tone when the duration parameter us used. Producing the tone uses one timer, and setting the duration uses another. PulseSensor Playground library also uses interrupts to time the accurate sampling of the PulseSensor. The duration parameter timer use crashes with the PulseSensor timer use, so that is why there is distortion in the audible tone.

The easiest way to get around this issue is to turn on the tone when a heartbeat happens, and then turn off the tone some time later. In our example, we are using the sawStartOfBeat function to turn on the tone and the isInsideBeat function to turn off the tone. The isInsideBeat function will return true as long as the pulse signal wave is above the THRESHOLD value.

As you have noticed, the length of the tone is limited. Another way to set the time length of the tone without using the duration parameter would be to use a software timer. Here is an example of a software timer that you can use in your code.

Above the setup() declare some global variables:

unsigned long toneStartTime;
unsigned long toneDuration = 150;  // time in milliseconds taken from original post

In the loop:

if(pulseSensor.sawStartOfBeat()){
  tone(Buzzer, 932);  // start playing the tone
  toneStartTime = millis();  // set the time in milliseconds that the tone started
  // other stuff if you want
}

if(millis() - toneStartTime >= toneDuration){  // when the time is up,
  noTone(Buzzer);  // stop the tone
}

Please let us know if this software timer works to solve the problem?

@qwqoffice
Copy link
Author

@biomurph
Thank you for your software timer code, but I just tried it and the problem still exists. I posted a video above, which uses your PulseSensor_Speaker example without the duration parameter but I manually extended the tone to hear the noise clearly. I'm reposting the video using the PulseSensor_Speaker example here.

WeChat_20240416034445.mp4

@biomurph
Copy link
Contributor

@qwqoffice
I am out of my lab until Thursday this week. I will try to replicate your bug then.

Please provide a link to the components you are using?
The clone PulseSensor, the speaker, the arduino board?

@qwqoffice
Copy link
Author

qwqoffice commented Apr 18, 2024

@biomurph
Thank you.
Pulse Sensor: https://item.taobao.com/item.htm?id=532146320168
Speaker: https://item.taobao.com/item.htm?id=522573889254
And the Arduino board has been taken down.

@biomurph
Copy link
Contributor

@qwqoffice
Thanks for those links.

I have setup an Arduino UNO in my lab, with a speaker just like the tutrorial found here
https://pulsesensor.com/pages/pulse-sensor-speaker-tutorial

I can confirm that the beep sound does have a small amount of noise in it. I have not found the source of the noise, but I am going to do more tests to see where the bug is coming from.

@qwqoffice
Copy link
Author

@biomurph
My guess is that the noise is due to performance limitations of the ATmega328P on the Arduino UNO. If you have another MCU with higher performance, please test with it. Thanks for your work.
And I will use the STM32 series MCU for testing later and report the results to you.

biomurph added a commit that referenced this issue Aug 1, 2024
This fixes the noisy tone issue #193
Tone interrupt collides with our interrupt, noisy tone is the result, and likely bad BPM values.

In order to fix this problem and use tone() the Arduino core needs to be updated so that the tone library operates 'hands free' like the PWM library. Or, the PWM library needs to be updated to accept a frequency parameter to ensure a clean(er) note. There are some architectures upon which the Tone library might work: nRF52? ESP32?
@biomurph
Copy link
Contributor

biomurph commented Aug 1, 2024

@qwqoffice
I have been able to dig into the noise problem in our speaker example. After going down a deep deep hole, I discovered that the the Arduino tone() function starts up a hardware timer at a specific freqeuency, and initializes an interrupt. The problem is that the interrupt needs to be called in order to toggle the pin at frequency! So that interrupt is interfered with by the PulseSensor Playground interrupt! I imagine that our interrupts are messed with too.
I have created a better performing 'beep' by using analogWrite instead to create a square wave on the speaker pin.
It seems like on AVR, the frequency of analogWrite is 500Hz (about Bb). It's not a bad note, and it sounds clean. Also, our beat finder is not messed with!
The PulseSensor Speaker.ino example is updated in version 2.3.0

In order to fix this problem and use tone() the Arduino core needs to be updated so that the tone library operates 'hands free' like the PWM library. Or, the PWM library needs to be updated to accept a frequency parameter to ensure a clean(er) note. There are some architectures upon which the Tone library might work: nRF52? ESP32?

Please try the new example, and let us know if it works for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants