Tuesday, 9 May 2017

Graphing the Data from the Venturi Tube

In the previous post I wrote about how I 3D printed a venturi tube and updated the code with new constant values.  At the end of the post I was looking for a way to display the data graphically live.

I think I have managed it!  The previous post for those that are interested is here:

http://langster1980.blogspot.co.uk/2017/05/making-venturi-tube.html

I had been researching Python scripting and whilst this is possible I don't have the time, patience or inclination to learn another programming language - there is only so much room in my head for information!  Perhaps I will learn Python in the future and being aware of it and it's function will probably serve me well.

I was browsing through you tube and google looking for programs which graph serial data automatically from comma separated values.  I specifically made sure that the data sent out to the serial port from the arduino was comma separated...it makes it easy to import into a spreadsheet program and graph.  I would like to be able to do that real time as well.

In my searching I found this video:

https://youtu.be/yYyW16FYqE0

It describes a java applet which has been written to graph serial data directly from the arduino - just what I was looking for!  The video itself explains how to use it quite simply so I won't bother. Sufficed to say all one needs to do is select the appropriate COM port and baud rate and then complete the form with the required information and units and the graph will be displayed.

The java applet can be downloaded from here:

http://farrellf.com/TelemetryViewer/T...

If you haven't got Java installed that will be needed also:

https://java.com/en/download/

Once everything is installed I would watch the video and learn how to use the applet.  The help button is quite useful! Here are the results:


Here is another screenshot:


Which is very close to the example image given when this project was first specified:

Displaying image.png

As this part of the project is almost complete, I'm going to move on to the next section which was to measure the pressure output from the ventilator using one of my pressure sensor breakout boards - not too hard to add hopefully. After that it's develop a EMG measurement circuit.

Along the way I think it might be useful to add a microSD card to log the data received along with a real time clock and finally use bluetooth communications to provide wireless serial communications. It's also time to consider powering the system - I'm looking at using 18650 lithium cells and a suitable charging circuit with protection.  After than design an enclosure and add some LEDS to show function and this project can be marked complete!  Not too far now!!!!

Take care always - Langster!

Monday, 8 May 2017

Making a Venturi Tube

In order to perform a little more testing on the Spirometer device I have designed a venturi tube which can be 3D printed.  It is possibly the most ugly and square shaped device ever to be designed but it will 3D print perfectly and because I designed it - I know the internal dimensions.  It was designed in the free version of google sketchup and assuming it works well I will share the design files.

The previous post for those that are interested is below:

http://langster1980.blogspot.co.uk/2017/04/create-spirometer-using-msp7002dp.html

Knowing the internal dimensions means the calculations performed will be more correct which in theory means the accuracy of the measurements will be correct.

I'm not going to go into how I designed the venturi tube - there are plenty of diagrams available.

Here is a picture of how the tube will look when printed:

Solid Version Venturi Tube
See Through Diagram of the Venturi Tube with dimensions
I used this and many other sites as a reference on how to make a venturi tube:




I'm going to 3D print this tomorrow but in the mean time lets repeat the calculations to calculate the areas of the first and second sections (The internal tube sections).

In order to make the measurements using the arduino we need the areas calculating for A1 and A2. The formula we are applying in total is:


The dimensions of A1 can be calculated using:





or


Next A2 can be calculated in the same way:






or



Lets now attempt to calculate Q, the Volumetric flow rate.  Lets use a value of 320 for P1 and 200 for P2:



Simplifying gives:





And for the second thinner section:



Simplifying gives:





Both values come in almost exactly the same - close enough for my requirements.  Good to know the mathematics works out!

From that as before the velocity of flow can then be calculated using:







Just for completeness lets use the value for A2 also:







We can now check all is correct as:





This actually computes to:



Which is really good - as we set the values for P1 and P2 to be 320 and 200 Pa to begin with!  The really small error is probably due to rounding errors creeping in with my calculations.  Not of significant importance in this case.

Here is a picture of the tube printed and displayed connected to the mask:

The venturi tube connected to a face mask

