Shop OBEX P1 Docs P2 Docs Learn Events
please help i am use time intervals to calculate an avg over time — Parallax Forums

please help i am use time intervals to calculate an avg over time

Tony_tsiTony_tsi Posts: 98
edited 2012-07-07 19:08 in Propeller 1
I have a sensor that will be triggered a few times a second. I am trying to calculate the average times per hour this sensor will be triggered. It will be around 2400 times an hour. I know there are many problems with this pub but i do not know there solutions. The two biggest problems I know of are that the values that i am working with are to big to store in a long. also the way i am using cnt to keep up with time interval is bad because it also counts the time it takes the code to execute. I have only included the pub that i am having trouble with.pub for avg.spin

Comments

  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-05 20:56
    Why not use scaling?

    You can scale the values to milliseconds or centiseconds and store them that way. There are 3,600,000 milliseconds in an hour, certainly small enough to store in a long.

    You can monitor the trigger in a variable and accumulate them until an hour passes, when the hour passes, take the count and store it, then clear the trigger count, clear the milliseconds count and start over

    This is untested psuedocode to give you an idea.
      l_timeStamp := cnt
    
    repeat
    
      if (l_trigger == true)                ' if sensor trigger is equal to true
        l_triggers += 1                    ' add 1 event to the variable that keeps track of sensor triggers
    
      if ((cnt - l_timeStamp) > 0)                       ' if cnt - l_timestamp is > 0
        l_milliseconds += 1                               ' add 1 to the milliseconds cnt
        l_timeStamp := (timeStamp + 80000)    ' push l_timeStamp another millisecond into the future
    
      if (l_milliseconds > 3599999)                   ' if milliseconds are greater than 3,599,999 or equal to 1 hour
        l_hourlyTriggers := triggers                   ' keep a copy of the number of triggers in an hour
        l_triggers := 0                                      ' after obtaining the copy, reset the value of l_triggers
        l_milliseconds := 0                              ' reset the number of milliseconds to 0 after an hour
    
    
    
  • Tony_tsiTony_tsi Posts: 98
    edited 2012-07-05 21:24
    I cant wait an hour for the results. I want to calculate how many times it will be triggered in an hour. I need to update a display every second .
  • JonnyMacJonnyMac Posts: 9,194
    edited 2012-07-05 21:48
    What about this:

    avg := accumulated_events * seconds_per_hour / accumulated_seconds

    This assumes, of course, that you have a simple mechanism of counting inputs (perhaps using a counter) every second and can run this formula every second.
  • Tony_tsiTony_tsi Posts: 98
    edited 2012-07-05 23:43
    I would like to measure the time between rising pulses then take the number of seconds in an hour and divide it by this value. Calculated_times_per_hour := time_in_an_hour / time_between_rising_edge_of_pulse . It's basically a RPH gauge (rotations per hour) with a 2m_s pulse for each full rotation
  • jmgjmg Posts: 15,183
    edited 2012-07-06 01:57
    Tony_tsi wrote: »
    I would like to measure the time between rising pulses then take the number of seconds in an hour and divide it by this value. Calculated_times_per_hour := time_in_an_hour / time_between_rising_edge_of_pulse . It's basically a RPH gauge (rotations per hour) with a 2m_s pulse for each full rotation

    What precision do you need ? - ie what is the desired LSB / how many digits ?

    If you want to display a value around 2400, and stick inside 32 bit maths, then the time LSB needs to be slower than appx 1us ( 1MHz count rate ) - as an example, clock at 1MHz and edges/hr is 3.6e9, which just fits inside 32 bits, and 2400pph will be 1.5e6 counts.
    If you speed up one LSB, now the closest adjacent possible displayed value is 1e6*3600/(1500000-1) = 2400.00160
    So that is the numeric limit.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-06 05:52
    Ok, that's completely different and probably easier, spin or PASM? The following is psuedospin
    if ina[5] := 1
    l_prevRisingEdge := l_risingEdge
    l_risingEdge := cnt
    
    
    l_edgeToEdgeTime := (l_risingEdge - l_prevRisingEdge)
    
    timesPerSecond := (clk/l_edgeToEdgeTime)
    timesPerMinute := (timesPerSecond * 60)
    timesPerHour := (timesPerMinute * 60)
    
    

    If you want a rolling average you'll have to take 8 or so samples, average them and then do the math, something like this. (there are quicker ways to do this with a FIFO buffer, but this makes more sense for a visual explanation in my opinion)
    l_risingEdgeAvg := 0    ' clear out the average value
    
    
    
    l_prevEdgeToEdgeTime7 := l_prevEdgeToEdgeTime6       ' cycle to previous
    l_prevEdgeToEdgeTime6 := l_prevEdgeToEdgeTime5       ' cycle to previous
    l_prevEdgeToEdgeTime5 := l_prevEdgeToEdgeTime4       ' cycle to previous
    l_prevEdgeToEdgeTime4 := l_prevEdgeToEdgeTime3       ' cycle to previous
    l_prevEdgeToEdgeTime3 := l_prevEdgeToEdgeTime2       ' cycle to previous
    l_prevEdgeToEdgeTime2 := l_prevEdgeToEdgeTime1       ' cycle to previous
    l_prevEdgeToEdgeTime1 := l_edgeToEdgeTime               ' cycle to previous
    l_prevRisingEdge := l_risingEdge                                     
    l_risingEdge := cnt
    l_edgeToEdgeTime := (l_risingEdge - l_prevRisingEdge)   ' get current
    
    
    l_risingEdgeAvg := (l_prevEdgeToEdgeTime7 + l_prevEdgeToEdgeTime6 + l_prevEdgeToEdgeTime5 + l_prevEdgeToEdgeTime4 + l_prevEdgeToEdgeTime3 + l_prevEdgeToEdgeTime2 + l_prevEdgeToEdgeTime1 + l_edgeToEdgeTime)    ' sum eight of them together
    
    l_risingEdgeAvg := (l_risingEdgeAvg / 8)   ' divide the sum by 8 to get the average of the 8
    
    
    timesPerSecond := (clk/l_risingEdgeAvg )
    timesPerMinute := (timesPerSecond * 60)
    timesPerHour := (timesPerMinute * 60)
    
    
  • JonnyMacJonnyMac Posts: 9,194
    edited 2012-07-06 20:16
    Here's a simple SPIN method (designed to run in its own cog) that does what you want. Test program is attached. The test program also includes a pulse generator cog that you can use to test expected pulse intervals.
    pri pph(pin, pntr) | mask, t1, t2                               ' launch with cognew
    
    '' Measures pulses-per-hour on pin
    '' -- updates long at pntr
    
      mask := 1 << pin              
    
      waitpne(mask, mask, 0)                                        ' wait for low
      waitpeq(mask, mask, 0)                                        ' wait for high
      t1 := -cnt                                                    ' start timing window
      
      repeat
        waitpne(mask, mask, 0)                                      ' wait for low
        waitpeq(mask, mask, 0)                                      ' wait for high
        t2 := cnt                                                   ' stop timing window
    
        t1 := (t1 + t2) / MS_001                                    ' convert to milliseconds
        if ((t1 > 0) and (t1 =< 3_600_000))                         ' valid time                   
          t1 := 3_600_000 / t1                                      '  convert to pulses/hour
        else
          t1 := 0
        
        long[pntr] := t1                                            ' update target
    
        t1 := -t2                                                   ' restart on last leading edge
    
  • Tony_tsiTony_tsi Posts: 98
    edited 2012-07-07 11:42
    JonnyMac wrote: »
    Here's a simple PASM method (designed to run in its own cog) that does what you want. Test program is attached. The test program also includes a pulse generator cog that you can use to test expected pulse intervals.
    pri pph(pin, pntr) | mask, t1, t2                               ' launch with cognew
    
    '' Measures pulses-per-hour on pin
    '' -- updates long at pntr
    
      mask := 1 << pin              
    
      waitpne(mask, mask, 0)                                        ' wait for low
      waitpeq(mask, mask, 0)                                        ' wait for high
      t1 := -cnt                                                    ' start timing window
      
      repeat
        waitpne(mask, mask, 0)                                      ' wait for low
        waitpeq(mask, mask, 0)                                      ' wait for high
        t2 := cnt                                                   ' stop timing window
    
        t1 := (t1 + t2) / MS_001                                    ' convert to milliseconds
        if ((t1 > 0) and (t1 =< 3_600_000))                         ' valid time                   
          t1 := 3_600_000 / t1                                      '  convert to pulses/hour
        else
          t1 := 0
        
        long[pntr] := t1                                            ' update target
    
        t1 := -t2                                                   ' restart on last leading edge
    


    Thankyou I will try this. I have no experence with pasm but I think I understand how to use this code.
  • Tony_tsiTony_tsi Posts: 98
    edited 2012-07-07 11:44
    timesPerSecond := (clk/l_edgeToEdgeTime)
    what is clk? I have not been able to try this code yet. I am at work and thumbed through the propeller manual and did not find clk as a command. I dont have the program on this computer so I cant check it.
  • Tony_tsiTony_tsi Posts: 98
    edited 2012-07-07 11:45
    turbosupra wrote: »
    Ok, that's completely different and probably easier, spin or PASM? The following is psuedospin
    if ina[5] := 1
    l_prevRisingEdge := l_risingEdge
    l_risingEdge := cnt
    
    
    l_edgeToEdgeTime := (l_risingEdge - l_prevRisingEdge)
    
    timesPerSecond := (clk/l_edgeToEdgeTime)
    timesPerMinute := (timesPerSecond * 60)
    timesPerHour := (timesPerMinute * 60)
    
    

    If you want a rolling average you'll have to take 8 or so samples, average them and then do the math, something like this. (there are quicker ways to do this with a FIFO buffer, but this makes more sense for a visual explanation in my opinion)
    l_risingEdgeAvg := 0    ' clear out the average value
    
    
    
    l_prevEdgeToEdgeTime7 := l_prevEdgeToEdgeTime6       ' cycle to previous
    l_prevEdgeToEdgeTime6 := l_prevEdgeToEdgeTime5       ' cycle to previous
    l_prevEdgeToEdgeTime5 := l_prevEdgeToEdgeTime4       ' cycle to previous
    l_prevEdgeToEdgeTime4 := l_prevEdgeToEdgeTime3       ' cycle to previous
    l_prevEdgeToEdgeTime3 := l_prevEdgeToEdgeTime2       ' cycle to previous
    l_prevEdgeToEdgeTime2 := l_prevEdgeToEdgeTime1       ' cycle to previous
    l_prevEdgeToEdgeTime1 := l_edgeToEdgeTime               ' cycle to previous
    l_prevRisingEdge := l_risingEdge                                     
    l_risingEdge := cnt
    l_edgeToEdgeTime := (l_risingEdge - l_prevRisingEdge)   ' get current
    
    
    l_risingEdgeAvg := (l_prevEdgeToEdgeTime7 + l_prevEdgeToEdgeTime6 + l_prevEdgeToEdgeTime5 + l_prevEdgeToEdgeTime4 + l_prevEdgeToEdgeTime3 + l_prevEdgeToEdgeTime2 + l_prevEdgeToEdgeTime1 + l_edgeToEdgeTime)    ' sum eight of them together
    
    l_risingEdgeAvg := (l_risingEdgeAvg / 8)   ' divide the sum by 8 to get the average of the 8
    
    
    timesPerSecond := (clk/l_risingEdgeAvg )
    timesPerMinute := (timesPerSecond * 60)
    timesPerHour := (timesPerMinute * 60)
    
    


    timesPerSecond := (clk/l_edgeToEdgeTime)
    what is clk? I have not been able to try this code yet. I am at work and thumbed through the propeller manual and did not find clk as a command. I dont have the program on this computer so I cant check it. should it be clkfreq ?
  • turbosupraturbosupra Posts: 1,088
    edited 2012-07-07 12:27
    Sorry, clk is your clock frequency. So if you have this in your constants

    _CLKMODE = XTAL1 + PLL16X
    _CLKFREQ = 80_000_000

    you can set a variable named clk to 80000000 to represent 80 million clock cycles per second. If you have a 5mhz crystal and a different multiplier (PLL16x) ( 5x16 = 80 million) then you would set your clk variable to something else. You can also used clkfreq as well, which is a predefined variable built into spin.

    Basically it represents a constant or a known value that is unchanging. You need this to start your calculations from and build from that.

    As an FYI, if you decide to try, I have found John's objects pretty simple to use, even when I didn't know how to read a word of PASM. Usually they are like a .net object where you may not know what is going on in the background but you can still use it to input and receive results, like a dll.

    Keep us posted on how it is going.
  • JonnyMacJonnyMac Posts: 9,194
    edited 2012-07-07 12:56
    Thank you I will try this. I have no experence with pasm but I think I understand how to use this code.

    None of the code I posted is PASM; it's 100% SPIN. As you are monitoring wide pulses that are infrequent, and you want to estimate pulses per hour based on edge-to-edge timing, it's easy to do without resorting to Assembly programming; the ability to access the Propeller's free-running counter (cnt) and determine elapsed time between events is something I find very useful.

    BTW, you'll note that t1 is loaded with the negative value of the counter; this makes finding the elapsed time as easy as adding the new ending counter value to the starting counter value, and takes care of negative values in the process. This will work with an event duration up to about 29 seconds at 80MHz. Note that this code will no properly handle a situation where there is an excessive delay between edges; I'll leave that to you (work on it after you get the basics handled).
  • msrobotsmsrobots Posts: 3,709
    edited 2012-07-07 15:24
    Jon

    You wrote it yourself in your post.
    Here's a simple PASM method (designed to run in its own cog) that does what you want

    Enjoy!

    Mike
  • JonnyMacJonnyMac Posts: 9,194
    edited 2012-07-07 19:08
    Thanks, I'll fix that. Sorry for the confusion -- been doing a lot of coding this week and I'm a little tired.
Sign In or Register to comment.