Hi,
I want to scale an incoming byte 00 - FF into a smaller range of
values so that 00 still is 00 but FF gets cut down to say 28h with
all the values in between filled in. I though of a few ways to do it;
1) Divide by a constant & round the result.
Maybe the best but I may need to change the curve of the scaling.
2) A 256 byte table.
Very definable but large & a pain to change scale.
3) Lots of compares.
Changeable points but woefully long & ugly.
I may need a few different scales in this application so does anyone
have any brilliant ideas on the the best way? Maybe there is another
solution that I've missed?
Regards...
Hi,
if not simple rotate will be sufficient ( i.e. scale
by 1/2, 1/4 etc ) then try out the code generator on the
piclist site, here what came with scaling to 0xFF->0x28:
; ACC = ACC * 0.156863
; Temp = TEMP
; ACC size = 8 bits
; Error = 0.500000%
; Bytes order = little endian
; Round = no
; ALGORITHM:
; Clear accumulator
; Add input / 8 to accumulator
; Add input / 32 to accumulator
; Move accumulator to result
;
; Error in constant approximation : 0.390596, %
; Input: ACC0 (8 bits)
; Output: ACC0 (6 bits)
cblock
ACC0
endc
;copy accumulator to temporary
movf ACC0, w
;shift accumulator right 2 times
clrc
rrf ACC0, f
clrc
rrf ACC0, f
;add temporary to accumulator
addwf ACC0, f
;shift accumulator right 3 times
rrf ACC0, f
clrc
rrf ACC0, f
clrc
rrf ACC0, f
Tony Kübek, Flintab AB
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
E-mail: spam_OUTtony.kubekTakeThisOuTflintab.com
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
>Hi,
>I want to scale an incoming byte 00 - FF into a smaller range of
>values so that 00 still is 00 but FF gets cut down to say 28h with
>all the values in between filled in. I though of a few ways to do it;
>1) Divide by a constant & round the result.
> Maybe the best but I may need to change the curve of the scaling.
>2) A 256 byte table.
> Very definable but large & a pain to change scale.
>3) Lots of compares.
> Changeable points but woefully long & ugly.
>I may need a few different scales in this application so does anyone
>have any brilliant ideas on the the best way? Maybe there is another
>solution that I've missed?
>Regards...
Do an 8x8 Multiply with a constant and use the high byte of the
result. Think of the constant as a fraction of 256, e.g. to scale the input to
30%, multiply by (30% of 256), i.e. 77 dec (rounded to nearest).
Welcome to the world of fixed-point arithmetic!
-- http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
> I want to scale an incoming byte 00 - FF into a smaller range of
> values so that 00 still is 00 but FF gets cut down to say 28h with
> all the values in between filled in. I though of a few ways to do it;
> 1) Divide by a constant & round the result.
> Maybe the best but I may need to change the curve of the scaling.
> 2) A 256 byte table.
> Very definable but large & a pain to change scale.
> 3) Lots of compares.
You don't say what machine you're on, how critical code space is, and how
critical execution speed is. I think there are two basic solutions, a table
and a fixed point multiply.
Since you are multiplying by a number less than 1, this works well when
expressed in fixed point with 8 fraction bits. Multiplying this value by
the original byte yields the scaled value in the high byte. This solution
is especially attractive if you are on a machine with a hardware multiplier.
The table is more general and probably the fastest solution if you don't
have a hardware multiplier, but it can eat up code space. However, note
that you don't need to index into the table with all 8 input bits. If the
result is only in the 0 - 40 range you should look at using only the high 6
bits of the input value as the table index for exapmle. I like to use
assembler loops to write such tables for me. It prevents error in typing in
individual values, and it makes it simple to change the overall scale or
whatever of the table if needed.
I prefer to cut-and-paste from a spreadsheet for tables. That way you can
get real fancy with the calculations, then make a column in the spreadsheet
where the values are all scaled and rounded just the way you need them to
make the PIC computations as simple as possible.
I've got some radio code with a whole slew of tables for frequency selection
and modulation patterns and stuff. Whenever the RF boys change their minds,
I just mess around with the spreadsheet a little, cut-and-paste, and voila!
I have new code faster then they can make up their minds about the next bout
of changes.
> assembler loops to write such tables for me. It prevents
> error in typing in
> individual values, and it makes it simple to change the
> overall scale or
> whatever of the table if needed.
>
>
> *****************************************************************
> Olin Lathrop, embedded systems consultant in Devens Massachusetts
> (978) 772-3129, olinKILLspamcognivis.com,http://www.cognivis.com
>
> --
> http://www.piclist.com hint: The PICList is archived three different
> ways. See http://www.piclist.com/#archives for details.
>
>
>
>
Olin wrote:
> > I want to scale an incoming byte 00 - FF into a smaller range of
> > values so that 00 still is 00 but FF gets cut down to say 28h with
> > all the values in between filled in. I though of a few ways to do it;
> > 1) Divide by a constant & round the result.
> > Maybe the best but I may need to change the curve of the scaling.
> > 2) A 256 byte table.
> > Very definable but large & a pain to change scale.
> > 3) Lots of compares.
>
>You don't say what machine you're on, how critical code space is, and how
>critical execution speed is. I think there are two basic solutions, a table
>and a fixed point multiply.
Sorry, forgot to say it's on a 16F876 but may have to jam it into a 16F628
whenever they get released and readily available. (or even a 16F84A)
Not sure how much code space I will need - still early days yet. Execution
needs to be fairly quick as there is the possibility of multiple commands
arriving from the host system in quick succession.
>Since you are multiplying by a number less than 1, this works well when
>expressed in fixed point with 8 fraction bits. Multiplying this value by
>the original byte yields the scaled value in the high byte. This solution
>is especially attractive if you are on a machine with a hardware multiplier.
I've never needed to do math before in a PIC - might be time to learn!
>The table is more general and probably the fastest solution if you don't
>have a hardware multiplier, but it can eat up code space. However, note
>that you don't need to index into the table with all 8 input bits. If the
>result is only in the 0 - 40 range you should look at using only the high 6
>bits of the input value as the table index for exapmle. I like to use
>assembler loops to write such tables for me. It prevents error in typing in
>individual values, and it makes it simple to change the overall scale or
>whatever of the table if needed.
I think the table is probably the most quick & portable solution as present.
Just have to brush up on those page boundary crossing details. :-)
Regards...
> I think the table is probably the most quick & portable solution as present.
> Just have to brush up on those page boundary crossing details. :-)
> Regards...
>I prefer to cut-and-paste from a spreadsheet for tables.
Having been playing with VBA recently in Excel, I suspect you could persuade
your spreadsheet to write an include file at the push of a button, which would
speed the process up even further (once you had the VBA written, but that would
be a case of slightly modifying existing code for writing CSV files).
Then you could have the new code assembled before they have even stopped talking
about what they want ;))
> Hi,
> if not simple rotate will be sufficient ( i.e. scale
> by 1/2, 1/4 etc ) then try out the code generator on the
> piclist site, here what came with scaling to 0xFF->0x28:
David, you can write a small program that will calculate a 'hard way'
mapping (scaling) using direct PIC code output if you want. It is very
much like the other table analysis example I gave. The output code outline
is:
1. Set acc = highest output code
2. compare input to the input step from table (that causes an output change)
if above, done, return acc
3. apply some operation to the acc using data from table or not (e.g.
shift right or substract)
4. select next table entry, and continue from 2
if no more table entries, return acc (which should be lowest output value)
This is a basic mapping function implemented 'a la pic' because on almost
any other machine you'd use some sort of lookup table instead. If you use
C code and can afford floats then you can try to write a function that
scales as you wish and see what the compiler produces from it. Otherwise
you can use a float function and then re-implement it using integer
arithmetic (some skill required) to reduce code size. I suspect that the
table will be less than 64 locations (32 values). This makes for a pretty
good approximation for most human-related purposes (inexpensive
logarythmic volume potentiometers can have the log curve approximated by
only 4 straight segments !).
The table can be computed by an auxiliary program described as above (in
the 1st paragraph of this mail) running on a PC.
>> Um. Good point. What's the right term for "infinite length non-repetitive
>> rational numbers"?
>
>As Olin said, there's no such thing - by definition.
I think you call them non-terminating decimals. Note that
'decimals' doesn't mean all that much to a piece of
base-two hardware (and "nice" numbers like 0.1 drive
it crazy! They don't terminate in binary....)
> And anyway, who said I was talking about the number? :)
>
> On Wed, 1 Nov 2000, Olin Lathrop wrote:
>
> > Date: Wed, 1 Nov 2000 15:42:44 -0500
> > From: Olin Lathrop <TakeThisOuTolin_piclistspamCOGNIVIS.COM>
> > Reply-To: pic microcontroller discussion list <PICLISTEraseMEMITVMA.MIT.EDU>
> > To: RemoveMEPICLISTEraseMEspam_OUTMITVMA.MIT.EDU
> > Subject: Re: [PIC]: Scaling down from 00 - FF
> >
> > > 40/255=.15686... (probably irrational)
> >
> > No. Irrational numbers, by definition, are those that CAN'T be
> Not sure how Olin got this, but here is some thoughts on the matter:
>
> 255 can be expressed as prime factors as 5*3*17
>
> I wonder if that 17 has something to do with it?
>
> {Original Message removed}
> Um. Good point. What's the right term for "infinite length non-repetitive
> rational numbers"?
There is no such thing because all rational numbers will repeat in a finite
number of digits. Arbitrary real numbers do not, or you could say
"irrational" to specifify that particular subset of real numbers that are
not rational.
> > Not sure how Olin got this, but here is some thoughts on the matter:
> >
> > 255 can be expressed as prime factors as 5*3*17
> >
> > I wonder if that 17 has something to do with it?
> >
> > {Original Message removed}
> Date: Thu, 2 Nov 2000 10:53:40 -0600
> From: Scott Dattalo <.....scott@spam@EraseMEDATTALO.COM>
> Reply-To: pic microcontroller discussion list <.....PICLISTRemoveMEMITVMA.MIT.EDU>
> To: .....PICLISTSTOPspam@spam@MITVMA.MIT.EDU
> Subject: Re: [PIC]: Scaling down from 00 - FF
>
> On Thu, 2 Nov 2000, Olin Lathrop wrote:
>
> > > Not sure how Olin got this, but here is some thoughts on the matter:
> > >
> > > 255 can be expressed as prime factors as 5*3*17
> > >
> > > I wonder if that 17 has something to do with it?
> > >
> > > {Original Message removed}
> Wow, I will need to ponder.
>
> So do you think this behavior is independent of conversion base, i.e.
> x/255 is no more than 17 digits even in binary, octal, base 1e17?
>
> If so, can we postulate that any rational number can be expressed as
> 'prime factor' repeating digits if written in the appropriate base?
>
> Then 1/bigprime in base X yields psuedo-random sequence of length bigprime
> in range 0 to X-1... potential for crypto system? Very cool, in any case.
>
> BTW, I can't find any examples where x/y yields y repeating digits (where
> y is prime), the best I can do is y-1, are you sure it's not 'prime factor
> minus 1'?
You are right. The maximum number of digits in the repeating sequence
representing 1/y is y - 1. Think of this as doing repeated integer divides
with the remainder of from one digit feeding the numerator value for the
divide of the next digit. In that case, there are only Y possible
remainders, make at most Y possible "states" in the repeating sequence.
However, if the remainder ever becomes 0, then the sequence terminates (no
error left, number represented exactly) instead of repeating infinitely.
There are therefore at most Y-1 possible "states" in such a repeating
sequence. This also shows that this is independent of the number base.
Lets do 1/7 in decimal as an example:
1/7 = 0 remainder 1, so the 1s digit is 0. So far: 0.
take remainder 1 times the radix for numerator: 10/7 = 1 rem 3. So far 0.1
30/7 = 4 rem 2: 0.14
20/7 = 2 rem 6: 0.142
60/7 = 8 rem 4: 0.1428
40/7 = 5 rem 5: 0.14285
...
As you can see, the only "state" between digits is the remainder, which is
always an integer from 1 to 6. This sequence therefore must repeat in 6
digits or less. This particular one happens to take 6 digits in base 10.
The same thing works in any radix. Here is the same example in base two:
1/7 = 0 rem 1: 0.
2/7 = 0 rem 2: 0.0
4/7 = 0 rem 4: 0.00
8/7 = 1 rem 1: 0.001
at which point the sequence repeats because we have already encountered a
remainder of 1 before.
> As you can see, the only "state" between digits is the remainder, which is
> always an integer from 1 to 6. This sequence therefore must repeat in 6
> digits or less. This particular one happens to take 6 digits in base 10.
Thanks Olin, well said and now makes perfect sense :)