PDA

View Full Version : rotate bytes in array



Art
- 13th March 2012, 23:23
Hi Guys,
I want to rotate all bytes (bytewise) in an array of 30 bytes so that the oldest value in the array is discarded
from one end, and a new value is placed in the other end, and the new value should be the last to be discarded.

A seemingly simple problem driving me nuts!
Something like this would just copy the new value to all bytes:

FOR gcnt = 0 TO 29 '
vmean[gcnt+1] = vmean[gcnt] '
NEXT gcnt '

Any help appreciated.
Cheers, Brek.

Art
- 13th March 2012, 23:38
Something like this:

ii = 29 '
FOR gcnt = 1 to 29 '
vmean[ii] = vmean[ii - 1] '
ii = ii - 1 '
NEXT gcnt '
'
vmean[0] = newvalue '


(I think is right)

languer
- 14th March 2012, 00:02
Seems right. Out of curiosity, what are you using this for?

Art
- 14th March 2012, 00:31
Adding a new voltage reading every second to calculate a new mean voltage over thirty seconds for a low voltage cutout.

Demon
- 14th March 2012, 01:54
Why not:


FOR ii = 29 TO 1 STEP -1
vmean[ii] = vmean[ii - 1]
NEXT ii

vmean[0] = newvalue

I don't have the manual nearby, but I'm pretty sure we can go backwards.

Robert

MikeWinston
- 14th March 2012, 02:39
instead of a for/next shift, how about a in-place overwrite. (instead of shifting the data, shift the index variable.)

index = 0

Loop:
adResult = {...new voltage value}

arraySum = arraySum - arr[index]
arr[index] = adResult
arraySum = arraySum + adResult

if index = 29 then
index = 0
else
index = index + 1
endif

goto Loop


Mike -

Art
- 14th March 2012, 02:48
Mike, is the compile size smaller?
I can't really check in my project because it appears code is being fragmented over several pages
after I crossed the first boundary.

Robert, Didn't know you could use a STEP -1 directive,
but if it works, it's shorter, and saves a useless byte.

It appears to be working nicely, but I will shorten it if possible.
It's for my car computer I've posted about here before.
With the vehicle running, the voltage reading is live.
With the engine stopped, but accessories relay on,
the stereo amplifiers tend to cause the voltage to jump around (understandably).
The thirty second average is then displayed and acted on to turn accessories off if the average is too low.

MikeWinston
- 14th March 2012, 02:56
Art,
don't know if it's smaller. i was going for speed rather than code size.

Mike -

languer
- 14th March 2012, 05:33
Adding a new voltage reading every second to calculate a new mean voltage over thirty seconds

I was thinking along the lines of what instead of what Tachyon wrote

a for/next shift, how about a in-place overwrite. (instead of shifting the data, shift the index variable.)


But, perhaps you want to look at rolling averages...
http://www.pbpgroup.com/modules/wfsection/article.php?articleid=7
http://www.picbasic.co.uk/forum/showthread.php?t=12183
http://www.picbasic.co.uk/forum/showthread.php?t=8046
http://www.picbasic.co.uk/forum/showthread.php?p=41702
http://www.picbasic.co.uk/forum/content.php?r=248-Analog-to-digital-averaging-with-hysteresis

Demon
- 14th March 2012, 17:12
...Robert, Didn't know you could use a STEP -1 directive,
but if it works, it's shorter, and saves a useless byte...


Yup, got off my lazy butt and got the manual, it's in there.

So far our score in PBP knowledge:
Robert 1 .... Art 56,743

:D

LinkMTech
- 14th March 2012, 17:20
Guys,
May not be the solution for Art's project, but this post interested me because I was also stumped trying to shift bytes of data FIFO and ended up making something work for me.
I liked the FOR/NEXT approach given here and thought I would try it since it looked faster and smaller since I'm really collecting 32 bytes instead of 12 in this example.

My kludge: This scheme uses 24 words and takes 12.5us


DEFINE OSC 8

RX VAR BYTE ' Buffer data
XYZ_val VAR BYTE[12] ' Accelerometer XYZ data
TC_OUT VAR PORTC.4 ' Test point to measure loop time