We can now use the values for A1 and A2 in the arduino code with the newly printed venturi tube. Hopefully the accuracy will be much improved.

Here is the new code - same as before but updated with the new constants for the venturi tube.

 // MPX7002DP Test Code with conversion   
 // to volumetric flow rate and velocity   
 // of flow  
 //  
 // A.Lang - 2017  
   
 // This code exercises the MPX7002DP  
 // Pressure sensor connected to A0  
   
   
 #include <Average.h>  
   
 Average<float> averageValue(100);  
   
   
 //variables  
   
 int sampleNumber = 0;      // variable to store the sample number   
 int sensorPin = A0;       // select the input pin for the Pressure Sensor  
 int sensorValue = 0;      // variable to store the Raw Data value coming from the sensor  
   
 float averageInitialValue = 0; // variable to store the average inital value  
   
 float diffPressure = 0;     // variable to store converted kPa value   
 float volumetricFlow = 0;    // variable to store volumetric flow rate value   
 float velocityFlow = 0;     // variable to store velocity of flow value   
 float offset = 0;        // variable to store offset differential pressure  
   
 //constants - these will not change  
 const float tubeArea1 = 0.01592994; // area of venturi tube first section 0.003095 0.01592994  
 const float tubeArea2 = 0.0042417; // area of venturi tube second section  
 const float airDensity = 1.225;  
   
 void setup() {  
  // start serial port at 9600 bps and wait for port to open:  
  Serial.begin(9600);  
   
  pinMode(sensorPin, INPUT);  // Pressure sensor is on Analogue pin 0  
   
  Serial.flush();  
  //Serial.println();  
   
  //Header for CSV data  
    
  Serial.print("Sample Number,  Raw Sensor Value, Differential Pressure,  Volumetric Flow Rate,  Velocity of Flow,");  
  Serial.println();  
  Serial.print("       ,     bits    ,      Pa     ,    m^3/second    ,     m/s    ,");  
  Serial.println();  
   
  // get initial sensor value  
   for (int i = 0; i < 100; i++) {  
       
     // read the value from the sensor:   
     sensorValue = analogRead(sensorPin);   
       
     //push sensor values to averageValue object  
     averageValue.push(sensorValue);  
   }  
   
   for (int i = 0; i < 100; i++)   
   {  
    // get average Sensor values  
    averageValue.get(i);  
      
   }  
   
   //calculate mean average sensor and store it  
   averageInitialValue = averageValue.mean();   
   
   Serial.print("Average Initial Value :");  
   Serial.print(averageInitialValue);  
   Serial.println();  
   
 }  
   
 void loop() {  
   
     
   //read the value from the sensor:   
   sensorValue = analogRead(sensorPin);   
     
   // initial value   
   sensorValue = sensorValue - (int)averageInitialValue;  
    
   // increment sample counter   
   sampleNumber++;   
   
  // map the Raw data to kPa  
  diffPressure = map(sensorValue, 0, 1023, 0, 4000);   
   
  if (sensorValue >= 0)  
    {  
     //calculate volumetric flow rate for Exhalation  
     volumetricFlow = tubeArea1 * (sqrt((2/airDensity) * (diffPressure/(sq(tubeArea1/tubeArea2)-1))));  
   
     //calculate velocity of flow   
     velocityFlow = volumetricFlow / tubeArea1;  
    }  
  // convert reading to a positive value  
  else if (sensorValue <= 0) {  
   diffPressure = diffPressure *-1;  
      
    //calculate volumetric flow rate for Inhalation  
    volumetricFlow = tubeArea2 * (sqrt((2/airDensity) * (diffPressure/(1-sq(tubeArea2/tubeArea1)))));  
      
    //calculate velocity of flow   
    velocityFlow = volumetricFlow / tubeArea2;  
  }  
    
  // Print the results as comma separated values for easier processing  
  // in a spreadsheet program  
   
  Serial.print(sampleNumber);  
  Serial.print(",");  
  Serial.print(sensorValue);  
  Serial.print(",");  
  Serial.print(diffPressure);  
  Serial.print(",");  
  Serial.print(volumetricFlow);  
  Serial.print(",");  
  Serial.print(velocityFlow);  
  Serial.print(",");  
  Serial.println();  
    
  // wait 100 milliseconds before the next loop  
  // for the analog-to-digital converter and  
  // pressure sensor to settle after the last reading:  
  delay(100);   
    
 }  

