VARIOMETER using GY63/MS5611 barometer

Benjie

Senior Member
I'm back home. Here is the Pl variance using this code:
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

; Uncomment the line below to use SERTXD output
'#Define USE_SERTXD

Symbol Pl = w1 : Symbol Pl.msb = b3 : Symbol Pl.lsb = b2
Symbol Ph = w2 : Symbol Ph.msb = b5 : Symbol Ph.lsb = b6

Symbol Xl = w3
Symbol Xh = w4

Symbol Dl = w5
Symbol D_MID= 5000
Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00
symbol Diff=300
Symbol K           = 1
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:


      Do
    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( Ph.lsb, Pl.msb, Pl.lsb) : Ph.msb = 0
    Pl=Pl - 10000

    Select Case Pl
        Case > Xl
          w0 = Pl - Xl / K : w6=0

        Case < Xl
          w6 = Xl - Pl / K : w0=0

      End Select
      
       SerTxd( #Pl,TAB, #Xl, TAB ,#w0, TAB,#w6,cr,lf)

    Xl = Pl
    Xh = Ph
  Loop
Noise needs to be addressed.
 

Attachments

Benjie

Senior Member
Back home, here is the list of readings using this code:
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

; Uncomment the line below to use SERTXD output
'#Define USE_SERTXD

Symbol Pl = w1 : Symbol Pl.msb = b3 : Symbol Pl.lsb = b2
Symbol Ph = w2 : Symbol Ph.msb = b5 : Symbol Ph.lsb = b6

Symbol Xl = w3
Symbol Xh = w4

Symbol Dl = w5
Symbol D_MID= 5000
Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00
symbol Diff=300
Symbol K           = 1
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:


      Do
    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( Ph.lsb, Pl.msb, Pl.lsb) : Ph.msb = 0
    Pl=Pl - 10000

    Select Case Pl
        Case > Xl
          w0 = Pl - Xl / K : w6=0

        Case < Xl
          w6 = Xl - Pl / K : w0=0

      End Select
      
       SerTxd( #Pl,TAB, #Xl, TAB ,#w0, TAB,#w6,cr,lf)

    Xl = Pl
    Xh = Ph
  Loop
 

Attachments

Benjie

Senior Member
I begin to consider that the sensor I have is somewhat faulty because moving it up and down by 1 meter does not exhibit a change different than a drift; in any case there is no visible difference on the reading which can be attributed to the heigh change.
Hope a friend of mine has another unit to test or I will purchase a second one.
 

Benjie

Senior Member
Let's make this consideration:
Pressure variation for 10 meter change in altitude is about 1.325mb.
MS5611 resolution or 1 bit is 0.012 mb.
10 meter altitude change will cause 1.325/0.012= 110.
This implies that the Pl.lsb should not be fouling around by more than a value of 10.
Actually it moves by more than 200.
Something is seriously wrong!
 

Benjie

Senior Member
Probably I found the problem in the sensor commands (HI2cout).
Now I face another problem: using the code below, the sertxd command shows a Ph value of 34560 but the Xl value is 34787. How does it happen since the last command line is Xl=Pl ?
Can someone spot the problem?
Thanks.
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

Symbol Pl = w1 : Symbol Pl.msb = b3 : Symbol Pl.lsb = b2
Symbol Ph = w2 : Symbol Ph.msb = b5 : Symbol Ph.lsb = b6
Symbol Xl = w3  : Symbol Xl.msb = b7  : Symbol  Xl.lsb = b8
Symbol Dl = w4  : Symbol Dl.msb = b9  : Symbol  Dl.lsb = b10
Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00
Symbol D_MID       = 5000
Symbol D_RANGE     =  100
Symbol D_MIN       = D_MID - D_RANGE
Symbol D_MAX       = D_MID + D_RANGE
Symbol K = 1
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:

do

    HI2cOut ( CMD_D1_4096 )
        Pause 10
    HI2cOut ( CMD_ADC )
        Pause 10

    HI2cIn ( Ph.msb, Ph.lsb, Pl.msb, Pl.lsb) : Pl.lsb= 0


  SerTxd(#Ph,"  ",#Xl,cr,lf  )
  pause 100
#rem
  Select Case Ph
  case > Xl
      Xl = Ph - Xl / K
     Dl= Ph+ Xl Max 1
     If Dl>=1 then sound 4,(120,20): endif
  Case < Xl
      Xl = Xl - Ph / K
     Dl= Xl - Ph Min 1
     if Dl<=1 then sound 4,(80,20):endif
  End Select
  #endrem
  
Xl=Ph  

 Loop
 

hippy

Technical Support
Staff member
MS5611 resolution or 1 bit is 0.012 mb.
I am not convinced it is, that "resolution" and "1 bit" value are in fact the same thing.

Look at the "ADC-value D1 vs Pressure" graph in the datasheet. That appears to be linear, and from points where we get convenient intersections ...

( Edited:: Numbers below corrected )

800 mbar = 7000000
300 mbar = 5000000 (ish)

A change of 500 mbar equates to a change of around 2000000 in sensor reading.

So a 1-bit sensor reading change equates to an mbar change of 500/2000000, that's 0.00025 mbar, not 0.012 mbar. There is a 50-fold difference.

Probably I found the problem in the sensor commands (HI2cout).
How so ?

I would venture that any difference you are seeing is down to having changed from making the 24-bit sensor reading lsb aligned in the 32-bit Ph:Pl to now making it msb aligned in Ph:Pl.

using the code below, the sertxd command shows a Ph value of 34560 but the Xl value is 34787. How does it happen since the last command line is Xl=Pl ?
Because you don't have "Xl=Pl", you have "Xl=Ph".
 
Last edited:

Benjie

Senior Member
I cannot understand: I need to hold the value of Ph for 100 ms, store it in a new word variable Xl and compare it with the next reading of Ph. Why does Xl change its value from the one given at the end of the code and the one at the next Ph reading? What is affecting its change.

How should I list two readings of pressure time spaced 100 milliseconds?
 

Benjie

Senior Member
By the way it is worth noting that the value of Ph responds pretty well to a two meter height change; the problem arises whenever I want to compare it at different time intervals.
And this happens not only in the current example but also in the large previous code where I used to add/subtract the pressure variation on a word called Dl supposed to alert when it was exceeding two preset values.
 

hippy

Technical Support
Staff member
Why does Xl change its value from the one given at the end of the code and the one at the next Ph reading?
The answer probably comes down to -
Code:
Symbol Ph = w2 : Symbol Ph.msb = b5 : Symbol Ph.lsb = b6
That 'b6' is not the least significant byte of 'w2'. It should be 'b4'.

And that seems to be an error I introduced in my code in Post #27, where it probably did not matter much as we were dealing with Pl only and ignoring Ph, though, given writing to Ph.lsb will actually be altering Xl.lsb, that would explain why the difference calculations aren't working as well as they would be expected to.

Force the Ph and Pl values in Post #27 code, simulate that, and it shows ever increasing differences, as you have seen with real data. Of course I never simulated it much, and what I did simulate seemed to show it working when it wasn't.

By the way it is worth noting that the value of Ph responds pretty well to a two meter height change
I am not sure how that claim correlates to the rather high jumps seen in Post #45, and the fact that the code has this bug in it.

But it would seem you are right; just using the 16-bit msb of the sensor reading is probably acceptable so we can simplify the code, and simplify the variable naming.

I would run this and see what results you get -
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

; Comment the line below to prevent SERTXD output
#Define USE_SERTXD

Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2
Symbol last = w2
Symbol diff = w3

Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00

Symbol K           = 1

Symbol D_MID       = 30000
Symbol D_RANGE     =  1000

Symbol D_MIN       = D_MID - D_RANGE
Symbol D_MAX       = D_MID + D_RANGE
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:

  Do

    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( this.msb, this.lsb, b0 )

    If diff = 0 Then
      diff = D_MID
    Else
      #IfDef USE_SERTXD
        SerTxd( #last, TAB, #this, TAB )
      #EndIf
      Select Case this
        Case > last
          w0   = this - last / K
          diff = diff + w0 Max D_MAX
        Case < last
          w0   = last - this / K
          diff = diff - w0 Min D_MIN
      End Select
      #IfDef USE_SERTXD
        Select Case this
          Case > last : SerTxd( "+", #w0 )
          Case < last : SerTxd( "-", #w0 )
          Else        : SerTxd( "="      )
        End Select
        SerTxd( TAB, #diff, TAB, ": " )
        If diff >= D_MID Then
          w0 = diff - D_MID
          SerTxd( "+", #w0, CR, LF )
        Else
          w0 = D_MID - diff
          SerTxd( "-", #w0, CR, LF )
        End If
      #EndIf
      Gosub SetTone
    End If

    last = this
  Loop

SetTone:
  ; Set the tone here based on diff
  Return
 
Last edited:

hippy

Technical Support
Staff member
From the datasheet, pressure and sensor readings would be predicted to be as follows -
Code:
1200 mbar = 8600000 = $8339C0
 800 mbar = 7000000 = $6ACFC0
 300 mbar = 5000000 = $4C4B40
   0 mbar = 3800000 = $39FBC0
There do not appear to be many ways to turn those 24-bit numbers into easier to handle 16-bit numbers other than by dropping the least significant 8-bits.

The 24-bit raw reading changes by about 4000 for every mbar change in pressure, so a one bit reading change represents a change of 0.00025 mbar.

Dropping the 8-bit lsb would mean the 16-bit reading would change by about 16 for every mbar change in pressure, so a one bit reading change would represents a change of around 0.0625 mbar.

Given a 1.325 mbar change represents a 10 metre change in altitude, with 24-bits we can theoretically discriminate changes of around +/-2 mm. Using 16-bit we can discriminate down to around +/-500 mm changes in altitude, about half a metre, one and a half feet.

Because 0 mbar means we're out in space and it can't get any lower, we can reasonably limit the sensor reading to a minumim of $300000, then subtract $300000 from the raw reading -
Code:
1200 mbar = 8600000 = $8339C0 -> $5339C0
 800 mbar = 7000000 = $6ACFC0 -> $3ACFC0
 300 mbar = 5000000 = $4C4B40 -> $1C4B40
   0 mbar = 3800000 = $39FBC0 -> $09FBC0
Which leaves the sensor reading's most-significant bit always zero, which allows us to multiply by two and bring in the msb of the least-significant byte we were going to drop, and combine that into a 16-bit reading we can then use -
Code:
1200 mbar = 8600000 = $8339C0 -> $5339C0 -> $A673 = 42611
 800 mbar = 7000000 = $6ACFC0 -> $3ACFC0 -> $759F = 30111
 300 mbar = 5000000 = $4C4B40 -> $1C4B40 -> $3896 = 14486
   0 mbar = 3800000 = $39FBC0 -> $09FBC0 -> $13F7 =  5111
The PICAXE code to do that would be -
Code:
HI2cIn ( this.msb, this.lsb, b0 )
this = this Min $3000 - $3000 Max $7FFF * 2 + bit7
That would mean we should be able to discriminate changes of around +/-250 mm, a quarter of a metre, about 9 inches.

It would be interesting to see what dropping that "this=" line into the code from Post #49 delivers.

( Edited: Changed from subtracting $4000 to subtracting $3000 )
 
Last edited:

hippy

Technical Support
Staff member
With code of post #49 I get this sertxd without moving the sensor.
with post #50 I get this:
The first readings are : displayed = sensor / 256
for the second that is : displayed = ( sensor - $400000 ) / 128

So in reverse the first is : sensor = displayed * 256
and in reverse the second is : sensor = ( displayed * 128 ) + $400000

Which for the first : 34896 * 256 = 8933376
and for the second : ( 37023 * 128 ) + $400000 = 8933248

Which looks like the raw 'this' and 'last' numbers are right, at least consistent. That would put atmospheric pressure on your sensor at around 1280 mbar. Though that's without any calibration or temperature compensation.

There would be more variance in the second than there would be in the first, not changing in the first, and changing by +/-1 in the second seems reasonable to me.

But why the #49 code had 'diff' jumping massively to 977 before settling there, or why the second fell before stabilising around -9/-10 I don't know.

I would suspect a large difference in early readings before things settled down.

I would suggest this which ignores the first 10 readings, hopefully let's things settle down at start-up -
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

; Comment the line below to prevent SERTXD output
#Define USE_SERTXD

Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2
Symbol last = w2
Symbol diff = w3

Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00

Symbol K           = 1

Symbol D_MID       = 30000
Symbol D_RANGE     =  1000

Symbol D_MIN       = D_MID - D_RANGE
Symbol D_MAX       = D_MID + D_RANGE
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:
  Do

    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( this.msb, this.lsb, b0 )

    this = this Min $3000 - $3000 Max $7FFF * 2 + bit7

    Select Case diff
      Case < 10 : diff = diff + 1
      Case   10 : diff = D_MID
      Else
        #IfDef USE_SERTXD
          SerTxd( #last, TAB, #this, TAB )
        #EndIf
        Select Case this
          Case > last
            w0   = this - last / K
            diff = diff + w0 Max D_MAX
          Case < last
            w0   = last - this / K
            diff = diff - w0 Min D_MIN
        End Select
        #IfDef USE_SERTXD
          Select Case this
            Case > last : SerTxd( "+", #w0 )
            Case < last : SerTxd( "-", #w0 )
            Else        : SerTxd( "="      )
          End Select
          SerTxd( TAB, #diff, TAB, ": " )
          If diff >= D_MID Then
            w0 = diff - D_MID
            SerTxd( "+", #w0, CR, LF )
          Else
            w0 = D_MID - diff
            SerTxd( "-", #w0, CR, LF )
          End If
        #EndIf
        Gosub SetTone
    End Select
    last = this
  Loop

SetTone:
  ; Set the tone here based on diff
  Return
 

hippy

Technical Support
Staff member
And just to explain why you are seeing +/-1 changes, which suggests a +/-250 mm movement using 16-bits even when there is none ...

If the raw 24-bit reading changes just by one, using invented numbers here -
Rich (BB code):
1200.00000 mbar = $4ABC7F -> $1578
1200.00025 mbar = $4ABC80 -> $1579
That single bit change in 24-bits ripples through to being a +/-1 change at 16-bit.

There is no way to avoid this, it's a fact of life.
 

Benjie

Senior Member
Now it responds very well moving +/- half a meter!
Last necessary adjustment is to create a word for the sound.
Looking at the sertxd we should not use the "diff" because it is very temperature sensitive and changes with absolute pressure while W0 can be used to create easily meaningful pressure change tone.
 

hippy

Technical Support
Staff member
Looking at the sertxd we should not use the "diff" because it is very temperature sensitive and changes with absolute pressure while W0 can be used to create easily meaningful pressure change tone
On the contrary, and depending where you are looking at that throwaway 'w0', it is just the instantaneous change which varies every loop, maybe only a small amount some times, but 'diff' is the rate of change, the smoothed out filter of those 'w0' values. It's just that there is little smoothing out ( K=1 ), and no decay, so it stays stuck where it is until direction changes.

But if something else works you can remove 'diff' entirely.
 

Benjie

Senior Member
I need to test "diff" more in depth. First results using the house lift (< 1m/sec) show high temp dependance of its value even thought it senses the change. Now I should play with K and timing to scale "diff" to get the variable suited to create the sound.
Btw the sound needs two fix tones: one for each change direction. The "diff" should inversely change the time (pause) between the pulsed tones.
 

hippy

Technical Support
Staff member
I have to admit that the maths of it all is somewhat beyond me. Though I can understand what it is meant to achieve how the example code achieves that is beyond me.

Turning it into a car analogy more people will be familiar with; we are trying to find whether we are accelerating or braking hard from looking at the instantaneous speed.

In that respect 'w0' does give an instantaneous rate of change, the difference from last to this, but we are trying to find the 'trend' because that instantaneous may have some misleading up and down in it. Basically we want a longer term rate of change.

I am not sure 'diff' gives us that how things stand, merely rebuilds the raw input from the changes we have seen, and will seemingly just be a smaller version when K is greater than 1 -
Code:
                        _
                    _  / \_
this          _   _/ \/    \_   
        _   _/ \_/           \_/\   _
     __/ \_/                     \_/ \__
                        |
w0   ___|_ _|_|_ _|_|_ _|_ _ _ _|_ _|_ _
          |     |     |   | | |   |   |
                         _        |
                     _  | |_
diff           _   _| |_|   |_   _
K=1      _   _| |_|           |_| |  _
     ___| |_|                     |_| |_
We want rate of change, and that's 'w0' for 'this minus last' over the loop time, but 'diff' isn't a rate of change over time because there is no time component; it's merely some reconstruction of what the input was. It's like integrating a differential function; it takes you back to where you were.

I'm not sure what it should be, what we need. Maybe someone on the forum has a better idea of what we need and how to achieve it ?
 

Benjie

Senior Member
Hippy, I made some record of the sertxd of your post 53 code.
The attached file show the values of "diff" when moving the sensor relatively fast up and down by about 2 meters. The response is very good.
However if I add two gosub on lines 57 and 58, (see bottom lotone, histone) the program does not loop any longer or, for what I hear, once every 15 seconds or more. Looks like it loops time to time without any relationship.
It is a pity because the records of the attached file are very promising (made in pdf and jpg format).
 

Attachments

Benjie

Senior Member
I noticed also that, due to the temperature variations, the pressure values have a drift which little by little move the w0 value away from the initial 3000. Something needs to be introduced to bring back w0 to its center value anytime there is no fast change. I noticed this problem while taking the sensor in the lift: the temperature in the lift was some 4-5 degressC below the starting temperature. The “diff”, because of that, kept moving in one direction making its usage for tone control useless.
Ideally we shoul have a reference pressure value as result of the average of 3 or 4 readings and compute the “diff” as the “this” +/- the reference average. I do not see a major difficulty in performing such logic: T1 collect “this” say in W0/3, pause abt 100, T2 store again in W1/3, T3 store again in W3/3, add the 3 readings and generate a signed “diff”, store last reading as W0/3, pause abt 100 and so on.
Probably, to have a reasonable time response, the 08M2 should be clock’d at 16 MHz and investigate if the MS5611 can operate with a I2C fast.
The two tones pulse recurrence (frequency) shoul be increasing as the “diff” increases. It may be possible to generate in a separate task a 50% duty circle pulse with a frequency proportional to “diff” and AND’d with one of the two sound pulses.
The usage of multitask may be beneficial in keeping the generation of the “average” and the generation of “diff” in two separated tasks (at least that is what I may imagine about multitasking).
Hope that this note gives a suggestion to your post #58.
 

Benjie

Senior Member
Hippy, can you explain again this line: " this = this Min $3000 - $3000 Max $7FFF * 2 + bit7".
In post #50 you say to subtract $300000 while in the above line you subtract $3000.
Thanks
 

Benjie

Senior Member
On the left are the rough msb and usb while on the right are the results of "this = this Min $3000 - $3000 Max $7FFF * 2 + bit7"
 

Attachments

hippy

Technical Support
Staff member
Hippy, can you explain again this line: " this = this Min $3000 - $3000 Max $7FFF * 2 + bit7".
In post #50 you say to subtract $300000 while in the above line you subtract $3000.
That is subtract $300000 from the 24-bit number. Which is subtract $3000 from the 16-bit number which are the most significant bits. the rightmost $00 is subtracted from b0 which, being zero, doesn't actually need to be done.
Code:
Using a 24-bit number       Using 16-bit + 8-bit numbers

                                          this   b0
           .----------.                .-------.----.
  $456789  | 45 67 89 |       $456789  | 45 67 | 89 |
           `----------'                `-------^----'
           .----------.                .-------.
- $300000  | 30 00 00 |     - $3000    | 30 00 |
           `----------'                `-------'
           .----------.                .-------.----.
= $156789  | 15 67 89 |     = $156789  | 15 67 | 89 |
           `----------'                `-------^----'
           .----------.                .-------.
*2 =       | 2A CF 12 |     *2+bit7 =  | 2A CF |
           `----------'                `-------'
The "Max $7FFF" is just a safety net, to ensure we don't overflow when shifted and the bit7 is added.
 
Last edited:

hippy

Technical Support
Staff member
On the left are the rough msb and usb while on the right are the results of "this = this Min $3000 - $3000 Max $7FFF * 2 + bit7"
Not sure your results are right. It seems to work when I simulate it -
Code:
Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2

this.msb = 134 : this.lsb = 224 : b0 = 188 : Gosub Test
this.msb = 134 : this.lsb = 224 : b0 =   0 : Gosub Test
End

Test:
  SerTxd( #this.msb, TAB, #this.lsb, TAB, #b0, TAB, #this, TAB, TAB )
  this = this Min $3000 - $3000 Max $7FFF * 2 + bit7
  SerTxd( #this.msb, TAB, #this.lsb, TAB, #this, CR, LF )
  Return
Using two values you have, that gives these results which appear to be as intended and expected -
Code:
.msb  .lsb  b0    this      .msb  .lsb  this
134   224   188   34528     173   193   44481 
134   224   0     34528     173   192   44480
You seem to have -
Code:
.msb  .lsb  b0    this      .msb  .lsb  this
134   224   188   34528     173   202   44490
134   224   0     34528     173   202   44490
There seems to be some discrepency in your 'this.lsb' result and thus in 'this'. Perhaps post your code and it will show what's wrong. I suspect some sort of variable usage conflict.
 
Last edited:

Benjie

Senior Member
Here the code and the two sertxd alternatively used.
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

; Comment the line below to prevent SERTXD output
#Define USE_SERTXD

Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2
Symbol last = w2
Symbol diff = w3

Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00

Symbol K           = 1

Symbol D_MID       = 30000
Symbol D_RANGE     =  1000

Symbol D_MIN       = D_MID - D_RANGE
Symbol D_MAX       = D_MID + D_RANGE
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:
  Do

    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( this.msb, this.lsb, b0 )
sertxd(#this.msb,tab,#this.lsb,tab,#b0,"    ",#this,cr,lf)
    this = this Min $3000 - $3000 Max $7FFF * 2 + bit7
    'sertxd(#this.msb,tab,#this.lsb,tab,#this,cr,lf)
  pause 1000
  loop
 

Benjie

Senior Member
The problem comes from the fact that the sertxd are run alternatively thus at different times. Printing them on the same run the result is predicted with the last digit somewhat toggling.
 

hippy

Technical Support
Staff member
The problem comes from the fact that the sertxd are run alternatively thus at different times.
Ah, right; the columns on the right do not relate directly to those on the left. On that basis; everything seems to be working as expect.
 

Benjie

Senior Member
Hippy, with these two lines:
HI2cIn ( this.msb, this.lsb, b0 )
this = this Min $3000 - $3000 Max $7FFF * 2 + bit7
you resolved brilliantly the resolution increase. Excellent.

Now, to really smooth the final datum which define the pause between the sound pulses, I got the idea to use the "average" of the two subsequent "diff".
This should reduce the toggling of last digit when nothing moves but maintains the improved resolution.
Here the tentative code which still has some syntax problem:
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2
Symbol last = w2
Symbol diff = w3
symbol old = w4 : Symbol old.msb = b8 : Symbol old.lsb = b7
symbol this1 = w5 : Symbol this1.msb = b11 : Symbol this1.lsb = b10
symbol beat = w6 : Symbol this2.msb = b13 : Symbol this2.lsb = b12

Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC  = $00

Symbol K = 1
symbol X = 1

Symbol D_MID  = 500
Symbol D_REF = 500
 
PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:

 HI2cOut ( CMD_D1_4096 )
        Pause 10
        HI2cOut ( CMD_ADC )
        Pause 10

        HI2cIn ( this.msb, this.lsb, b0 )
        old = old Min $3000 - $3000 Max $7FFF * 2 + bit7 

  do

        HI2cOut ( CMD_D1_4096 )
        Pause 10
        HI2cOut ( CMD_ADC )
        Pause 10

        HI2cIn ( this.msb, this.lsb, b0 )
        this= this Min $3000 - $3000 Max $7FFF * 2 + bit7 
        select case this
            < old : diff = this - old : D_MID = D_REF + diff
            > old : diff = old - this : D_MID = D_REF - diff
            = old : diff = 0

            sertxd(#D_MID, tab.)    
 
        HI2cOut ( CMD_D1_4096 )
        Pause 10
        HI2cOut ( CMD_ADC )
        Pause 10

        HI2cIn ( this.msb, this.lsb, b0 )
        this1= this1 Min $3000 - $3000 Max $7FFF * 2 + bit7 
        select case this1
            < this : diff = this1 - this : D_MID = D_MID + diff
            > this : diff = this - this1 : D_MID = D_MID - diff
            = this : diff = 0
  
            sertxd(#D_MID, tab.)    
            
          HI2cOut ( CMD_D1_4096 )
        Pause 10
        HI2cOut ( CMD_ADC )
        Pause 10

        HI2cIn ( this.msb, this.lsb, b0 )
        old = old Min $3000 - $3000 Max $7FFF * 2 + bit7 
        select case old
            < this1 : diff = this1 - old : D_MID = D_MID + diff
            > this1 : diff = old - this1 : D_MID = D_MID - diff
            = this1 : diff = 0
  
            sertxd(#D_MID, tab.)    
            
        select case D_MID
            > D_REF : beat = D_MID - D_REF : sound 4,(80,20)
            < D_REF : beat = D_REF - D_MID : sound 4,(120,20)
            = D_REF : exit
            
            beat = D_MID * X
            sound 4,(0,20)
            pause beat
            this1 = old
            
   loop
Can I have your opinion? thanks
 

Benjie

Senior Member
Hippy, I found this article from https://github.com/har-in-air/ms5611 which is killing my expectation from this exercise with Picaxe:

ms5611
MEAS MS5611 pressure sensor library for altitude / variometer applications

Integer code provided in datasheet does not have adequate resolution for variometer (rate-of-climb) applications. So I've modified some of the computations to use floating point operations. This does not mean the improved-resolution pa measurements are more accurate. You will still need noise-filtering algorithms to process the data. Sliding-window averaging is fine for barometric pressure/altimeter applications, but more sophisticated processing will be required for variometer applications. E.g. Kalman filtering, linear regression etc.

The pressure to altitude conversion is done via look up tables followed by linear interpolation. This is useful if using an 8bit/16bit processor and the processing time is critical. Accuracy can always be improved by decreasing the lookup table interval (more entries), but at the cost of code space.

Code assumes spi bit-bang interface to the MS5611.
 

hippy

Technical Support
Staff member
Hippy, I found this article from https://github.com/har-in-air/ms5611 which is killing my expectation from this exercise with Picaxe:
You are possibly right. That's another example which shows what is being done but has no real background detail which would explain how exactly it is done or the theory and principles behind what is being done. One would have to figure out exactly what is being done and then try to figure out the why, and how this example achieves its results.

The problem with porting code for one thing to anything else is, where the two are not compatible, the code cannot run as it is. In those circumstances it is usually best to forget porting the actual code, take a step back and go from 'what it does and how it does it' to an implementation suitable for the target.

Key is 'what it does and how it does it' and that's what's missing here and in other examples. It's not so much that the PICAXE couldn't do it, but that we cannot figure out what the PICAXE actually needs to do to achieve it. While the input and desired output is known, it's not clear how to get from one to the other.

It may be that what a PICAXE needs to do is beyond is capabilities or not achievable without a lot of hard work. But we would need a well defined, specified and proven, 'what it needs to do' before being able to tell.
 

Benjie

Senior Member
I understand the impossibility to port a code from one system to another. The approach should be to understand first what the foreign code is attempting (verbalize the strategy used) and instruct the Picaxe code to perform the same basic steps.
I found a well described article in:
https://www.instructables.com/id/Arduino-Atmospheric-Tape-Measure-MS5611-GY63-GY86-/
which has an in depth description of the steps. It is interesting the application of the moving average code; have no idea if that can be performed with Picaxe......it would simplify the task.
 

hippy

Technical Support
Staff member
found a well described article in:
https://www.instructables.com/id/Arduino-Atmospheric-Tape-Measure-MS5611-GY63-GY86-/
which has an in depth description of the steps. It is interesting the application of the moving average code; have no idea if that can be performed with Picaxe......it would simplify the task.
Well, it did reveal one flaw with what we have been doing -
The data has some noise... This can be smoothed using a digital filter (a really useful tool). The filter equation is:

value = value + K(new-value)
That, using the terminology I have been previously using, is -

diff = diff + ( ( this - diff ) * K )

But what we have been using is -

diff = diff + ( ( this - last ) * K )

The first is creating an average, the second, what we have been doing, doesn't.

Whether we need any averaging using 16-bit values is debatable. We seem to have mostly removed the noise by truncating from 24-bit, have variances of just +/-1 when static, and that can probably be smoothed out with a simple rolling average filter -

average = ( average + this ) / 2

The other thing that description suggests is that height in metres is the pressure, less the ground reference, divided by 12.

That divisor will need to be adjusted because we are using 16-bit data which has been offset by subtracting $300000 from the 24-bit raw sensor value.

I think we need to take a step back. Use what we have to create something which accurately determines elevation. See how that goes, and take it from there.

I would be starting with this -
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

; Comment the line below to disable  SERTXD output
#Define USE_SERTXD

Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2
Symbol avrg = w2
Symbol grnd = w3

Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00

PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:

  Do

    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( this.msb, this.lsb, b0 )
    #IfDef USE_SERTXD
      SerTxd( #this, TAB, #b0, TAB )
    #EndIf
    this = this Min $3000 - $3000 Max $7FFF * 2 + bit7 

    If avrg = 0 Then
      avrg = this
    Else
      w0   = this / 2
      avrg = avrg / 2 + w0
      If grnd = 0 Then
        grnd = avrg
      End If
      #IfDef USE_SERTXD
        SerTxd( #this, TAB, #avrg, CR, LF )
      #EndIf
    End If
    Pause 430
  Loop
 

Benjie

Senior Member
Hippy, before I consider your post #73 code, let me express a substantial doubt: when I record the least significant byte (bit 0 to 7) of the output, it swings from 10 to 200 without moving. We can apply any smoothing, average or other tools but it will not be possible to have a meaningful data from that byte.
My conclusion is that something is wrong in reading the pressure raw data from the sensor.
Can you have a new look to the data sheet to ensure that the ADC reading collect the right sensor raw data?
 

hippy

Technical Support
Staff member
Hippy, before I consider your post #73 code, let me express a substantial doubt: when I record the least significant byte (bit 0 to 7) of the output, it swings from 10 to 200 without moving. We can apply any smoothing, average or other tools but it will not be possible to have a meaningful data from that byte.
The least significant byte is the noise the linked article talks about. We can make that meaningful, apply smoothing, but only by averaging all 24-bits. That's a pain to do on a PICAXE.

But that noise is like someone with very shaky hands manually adjusting a watch which doesn't tick to keep up with what the actual time is; the seconds hand will go back and forth and all over the place even if they are keeping hour and minute time correctly.

But, by removing the seconds hand we won't see that noise, even though it's still there. There might be a little noise in the minutes every now and again but not that much. That's what we are achieving by truncating to 16-bits. It therefore doesn't matter that there is noise.

Another analogy is an audio amp wound-up to full, maximum resolution, "11" as the joke goes. There will be lots of hiss. Turn the volume down a little and there will be less hiss.

By making the volume lower, reducing the range of volume, we effectively average out the noise. We are reducing 24-bits, actually 23-bits because of our subtract $300000 trick, to 16-bits. The pressure gets compressed, but so does the noise -

23BIT.jpg

The only consequence of doing it this way is that we no longer have altitude resolution of +/-2mm, only +/-250mm, and that's not so bad when we don't actually need to have +/-2mm for the end application.

My conclusion is that something is wrong in reading the pressure raw data from the sensor.
Can you have a new look to the data sheet to ensure that the ADC reading collect the right sensor raw data?
It looks right to me; the numbers match what I think we would be expecting to see.

The best way to confirm it would be to get some readings and look at the results. At ground level, up at 1 metre, up at 10 metres, at 20 metres; the more the merrier, and the higher the better.

If the drop in readings going from ground level to 10 metres is somewhat the same as the drop going from 10 metres to 20 then that would seem to confirm it.

Knowing what those readings were and at what altitude would also make it easier to determine how to convert pressure to an actual altitude output.

As regards the datasheet; D1 is pressure, D2 is temperature, the ADC command we use is $48, which means read D1 (pressure) with 4096 oversampling. That all checks out.
 

Benjie

Senior Member
Last attempt: let's do the average=(average+this)/n and add the last 10 readings of b0 into W0. Hopefully the operation will take less than 500 ms. I'll come back once I complete such code.
 

hippy

Technical Support
Staff member
let's do the average=(average+this)/n and add the last 10 readings of b0 into W0.
Why ? Why not do what I suggested and see what the results are ?

And it won't work to average just b0 when that's a component part of a 24-bit number, is not something one can deal with separately.

I don't see what the evidence is for needing a more complicated averaging regime. The previous results were only showing noise in the order of +/-1 bit in 16-bits. Trying to get no noise at all is likely a fool's errand.

And averaging multiple 16-bit numbers isn't possible without losing accuracy using only 16-bit maths. That will require 24-bit numbers and maths. One might as well average out the raw 24-bit numbers before converting to 16-bit.

One thing I would suggest for any averaging is to use a power-of-two number of samples as that will make the maths far easier, just needing bit-shifts to achieve the division.
 

rq3

Senior Member
That suggests the raw pressure sensor reading is tending towards increasing or decreasing over time rather than remaining static.

There seems to be two possible explanations for that -

Pressure is changing. It can and is the basis for using a barometer to predict changes in weather.

Temperature is changing ( ambient or in-chip ) and that is affecting the value reported.

However, neither should matter much. It's not change we are interested in, but rate of change.

The problem perhaps is that our accumulation of changes isn't actually rate of change.

What we are currently trying to do is determine we are rising 5 feet in an hour by detecting we have risen an inch in a minute, and trying to compensate for there being some wobble in our rising.

In practice though we don't care if we are rising 5 feet in an hour, we only care about the instantaneous change; an inch a minute is fine but a foot a minute should set alarm bells off.

To make the accumulation go down we actually need pressure to change in the opposite direction. There should probably be some sort of on-going decay in there which removes the overall long term increase or decrease and only leaves the instantaneous.

I would guess that's why the original code example seems to have two averages; short term and long term, so the long term can be removed from the short, leaving only instantaneous changes; rate of change.

Is there any page which describes the maths and theory behind that code example ?

That might help because at the moment we are trying to implement an algorithm to solve a mathematical problem neither of us seem to particularly understand.
There is a common misperception that atmospheric pressure change is a very slow phenomenon. It isn't. It's not a trivial exercise to average the changes of atmospheric pressure detected by a digital sensor, when aiming for data at the foot, or meter, level.

Google "microbarom", especially if you are anywhere near sea level in altitude, or within a few hundred miles of a coastline.

Looking at the "foot" counter hand on a high quality analog aircraft altimeter with a magnifying glass will let you see it slowly increment and decrement by about 5 feet over a span of perhaps 60 seconds. With a storm approaching, the variation can be much greater (10's of feet), and much more rapid (a few 10's of seconds).

Some aircraft have "altitude hold" functions on their autopilots, which keep the plane at a constant barometric altitude. The altitude hold function is severely low pass filtered. Basically, the autopilot barometer asks itself if the required change in control is reasonable, based on its last measurement. If the required change is NOT reasonable, it makes another measurement, and goes through the loop several more times. If the loop iterations get excessive, the autopilot flashes a warning to the pilot, and disconnects itself.

If a Picaxe experimenter is expecting to light an LED within a foot or two of a "known" altitude (too high, too low), it won't work unless the altitude is well averaged over an appreciable span of time. And expecting an aircraft, of any type, to hold a rigid altitude above the ground based upon barometric measurements is an exercise in futility. It's like measuring your absolute height above the ground while using a barometer on a huge trampoline that throws you into the air 20 feet or so about every 30 seconds or so. That's the condition of the normal atmosphere.
 

Benjie

Senior Member
Hi Hippy, despite displaying as logged-in, I was absent few days.
Have read your posts and tried the code of post #73. Reducing the pause to 100 and watching the terminal I noticed a variation on "avrg" of about 3-4 digits for an altitude change of 80 cm. I attach the data.
The variations are consistent. Unfortunately I cannot record the data for 10 m variation.
One question: what is the purpose of the code:
If grnd = 0 Then
grnd = avrg
End If
I do not see any reference to "grnd" in the rest of the code.

Starting from post#73 code, I will add the usual comparison check and drive two led's to experiment with the house lift to assess the consistent light-up one led going down and the other going up.
Will report the results by tomorrow.
 

Attachments

Benjie

Senior Member
I implemented the comparison between averages taken at two different times and it works except......
the led connected to c.4 react correctly while the led connected to output c.0 is almost all time "on".
The out c.0 is also the serial out therefore in normal operation is disconnected from the programming cable and connected to the led. I tried to do a simple code to make the led on and off as per this code:
Code:
do
    low 0
    pause 100
    high 0
    pause 100
loop
and it blinks when I disconnect the programming cable.
However with this code:
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

Symbol this = w1 : Symbol this.msb = b3 : Symbol this.lsb = b2
Symbol last = w2 : Symbol last.msb = b5 : Symbol last.lsb = b4
Symbol avrg = w3
Symbol avrg1 = w4
Symbol diff = b0
Symbol grnd = w5
Symbol CMD_RESET   = $1E
Symbol CMD_D1_4096 = $48
Symbol CMD_ADC     = $00

PowerOnReset:

  HI2cSetup I2CMASTER, %11101110, I2CSLOW, I2CBYTE

MainLoop:

  Do
'fiest reading

    HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( this.msb, this.lsb, b0 )
    this = this Min $3000 - $3000 Max $7FFF * 2 + bit7 

    If avrg = 0 Then
      avrg = this
    Else
      w0   = this / 2
      avrg = avrg / 2 + w0
      If grnd = 0 Then
        grnd = avrg
      End If
    End If

    Pause 50

'second reading store avrg

       HI2cOut ( CMD_D1_4096 )
    Pause 10
    HI2cOut ( CMD_ADC )
    Pause 10

    HI2cIn ( last.msb, last.lsb, b0 )
    last = last Min $3000 - $3000 Max $7FFF * 2 + bit7 

      avrg1 = last
      w0   = last / 2
      avrg1 = avrg1 / 2 + w0

  
select case avrg1
    
case = avrg
    diff = 0 : high 4 : high 0
case > avrg
      diff = avrg1 - avrg : low 4
case < avrg
      diff = avrg - avrg1 : low 0 
end select

  diff = diff
  pause diff
    high 4 : high 0
sertxd(tab,#avrg1,"   ",#avrg,"  ",#diff,lf,cr)
  Pause 50
  loop
it blinks in an erratic fast sequence (checked on the scope).
The sertxd displays a correct value of "diff" which is correctly followed by the led on c.4.
Where is the mistake?
 
Top