Load_array:
TC_OUT = 1
XYZ_val[0] = XYZ_val[1] ' Oldest data
XYZ_val[1] = XYZ_val[2]
XYZ_val[2] = XYZ_val[3]
XYZ_val[3] = XYZ_val[4]
XYZ_val[4] = XYZ_val[5]
XYZ_val[5] = XYZ_val[6]
XYZ_val[6] = XYZ_val[7]
XYZ_val[7] = XYZ_val[8]
XYZ_val[8] = XYZ_val[9]
XYZ_val[9] = XYZ_val[10]
XYZ_val[10] = XYZ_val[11]
XYZ_val[11] = RX ' Newest data
TC_OUT = 0
RETURN


Was surprised to to find that this scheme uses 43 words and takes 216us:


DEFINE OSC 8

RX VAR BYTE ' Buffer data
XYZ_val VAR BYTE[12] ' Accelerometer XYZ data
TC_OUT VAR PORTC.4 ' Test point to measure loop time


Load_array:
TC_OUT = 1
FOR z = 0 to 10
XYZ_val[Z] = XYZ_val[Z+1]
NEXT z
XYZ_val[11] = RX
TC_OUT = 0

RETURN


It meant more typing but saved some space and time.

Demon
- 14th March 2012, 19:02
...It meant more typing but saved some space and time.


I'm not surprised at all. We quickly forget that FOR-NEXT commands are a combination of ADDs, IFs and GOTOs in the background. The only problem is that the compiler has to make it generic to work for many circumstances; like the STEP -1 example. So now it has to include SUBTRACTs as well, that generates even more code whether you need it or not.

I'm simplifying, but that's pretty much it.

I use the simplified commands 'cause I haven't run out of space yet, and speed hasn't been an issue yet either. But if I ever reach that point, that's when I start breaking them down to their basic elements.

Robert
:)

EDIT: Assembler class was back in '78-'83 era, yeesh...

LinkMTech
- 14th March 2012, 19:16
Thanks for the insight Robert.
The PBP simplified commands are the very reason I started "programming" especially after seeing the difference Bruce gives on his site (http://www.rentron.com/PicBasic2.htm).

My PIC16F1823 is nearing the end with 2020 words used and just happened to need the space and faster time. Plus it was just rewarding to figure this out on my own and thought I'd share a little for some other newbie out there.

Art
- 14th March 2012, 22:31
So far our score in PBP knowledge:
Robert 1 .... Art 56,743
I wouldn't say that, and you might not if you saw what my code looks like when only written for myself!

I'll end up using it because that part of the program can be slow, so I'd rather it tight.
Just had to remember to fill up the array with an acceptable value at initialisation so the low voltage cutout
doesn't kick in straight away (values start out all zeros), so I initially fill the array with the first stable voltage reading.

Acetronics2
- 15th March 2012, 09:24
Hi, Art

a good question to ask : do you need to store the 30 values for another purpose than calculate your mean value ???

because @ each measurement you could calculate:

new_meanval = (old_meanval*29 + last_measure) /30 ... which gives you the mean value over the 30 lasts measurements ! ( called "rolling average", if I'm right )

note here 32 measures would be best for dividing time ! so :

new_meanval = (old_meanval*31 + last_measure) >> 5 ...

I think Darrel posted a while ago a nice routine about that ...

I remember he also posted about a 48 level stack ... may be ideas to take there ...

Alain

Art
- 15th March 2012, 10:02
Yes, the device is also a car alarm that is triggered by internal lights that come on when the vehicle door is opened.
The line is 12 Volts live until a door is opened & a resistor divider provides 5 Volts for the pic's input.
If ever I get a false alarm, I want to save the last thirty seconds voltage readings to see if I can prevent it.

When the car battery goes cactus my alarm might also sound since the resistor divider is at the unregulated side,
and may not produce the voltage for logic high at the pic pin.

I could have the program look at the last thirty seconds values to prevent these false triggers.

amgen
- 15th March 2012, 15:03
from your decription, the alarm part could be done with 1's and 0's, door opened/closed, no a/d overhead, just digital pin, "0" at < 2.5volts and "1" > about 2.5volts. No help checking batt voltage though...??
Don

Demon
- 15th March 2012, 18:19
Yes, the device is also a car alarm that is triggered by internal lights that come on when the vehicle door is opened.
...


Just a technicality; I'd feed directly from the door switch, not the lamp itself. You could have forgotten the interior lamp switch in the OFF position, the lamp could be burnt, or the robbers might know this trigger; they could just break the window, turn off the lamps and open the door.

I know it's highly unlikely, but it would make your device even better. :)

Robert

Art
- 15th March 2012, 22:59
It does get it's input from the door switch :)
It's live until any door is opened, then it is earthed.
That is why I might get a false trigger as the batteries die.