I have added to the setup function to provide an initial average.  This zeros the sensorValue so that there are no issues with negative numbers during the calculation stage.  It is always a good idea to zero things before performing calculations.  I have also reduced the number of variables needed.

If people wish to use this code they will need to download the Average.H library from here:

https://github.com/MajenkoLibraries/Average

The library has been kindly provided by Majenko Technologies and appears to work very well.  It was much quicker to use this library than to write my own function to calculate the average!

Here is the output from the new arduino serial plotter - which is very cool!


Blue trace: Raw sensor Value
Red trace: Differential pressure value, (Positive = Exhaling, Negative = Inhaling)
Green trace: Volumetric Flow
Orange trace: Velocity of Flow

If I could adjust the scales and print each graph on a separate line I'd be half way to displaying the data as requested!

I'm going to look at python scripting to achieve this functionality as I believe it will work best.

That is all for now people - take care always!

Saturday, 22 April 2017

Create a Spirometer using the MSP7002DP Differential Pressure Sensor

The previous post discussed how to use the MSP7002DP differential pressure sensor:

Using MPX7002DP differentia pressure sensor

This post will discuss how to take that sensor and use it to make a spirometer - a measurement instrument used to measure air inhalation and exhalation.  Doctors and medical professionals use a spirometer to assess a person's respiratory function.  The information is then used to provide treatment for such conditions such as Asthma, Emphysema, chronic bronchitis etc.

If more information about Spirometry is required please check out the links below:

https://www.asthmafoundation.org.nz/your-health/living-with-copd/what-is-spirometry

https://patient.info/health/spirometry-leaflet

https://en.wikipedia.org/wiki/Spirometer

In order to make a spirometer we will need a special kind of tube known as a Pnuemotachograph, A Pneumotachograph is a tube with two distinct sections separated by a known restrictive plate.  I didn't make my own Pneumotachograph, as helpfully, a friend who is also a doctor, supplied me with one! If people do need to make their own tube they could be easily constructed or 3D printed.

A medical pneumotacograph
The two pipes shown will be attached to the MSP7002DP Differential Pressure sensor.  When someone breathes in and out through the tube a difference in pressure will be measured due to the difference in pressure in either tube and this will be passed to the microcontroller and displayed.  At the moment the results would be displayed in Pascals (Pa).  But in order to measure lung function this value needs to be converted to litres / minute.

The theory behind all this was first discovered by a very clever Swiss gentlemen called Daniel Bernoulli:

https://en.wikipedia.org/wiki/Daniel_Bernoulli

Amongst other work Mr Bernoulli discovered that one could calculate the rate at which fluids and gases flow. He noticed that if the pressure applied to a fluid or gas decreases then at the same time the speed or velocity of the fluid or gas would increase.  This has become known as the 'Bernoulli Principle' and is used considerably in science and engineering - particularly in aerodynamics.

We are going to apply Bernoulli's principle to calculate the velocity of the air flow (volumetric Flow Rate) when someone breathes into the pneumotachograph and from that calculate volumetric flow which is measured in litres / second or litres per minute.

https://www.grc.nasa.gov/www/k-12/airplane/bern.html

The mathematics is quite complicated and I have never been particularly good at mathematics...Here is the theory and the associated mathematics:

In a pneumotachograph tube the downstream pressure after the obstruction (a thin plate like flap in the spherical section) will be lower than the upstream pressure in the first part of the tube. To understand pneumotachograph tubes it is necessary to explore Bernoulli's equation.  If it can be assumed that a fluid flows in a horizontal manner (neglecting the minor elevation difference between the measuring points) then Bernoulli's equation can be expressed as:



where:

P1 is the pressure in first part of tube and P2 is the pressure in the second part of the tube.

