Note that there are some explanatory texts on larger screens.

plurals
  1. POGenerating Logarithmically Spaced Values on an Operation Limited Microcontroller
    primarykey
    data
    text
    <p>I've recently come across a problem where, using a cheap 16 bit uC (MSP430 series), I've had to generate a logarithmically spaced output value based on the 10 bit ADC read. The reason for this is that I require fine grain control at the low end of the integer space, while, at the same time, requiring the use of the larger values, though at less precision, (to me, the difference between 2^15 and 2^16 in my feedback loop is of little consequence). I've never done this before and I had no luck finding examples online, so I came up with a little scheme to do this on my operation-limited uC. </p> <p>With my method here, the ADC result is linearly interpolated between the two closest integer powers-of-two via only integer multiplication/addition/summation and bitwise shifting, (outlined below).</p> <p>My question is, is there a better, (faster/less operations), way than this to generate a smooth, (or smooth-ish), set of data logarithmically spaced over the integer resolution? I haven't found anything online, hence my attempt at coming up with something from scratch in the first place.</p> <p>N is the logarithmic resolution of the micro controller, (here assumed to be 16 bit). M is the integer resolution of the ADC, (here assumed to be 10 bit). ADC_READ is the value read by the ADC at a given time. On a uC that supports floating point operations, doing this is trivial: </p> <pre><code>x = N / M #16/1024 y = (float) ADC_READ / M #ADC_READ/1024 result = 2 ^ ( x * y ) </code></pre> <p>In all of the plots below, this is the "Ideal" set of values. The "Resultant" values are generated by variations of the following:</p> <pre><code>unsigned int returnValue( adcRead ){ unsigned int e; unsigned int a; unsigned int rise; unsigned int base; unsigned int xoffset; unsigned int yoffset; e = adcRead &gt;&gt; 6; a = 1 &lt;&lt; e; rise = ( 1 &lt;&lt; (e + 1) ) - ( 1 &lt;&lt; e ); base = e &lt;&lt; 6; xoffset = adcRead - base; yoffset = ( rise &gt;&gt; rise_shift ) * (xoffset &gt;&gt; offset_shift); //this is an operation to prevent rolling over. rise_shift + offset_shift = M/N, here = 6 result = a + yoffset; return result; } </code></pre> <p>The extra declarations and what not are for readability only. Assume the final product is condensed. Basically, it does as intended, with varying degrees of discretization at the low end and smoothness at the high end based on the values of rise_shift and offset_shift. Here, they are both equal to 3: <img src="https://i.stack.imgur.com/ZxZgz.png" alt="rise &gt;&gt; 3, offset &gt;&gt; 3"> Here rise_shift = 2, offset_shift = 4 <img src="https://i.stack.imgur.com/x4CEh.png" alt="rise &gt;&gt; 2, offset &gt;&gt; 4"> Here rise_shift = 4, offset_shift = 2 <img src="https://i.stack.imgur.com/4R7Ft.png" alt="rise &gt;&gt; 4, offset &gt;&gt; 2"> I'm interested to see if anyone has come up with or knows of anything better. Currently, I only have to run this code ~20-30 times a second, so I obviously have not encountered any delays. But, with a 16MHz clock, and using information from <a href="http://www2.ife.ee.ethz.ch/~roggend/publications/wear/DSPMic_v1.1.pdf" rel="nofollow noreferrer">here</a>, I estimate this entire operation taking at most ~110 clock cycles, or ~7us. This is on the scale the ADC read time, which is ~4us. </p> <p>Thanks</p> <p>EDIT: By "better" I do not necessarily just mean faster, (it's already quite fast, apparently). Immediately, one sees that the low end has fairly drastic discretization to the integer powers of two, which results from the shifting operations to prevent roll-ever. Other than a look-up table, (suggested below), the answer to how this could be improved is not immediate. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload