Shop OBEX P1 Docs P2 Docs Learn Events
Getting accurate results from MOD (//) — Parallax Forums

Getting accurate results from MOD (//)

pgbpsupgbpsu Posts: 460
edited 2009-06-16 18:34 in Propeller 1
I have a timer application which uses MOD and it's giving unexpected results. The application allows the user to select the length of a countdown timer (5,10,15,30seconds, 1,2,3,4,5,10,15,30minutes, 1,2,6,12hours). When the current time (provided by GPS) is evenly divisible by the selected interval it dings a bell. So if the user selects 10seconds as the interval the bell should ring at 13:25:10 13:25:20 13:25:30..... Until the timer is turned off.

I thought I had this working properly until I started logging the results. What I found was sometimes a timer will go early and then go again at the right time. I believe my error is in the way I calculate time_remaing_in_current_interval.

I've taken the interval and converted it to seconds. So a five minute interval is 300 seconds. I've also taken the current time and converted it to total seconds since beginning of the day. And when
remainder := interval_sec - ( gps.total_seconds //  interval_sec )                            
if ( remainder == interval_sec )
  ring bell




Here's how I found the error. With the interval set to 30 seconds, when the current time reaches 8:24:40 the bell rings.
By my calculation total_seconds (8*3600+24*60+40) is 30280. When you 30280//30=30.039 which gets truncated to 30 which is a TRUE condition for my test and the bell rings.

Can this be made to work with MOD? I have a limited number of possible intervals. I guess I could create a case statement which would know the current interval and compare it to the current time. If the two matched it would ring the bell. That seems unnecessary, prone to error, and not very elegant. It seems MOD should do what I want. I was thinking about multiplying one or both sides of the equation to improve the "resolution" of MOD, but I couldn't come up with anything that worked

Has anyone dealt with this? Any suggestions?

Thanks in advance.
Peter

Comments

  • ericballericball Posts: 774
    edited 2009-06-15 16:11
    The following should work:
    IFNOT gps.total_seconds // inverval_sec
      ring bell
    
    



    Although, now that I look at it, yours should have worked as well. Hmmm....
    8 * 3600 + 24 *60 + 40 = 30280, which is less than 2^31, so the sign bit shouldn't be set. 30280 // 30 = 30280 - INT( 30280 / 30 ) * 30 = 10. Modulus is an integer operation, so no rounding.

    Are you certain gps.total_seconds is returning the value you think it is?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Composite NTSC sprite driver: http://forums.parallax.com/showthread.php?p=800114
    NTSC color bars (template): http://forums.parallax.com/showthread.php?p=803904
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-15 16:39
    @ericball

    Thanks for looking this over. I let this system log data overnight (>1300 samples) and the only error I got was the one above. So I'm really confused as to where this comes from. I can tell you that the system reports the time at which it rings the bell and it reports that it rang early. I only mention this because total seconds is derived from that same string. The current GPS time is provided as a string. The conversion there there is pretty straight forward:
    pseudo code:
    current_time := string2int(HHMMSS)
    HH := current_time /10_000
    MM := ( current_time / 100 ) // 100
    SS := current_time // 100
    total_seconds := HH * 3600 + MM * 60 + SS

    I assumed that was correct, but I'll have to look at it more carefully. I've got a number of repeat loops watching and reading things. Since the GPS time changes every second it's possible I'm grabbing it one reason now then grabbing it again a short time later for a different reason. I guess it's possible that every once in a while I grab it on either side of a new second.

    Thanks,
    Peter
  • whickerwhicker Posts: 749
    edited 2009-06-15 16:43
    is the method that is grabbing the time from the GPS unit consistent across characters, specifically "point in time" consistency?

    What I am saying, is that can the time string returned, since you are the once calculating seconds, change in the middle of being sent or doing the calculation?

    example time:
    >1:44.59
    >1:45.00

    time read:
    1:44.50
    (read "1:44.5" then the time advanced one second, then read the "0")

    This kind of thing is extremely common (and annoying).
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-15 17:04
    @whicker

    That might be the issue. I'll have to redo some code and then check it. I didn't suspect this earlier because out of 1330 attempts, I only got one wrong answer. I wouldn't call that very common, but I'm not sure it ISN'T happening. To be quite honest, I'm not sure I can prevent it from happening. I say that because I'm using one cog of the Prop to parse the GPS NMEA string and store things in memory. I'm using a different cog to manage the buttons, display, and the countdown. Being in separate cogs they run independently and therefore I'm not sure I can prevent one cog from asking "What time is it" while the GPS is updating the cog.

    I'll have to think about this. I suspect this is the problem, but I'm not sure how to solve it.
    Thanks for the input.
    Peter
  • Mike GreenMike Green Posts: 23,101
    edited 2009-06-15 17:17
    That's what the LOCKxxx instructions are for. The cog that's parsing the NMEA strings and storing the time in memory can set a lock while it's changing the stored time. The other cog that refers to the stored time can then wait until the stored time is formatted correctly before trying to access it. Read the sections in the Propeller Manual for details.
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-16 17:08
    @Mike-

    Thanks for the suggestions. I've looked over that section of the manual and I'm sure that would prevent me from reading a portion of memory which is being written to by another cog. Maybe it's poor coding on my part, but implementing that was going to be difficult. I !think! I've found a solution. I know when the NMEA messages come from my GPS engine relative to the 1PPS it generates. So I've forced the code not to read from the NMEA data in prop while the prop is busy reading the NMEA messages. Although it doesn't use the LOCKxxx instructions, effectively this is the same thing but, for this project, was pretty easy to institute.

    I ran the unit overnight with no problems (~1300 instances). I'll run it a few more days to see if it hiccups for another reason.

    Thanks to all for pointing out something that should have been obvious to me. Lesson learned (I hope.).

    Peter
  • Mike GreenMike Green Posts: 23,101
    edited 2009-06-16 17:41
    We're talking here about what's called "multi-processing" where multiple CPUs are sharing some kind of common resources (usually memory or I/O). This has been around for a long time and is well understood. There are ways to share data without using a lock (semaphore), mostly what's called the single-producer / single-consumer case. Pretty much everything else needs a lock. The fact that a problem doesn't show up doesn't say anything about whether it will eventually. I don't mean to make this all sound more complicated than it really is, but multi-processing is something you can't wave your hands at. You have to have a clear idea of what you're trying to do and how you're trying to solve the timing issues.
  • pgbpsupgbpsu Posts: 460
    edited 2009-06-16 18:14
    @Mike

    I appreciate your concern and words of wisdom. I'm aware of the "responsibility" that comes with multi-processing. In fact it something I've dealt with a few times already. I somehow overlooked it in this case. To the the forum members credit, they (including you) picked up on it right away. Clearly using LOCKxxx would prevent attempts by different parts of the program from reading/writing areas of memory at the same time. I believe what I've done without LOCKxxx is functionally the same albeit using an external source. I recognize the risk in this. So I'll have another look at implementing the LOCK system. The code has already been altered and including the LOCKxxx instructions as a final safety measure may now be possible.

    You did raise one concern. "The fact that a problem doesn't show up doesn't say anything about whether it will eventually." Doesn't the deterministic nature of the Prop give one confidence that if steps A,B, and C work now, they will work tomorrow? No one is moving things around in memory, delaying access to resources, or interrupting it so why would something that works now, not work later if the external circumstances haven't changed? I hope I don't fundamentally misunderstand something? I don't think this is cause for reckless coding or abandonment of error checking. I realize that external circumstances do change and the code should handle that gracefully. For example, if my GPS engine dies, my alarm clock shouldn't start ringing constantly. I'd prefer it not ring at all, or more usefully, it should ring with a unique sound to alert me that the gps signal is missing. But there's no amount of coding that will make up for a missing time signal.

    I'll let you know how that goes.

    Regards,
    Peter
  • heaterheater Posts: 3,370
    edited 2009-06-16 18:34
    Yes the deterministic nature of the Prop gives us confidence in many things.

    Depending on the nature of your program, how big it is, how well you understand it's interactions you may need to worry or not. Thing is, if there is a potential race condition (simultaneous read/write to same data causing corruption) it quite often does not show up in any amount of testing. Oh no, it waits till it's out in the field and something unexpected happens. Some input is early, or late, or some calculation gets an input that causes it to take longer than normal, whatever.

    Or, perhaps more importantly sometimes, your program works fine. Until one day, possibly months after you have written it and hence have forgotten half the trick timing issues, you have to make some small changes. Bang it stops working, or works erratically. Just because some timing got moved around a bit or a particular interaction was overlooked.

    Been there, done all that. I like to wear a belt and braces now if I'm going out in public[noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
Sign In or Register to comment.