ρ = density of air at standard temperature and pressure in kg/m3

v = flow velocity in metres / second

Again making an assumption that the air flows in each section without restriction - the continuity equation can be expressed as:



where

Q = flow rate in metres / second

A1 = cross sectional area of first part of the tube in m3
A2 = cross sectional area of the second part of the tube in m3

Combining (1) and (2), gives the equation needed:



The above equation is technically an application of the Venturi Effect.  Both Venturi and Bernoulli worked on similar experiments and could be equally credited.  More information on the Venturi Effect here:

https://en.wikipedia.org/wiki/Venturi_effect

If we apply the equation to the Pneumotachograph tube dimensions and the differential pressure measured it should be possible to calculate the flow rate (Q) and from that we can then re-arrange equation 2 and calculate V1 or V2.



From this information we can write some firmware to calculate the velocity of flow directly from the differential pressure measurement made by the MSP7002DP sensor.

My one concern with this method is that I have no information concerning the internal dimensions of the pneumotach tube provided.  I have measured it as best as I can and I have also performed some simple experiments but I suspect the accuracy will be slightly compromised because I don't have that information.  I think this will work but as I'm striving for accuracy it would be better to have the datasheet.  I may well make my own to compare to it - that way I have the mechanical data and I can share how to make a pneumotach tube with everyone else...which might be useful...

Anyway having measured the length and diameter of the tube section, the cross sectional area can easily be calculated.  The middle section of the device is (sort of) conical and therefore I need to take account of that extra area.  The area of a cone can be calculated with:




I'm guessing at the radius of the conical section as I have no way of accurately measuring it.

Lets say that the cone radius is 12 mm

Lets say that the cone height is 24 mm

The area of the full cone is:





but....because the shape is not a full cone...it's top section has been removed it's a type of shape known as a conical frustum and the area of a conical frustum is calculated by:









Next the tube section must be calculated.  The formula for that is:







If we now add those two figures together we have the area of the first section of the pneumotach tube.





which is 0.00309579817057 m2

The areas of each section of the tube are the same so A1 = A2.

The fluid density of air is 1.225 kg / cubed metre, lets select P1 as 320 Pa and P2 as 200 Pa and then lets plug all of the values into the first formula and find the volumetric flow rate:











Lets now apply the velocity of flow formula:







Well...that was a considerable amount of work!  I'm not convinced this is quite correct.  I would be more comfortable with applying known values for the areas for the different sections of the pneumotach tube.  Incorrect values for area will affect the accuracy...

Anyway...with the mathematics sorted we can now write a program which performs the conversions for us.

Note m/s can be converted to litres / second by multiplying by 1000.

