always a Sine wave

Hello

I am creating an EMG sensor from an INA128, I have been following a tutorial (link down below). when I connect the output from the INA128 to the Arduino, all I get is a sine wave when I reduce the reading speed of the sensor. I will attach my code that I am using to display the values of the sensor.

// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.print(0); // To freeze the lower limit
Serial.print(" ");
Serial.print(750); // To freeze the upper limit
Serial.print(" ");
Serial.println(sensorValue); // To send all three 'data' points to the plotter
delay(70); // delay in between reads for stability
}

Please enclose your code in code tags when posting it on the forum. Use the </> button in the top left of the post editor to insert the code tags.

building_Optimus_Prime:
when I connect the output from the INA128 to the Arduino, all I get is a sine wave when I reduce the reading speed of the sensor.

What were you expecting?

delay(70);

So you are sampling at roughly 14Hz. The highest frequency you will theoretically be able to detect will be at most half of that.

thank you for your help, so how would I go about making it so that only the change in muscle activity will show up?

I have followed the instructions on making it, it works but I am trying to 'remove the sine wave' from the graph so its flat line and then spikes with an input.

Is this sine wave 60hz? It's very, very likely that your sensor is picking up electrical noise.

According to this, you make can make a notch filter to reject 60Hz fairly easily.

165 microseconds is about 1/101 th of a single 60hz cycle, so we'll sample at that rate. Let's reject a bandwidth of (say) 10Hz.

I don't know if this works, but according to the book I think it might.

uint32_t prev_sample_us;

const uint32_t sample_rate_us = 165;
const double SAMPLE_RATE_Hz = 1000000.0 / sample_rate_us;
const double POWER_HUM_Hz = 60; // Here in Australia it's 50
const double BANDWIDTH_Hz = 10.0;

const double sample_F = POWER_HUM_Hz / SAMPLE_RATE_Hz;
const double sample_BW = BANDWIDTH_Hz /  SAMPLE_RATE_Hz;

double filter_samples[3];
double filter_output[3];
double filter_a[3];
double filter_b[3];

void setup() {
  double R = 1 - 3 * sample_BW;

  double cos2pif = Math.cos(2 * Math.PI * sample_F);

  double K = (1 - 2 * R * cos2pif + R * R) / (2 - 2 * cos2pif);

  filter_a[0] = 1 - K;
  filter_a[1] = 2 * (K-R) * cos2pif;
  filter_a[2] = -R * R;
  // there is no filter_b[0]
  filter_b[1] = 2 * R * cos2pif;
  filter_b[2] = - R * R;

  prev_sample_us = micros();
}

void loop() {
  if(micros() - prev_sample_us >= sample_rate_us) {
    take_a_sample();
    prev_sample_us += sample_rate_us;
  }
}
 
void take_a_sample() {
  // move everythgn down by one. Yeah, a ring buffer might be faster.
  memcpy(filter_samples+1, filter_samples, sizeof(filter_samples)-sizeof(filter_samples[0]));  
  memcpy(filter_output+1, filter_output, sizeof(filter_output)-sizeof(filter_output[0]));  

  filter_samples[0] = analogRead(A0); // for instance
  
  filter_output[0] =
    filter_samples[0] * filter_a[0]
    + filter_samples[1] * filter_a[1]
    + filter_samples[2] * filter_a[2]
    + filter_output[1] * filter_b[1]
    + filter_output[2] * filter_b[2];
    

}

thank you so much for your help!
I am currently lost and unsure of how to make this code run, comes up with 'math was not declared in this scope'
I am currently using 50Hz instead of 60Hz as well
Thanks
Mitchell

building_Optimus_Prime:
thank you so much for your help!
I am currently lost and unsure of how to make this code run, comes up with 'math was not declared in this scope'
I am currently using 50Hz instead of 60Hz as well

I wrote this at the keyboard without compiling it. For Arduino programming, turns out you don't need the 'Math.'

  double cos2pif = cos(2 * PI * sample_F);

Compiles with that fix … but that's not the same as saying that it works :slight_smile:

thank you so much for your help, I will have a look at it soon.

building_Optimus_Prime:
thank you so much for your help, I will have a look at it soon.

I'd really like to know if it actually works and if this code really does implement a notch filter at the appropriate frequency. I had a read through the book I linked to, but a lot of the mathematics strains the limits of my ability to do calculus. The code I gave is a correct implementation, I hope, of a recipe that I really only half-understand.

If it works, I think I'll do up a page in the playground showcasing it.

Could you let me know in a PM? Although I am watching this thread anyway.

I uploaded your code to my Arduino and ran it without my sensor connected and it was a flat signal which is amazing. I then turned it off and got the sensor to plug in and now it doesn't want to work at all, with or without the sensor. I didn't do anything other than turn it off. I have even tried it on another Arduino and nothing. When I go to the Serial Plotter, it doesn't show anything now.

building_Optimus_Prime:
I uploaded your code to my Arduino and ran it without my sensor connected and it was a flat signal which is amazing. I then turned it off and got the sensor to plug in and now it doesn't want to work at all, with or without the sensor. I didn't do anything other than turn it off. I have even tried it on another Arduino and nothing. When I go to the Serial Plotter, it doesn't show anything now.

That's a bit of a shame. You are plotting the value of [nobbc]filter_output[0][/nobbc] ? If you just grab a wire and connect your analog input to ground or to vcc, does the detected signal jump like it should? What if you connect the op-amp ground or peg its input?

