Avaraging pressure I2C readings
msiriwardena
Posts: 301
I am working respiratory system project.What I am trying to accomplish is to read the inhaled air pressure[of arespiratory circuit] and the expiratory pressure of the same circuit.I have connected the I2C - MS4515DO (Specs attached) - I have no problem reading the I2C data with the attaced code via PST.
The readings are -ve during inspiration and +ve during expiration(as it should) - so far I am doing Ok.
The problem I have is I have no idea how to avarage out the +ve readings, separately avaraging the -ve values.for instance a period of 30.sec or 1.0 min.
I am trying to display these results on a LCD display.
Any help how to avage these valus and to capture them in 2 separate variables so I can update the vales every 0.5 min or 1.0 min - as onging vales witout avaraging
is not helpful to manage the respiratory syatus.
Attahed are 1. Code - I have now
2. I2C- MS4515DO Data sheet.
3.The 2 objects - pasm_I2C driver and FullDuplex serial
Thanks,
Siri
The readings are -ve during inspiration and +ve during expiration(as it should) - so far I am doing Ok.
The problem I have is I have no idea how to avarage out the +ve readings, separately avaraging the -ve values.for instance a period of 30.sec or 1.0 min.
I am trying to display these results on a LCD display.
Any help how to avage these valus and to capture them in 2 separate variables so I can update the vales every 0.5 min or 1.0 min - as onging vales witout avaraging
is not helpful to manage the respiratory syatus.
Attahed are 1. Code - I have now
2. I2C- MS4515DO Data sheet.
3.The 2 objects - pasm_I2C driver and FullDuplex serial
Thanks,
Siri
pdf
401K
Comments
Either you store the data you need for calculating the average in a ring-buffer (one ring buffer for -ve and another for +ve). The ring-buffer is needed to subtract the oldest value before adding the newest value to a variable which always contains the sum. This way an average is calculated by 3 steps:
1. subtract oldest
2. add newest
3. divide sum by number of samples
This is the accurate way.
Have a look at this: http://forums.parallax.com/showthread.php/107474-Smoothing-out-Data?highlight=running%20average
This does not need any buffer but it is a bit less accurate.
Weighted_moving_average#Exponential_moving_average
Instead of averaging a set of previously measured samples, which all would have the same weight, one recursively gives more
recent samples more weight than older samples.
If I can explain it well:
Take the current value and multiply it by a factor, say 99%, then add the new value multiplied by 101% and divide the result by 2.
The result is a running average where the oldest sample about 100 ago has little weight compared to the more resent samples.
If someone has a better explanation of this please help me out.
This algorithm is quite fast even though there are 2 multiplies per iteration, (the divide by 2 is a right shift).
Duane J
The key though is automatically categorizing the results into two sets of values, +ve and -ve. Right?
A simplistic approach might find the average of all the values and group results > avg into the +ve category and < avg goes to -ve category. Then average these separately
http://jeremykun.com/2013/02/04/k-means-clustering-and-birth-rates/
Maybe it is me who does not understand the problem?!
So, please explain to me why you come up with clustering? Clustering in this special case is pretty easy to be done with a single if statement:
No need to work with general purpose clustering, which means that the code has to find the clusters itself. This is what we in germany call "Shooting with canons on pigeons" ;o)
Clustering is just a general case of the problem, was interesting to me so posted that url as a curiosity not meant as a solution. Just another case of what's going on in my head not making it to the keyboard.
Thanks for all the help.I will try the ring buffer as soon as I learn to create one ang populate it - the try the avaraging.
Siri
You say you want to average over fixed time intervals like 30 or 60 seconds. You accumulate samples and then at the end of the interval simply divide by the number samples taken, and then rezero the accumulators for the next round. To make regular intervals, use the synchronized form of waitcnt().
@ Tracy Allen - Thanks you very much for the code - I got it to work.
Thank you all trying to help me with this.
Regards,
Siri
I thought I had it all worked out but The avarage reading ia always '0'
I am attaching the code I am using - Please see where I amm going wrong.
Thanks,
Siri
P.S - I changed the Con to -" LOG_INT_MS = LOG_INTERVAL_SECONDS / 1000" which was " LOG_INT_MS=LOG_INTERVAL_SECONDS * 1000"
And the previous definition was correct at least according to the name: 1 second = 1000 milliseconds
Well .. in the end this
N_SAMPLES = LOG_INT_MS / SAMPLE_MS
is 0, which means that the repeat loop will not be executed.
I totally understand what you have pointed out but If I go back to what Tracy Allen had - I do not get any responses from the I2C at all.
I guess there is much more to it but I agree 1 error does not fix the problem with another error crrectly.
I figured out my mistake - I saw it as miliseconds = seconds /1000 - instead of how many miliseconds in the LOG_INTERVAL_SECONDS - I overlooked the INTERVAL part.
Thanks @ Magio
@Tracy - when I comment out the Repeat loop the readings are sent to the PST.
I hope you will help to remedy this dilema.
Thanks,
Siri
LOG_INT_MS = LOG_INTERVAL_SECONDS * 1000
to (big difference!)
LOG_INT_MS = LOG_INTERVAL_SECONDS / 1000
1000 milliseconds in one second.
You could simply track the local maximum pressure for each inhalation and exhalation period, and update the corresponding displayed value at the end of each period.
For example, on startup, display 0 for both +ve and -ve. Then wait for a transition between +ve and -ve and start tracking the local maximum. At the next transition, write out the latest peak to the display, zero the opposite tracking variable, and start tracking that local maximum. Repeat. You might want to set a small threshold for the transition so you don't get false triggers when there are no breaths, or to detect the end of the test.
The only variables you need in this case are two integers, one to track the -ve and one to track the +ve pressure peaks. By setting timestamps, you could also display the duration of the previous breath.
If you really want to get fancy you could then take the average of the previous maximums and minimums as well as the breath period lengths, and display the session average.
sampleCnts := clkfreq / 1000 * SAMPLE_MS
Then the sychronized waitcnt can be
waitcnt(time+= sampleCnts)
I had put SAMPLE_MS there instead of the time in cnt units.
To use the synchronized method, you have to have the initialization statement,
time := cnt ' set up synchronous sampling at interval
Without that, the program could be stuck for a minute aat a time while it waits to sync with cnt.
You could alternatively change delay in the inner repeat loop into a non-synced waitcnt.
waitcnt(sampleCnts + cnt)
Another important action is setting the accumulations to zero before the inner repeat loop:
positives := negatives := 0
Thus a separate accumulation for each interval.
PS--I like the suggestion from thebigmacd
readings show up on the PST.The latest code Iam dealing with your amenmends is attached.
I guess I need more help.
@ bigmacd - I like your idea to read the peak -ve and +ve pressures but my knowledge in programing require lot more to do what you are suggesting.
If you can show me how to do that - I will learn more for the future.(I am self a taught - electronic junkie)
Thanks ,
Siri
Alternatively, encapsulate that as a method and call it from the inner repeat
I suggest changing the waitcnt to non-sychronized, because the last program still did not have the necessary clock synchronization command. The non-synchronized form is less demanding.
I did all the changes as you wanted to but still it would not read the I2C.
I took out all the CON parameters and replced them with with simple number(500 in the code) and also a if statement on
the posive readings as it continue to read the negative values to that variable(positives) as I could not figure out why.
I am attaching the code I have now - If you have time please help figure this issue.
You can see the CON statements commentd out in the code.
Thanks again,
Siri
I don't have the pressure sensor you are using, but I modified your little program so that it substitutes random number for each pressure reading, and prints them out on the debug screen as it takes them. Then at the end it shows you how many positives and how many negatives it found and also shows you the averages. I set it back to 10 seconds of averaging at 1/2 second between samples taken, so it ends up with a managable 20 samples so you can verify that the math is correct.
Then you can substitute back in the method that acquires data from your pressure sensor, and change the overall interval back to 60 seconds and the sampling interval to ~100ms.
Does that help?
Thank you very much.
Regards,
Siri