Here is the arduino code to read in the differential pressure measurement and then calculate the volumetric flow rate and the velocity of flow:

   
 // MPX7002DP Test Code with conversion   
 // to volumetric flow rate and velocity   
 // of flow  
 //  
 // A.Lang - 2017  
   
 // This code exercises the MPX7002DP  
 // Pressure sensor connected to A0  
   
 //variables  
   
 int sampleNumber = 0; // variable to store the sample number   
 int sensorPin = A0; // select the input pin for the Pressure Sensor  
 int sensorValue = 0; // variable to store the Raw Data value coming from the sensor  
 float diffPressure = 0; // variable to store converted kPa value   
 float volumetricFlowExhale = 0; // variable to store volumetric flow rate value when Exhaling  
 float volumetricFlowInhale = 0; // variable to store volumetric flow rate value when Inhaling  
 float velocityFlowExhale = 0; // variable to store velocity of flow value when Exhaling  
 float velocityFlowInhale = 0; // variable to store velocity of flow value when Inhaling  
 float offset = 0; // variable to store offset differential pressure  
   
 //constants - these will not change  
 const float tubeArea1 = 0.003095; // area of pneumotach first section  
 const float tubeArea2 = 0.003094; // area of pneumotach second section  
 const float airDensity = 1.225;  
   
 void setup() {  
  // start serial port at 9600 bps and wait for port to open:  
  Serial.begin(9600);  
   
  pinMode(sensorPin, INPUT); // Pressure sensor is on Analogue pin 0  
   
  Serial.flush();  
  Serial.println();  
   
  //Header for CSV data  
   
  Serial.print("Sample Number,Differential Pressure, Volumetric Flow Rate (Exhale), Volumetric Flow Rate (Inhale), Velocity of Flow Exhale, Velocity of Flow Inhale,");  
  Serial.println();  
  Serial.print("       ,     Pa     ,   m^3/second       ,     m^3/second      ,      m/s     ,      m/s     ,");  
  Serial.println();  
   
 }  
   
 void loop() {  
   
  // read the value from the sensor:   
  sensorValue = analogRead(sensorPin);  
   
  // initial value   
  sensorValue = sensorValue - 48;  
   
  // increment sample counter   
  sampleNumber++;  
   
  // map the Raw data to kPa  
  diffPressure = map(sensorValue, 0, 1023, -2000, 2000);  
   
  // convert reading to a positive value  
  if (diffPressure < 0) {  
   diffPressure = diffPressure * -1;  
   
   //calculate volumetric flow rate for Inhalation  
   volumetricFlowInhale = tubeArea2 * (sqrt((2 / airDensity) * (diffPressure / (1 - sq(tubeArea2 / tubeArea1)))));  
   
   //calculate velocity of flow   
   velocityFlowInhale = volumetricFlowInhale / tubeArea2;  
  } else {  
   //calculate volumetric flow rate for Exhalation  
   volumetricFlowExhale = tubeArea1 * (sqrt((2 / airDensity) * (diffPressure / (sq(tubeArea1 / tubeArea2) - 1))));  
   
   //calculate velocity of flow   
   velocityFlowExhale = volumetricFlowExhale / tubeArea1;  
  }  
   
  // Print the results as comma separated values for easier processing  
  // in a spreadsheet program  
   
  Serial.print(sampleNumber);  
  Serial.print(",");  
  Serial.print(diffPressure);  
  Serial.print(",");  
  Serial.print(volumetricFlowExhale);  
  Serial.print(",");  
  Serial.print(volumetricFlowInhale);  
  Serial.print(",");  
  Serial.print(velocityFlowExhale);  
  Serial.print(",");  
  Serial.print(velocityFlowInhale);  
  Serial.print(",");  
  Serial.println();  
   
  // wait 100 milliseconds before the next loop  
  // for the analog-to-digital converter and  
  // pressure sensor to settle after the last reading:  
  delay(100);  
   
 }  

It is a little more complicated than the previous code but here is essentially how it works:
  • All the variables needed are declared, the variable names should explain what their purpose is.
  • All the constants we need are declared, again their names should explain their purpose.
  • The setup function is called next.  It initialises the serial monitor and declares the sensorInput variable as an input.  Next it writes some messages to the serial monitor to create a header for a comma separated value file - an easy way to copy and paste the data from the serial monitor into a text file so it can then be important into a spreadsheet program for graphing.  More on this later.
  • The loop function is called next.  The sample count is incremented by one every time the loop runs. This is for graphing purposes - we take a sample every 100 ms.  Next the differential pressure sensor is read and the results are converted to Pascals.  If the result is negative (someone is inhaling) then the value taken is converted to a positive number - if we don't do this the calculations will not be correct - it is not possible to take the square root of a negative number (Unless the quantity is complex - not relevant here!)
  • Next volumetric flow rate is calculated for both exhalation and inhalation after that the velocity of flow rates are calculated and then all these results are sent to the serial monitor.  Then the program loops back to the start.
When the code has been uploaded to the arduino the serial monitor should provide some data.  If the pneumotach tubes are correctly connected to the MXP7002 Differential pressure sensor then when one breathes in and out of the pneumotach tube - data should be received!


If one were to copy and paste this data into an ascii text editor and save that file as a CSV extension then the data can be imported into a Spreadsheet or graphing program.  Here are graphs of some of the data taken:


That's all for now.  The next post will deal with graphing the data live to a rolling display. - Take care people - Alex!