Do you get the sine wave back if you remove my code? If not, something is fried. How are you powering this op-amp? I'd imagine you power it off 5v (NOT Vin) and likewise connect pin 5 on the IC to 5v to give it its reference value (not 100% sure whether Vref on the arduino is an input or an output). You're not jamming 9v into an analog input, I hope.

Do you get the sinewave back if you just plot the value of filter_samples[0]? This is supposed to be the input and should just echo the value of analog input 0. If there's no sine wave there, but it works without my code, then maybe the gear in there that controls the sampling rate is to blame.

Another possibility might be to fool about with the bandwidth constant in my code. I set it to 10Hz - maybe another value would work.

If it now doesn't work with or without the sensor … I'm not sure what might be going on. It might involve electronics, which is not really my thing. Having a look at that circuit in the link, they hav a cap between pins 1 and 8, which is pretty weird as the data sheet says to use a resistor INA128 datasheet | TI.com . The instructable says that he cap acts as a high-pass filter. I suppose that makes some sense … but a cap will do damn strange things.

The sampling rate is 165us, but if you are printing out something after every sample, well - that's going to take far more time than 165us. What you probably need to do is accumulate the average value of the sample and print it out every 10th of a second or so, or the average over time of the difference between the filtered value and the average value. Or something. On the other hand, maybe you are just putting the filtered sample out to another analog output, so time isn't really a thing. Perhaps reduce the sampling rate, and see if you start to see something.

I mean - there's a lot of things to experiment with before just giving up on your project.

Yeah I was plotting ‘filter_output[0]’
My Arduino still works, I did your test and it drops down to ‘0’ when connected to ground and jumps up when connected to Vcc. I connected the Ref pin of the INA128 to the Arduino and it just gave more of a square wave and didn’t read any muscle movements.

When I use my code, it goes back to the sine wave but it detects the muscle movements as well.
I am using a battery pack to get 6V as an input and then I’m using a TC1044S to give a negative voltage. When I used the Arduino 5V, I got a funny result but I will have to give it another go.
When I tried ‘filter_samples[0]’ it didn’t work either, I tried to serial monitor and it gave “⸮⸮⸮ ⸮⸮⸮X⸮r⸮⸮0” and I get a similar result when I use ‘filter_output[0]’.
It is almost as if the Serial Plotter doesn’t want to start, it’s just an empty screen. I even added
Serial.print(200);
Serial.print(" ");
So that I could see if it was actually running but not displaying anything.

I will play around with the bandwidth to see if I can get something to work for me.
I have been using a capacitator just because it was the bloke has used and I did question the datasheet as well. I am now using a gain of 1 but will keep trialling it with different values along with different bandwidths and different sample rates.
I have even added in the 0.1uF capacitators at pins 4 and 7, going off the datasheet.

I am thinking about using the AD8648 which is what the MyoWare muscle sensor has used, if I can't get the INA128 to work.
http://www.analog.com/media/en/technical-documentation/data-sheets/AD620.pdf

Thank you ever so much for your help.

building_Optimus_Prime:
When I use my code, it goes back to the sine wave but it detects the muscle movements as well.

Well, that's pretty conclusive.

It's a bit of a pity that it didn't work "out of the box". Oh well. You could try making a basic low-pass filter

filteredValue = .75 * filteredValue + .25 * newReading

and subtracting that from the readings to get the higer frequency components. That's assuming that the muscle sensing stuff is higher frequency than your sine wave.

Hang on … do you really have a "delay(70)" in your code???? What happens if you alter it a little?

I will have a look into using the low pass-filter today.

In my code I was using "delay(70)", but I did try a few different values from no delay all the way to 250 and I found that 70 was the best.

I Might have to find another way to detect minute muscle movement for my project (that isn't a bought sensor).

I am just watching a video on YouTube that is doing a similar task, only he has made it so that it just turns on an LED instead of going to an Arduino. I am guessing he would still need to remove the sine wave as it would trigger the LEG each cycle of the wave. The guy has used an instrumentation amp that amplifies it by 10 and then he uses two chips to make a bandpass and then finally he uses an amplifier.

building_Optimus_Prime:
In my code I was using "delay(70)", but I did try a few different values from no delay all the way to 250 and I found that 70 was the best.

Riiiight. Ok, I had misunderstood where you are coming from.

All of the gear in the notch filter that calculates constants is wrong.

  1. Get rid of my gear that does timing. Just call take_a_sample each time you loop.

  2. Count how many samples there are from peak-to-peak of your sine wave. That is, if you are spitting out line of output each sample, how many samples are there from one peak to the same peak (in the same direction)? That's a full wavelength.

Then,

// the frequency is the frequency being supressed *IN TERMS OF THE SAMPLE RATE *
// it must be between 0 and .5
const double sample_F = 1.0 / /* number of samples in a full wavelength goes here */;

// the bandwidth must be between 0 and .5.
// if you make the bandwith tighter (smaller), it will potentially fail to filter out the 50Hz noise
// if you make the badwidth looser (larger), it will potentially suppress the muscle data
const double sample_BW = 0.05;

I feel like you have confused me with this post, I am a little unsure of how to edit the code sorry.

but I spoke to the people down at JayCar and they said it might be the Arduino itself or the mains that is making the noise. Their advice was try and ground it better which I am going to be doing that today.