pow(a,b) - Page 1
Forum section: electronics / general

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2021, 05:50:49 am
content: Given two real (floating point or fixedpoint), `a` and `b`, where `b` can be negative, how to efficiently compute the power function `pow(a, b)` ?Mathematically, it's required to compute pow(a, b)=exp(b*ln(a))I have to implement it in C, and then, I have to rewrite it in assemblyedit: Typo: a^b.a,b are real numbersb can be negative.

author: bpiphany
author_rank: Regular Contributor
timestamp: March 05, 2021, 07:46:55 am
content: Aren't Taylor series and Newton-Raphson's method the answer to most computations on irrational functions?Also, google is your friendhttps://stackoverflow.com/questions/4518011/algorithm-for-powfloat-floathttps://stackoverflow.com/questions/9799041/efficient-implementation-of-natural-logarithm-ln-and-exponentiation/44232045

author: Zero999
author_rank: Super Contributor
timestamp: March 05, 2021, 11:21:29 am
content: Other than for a learning exercise, the answer normally is to use the compiler's floating/fixed point library and a powerful enough CPU, with sufficient memory, to handle it.

author: newbrain
author_rank: Super Contributor
timestamp: March 05, 2021, 12:14:07 pm
content: Quote from: DiTBho on March 05, 2021, 05:50:49 amAnd 'n' would be? Is it 'a' or 'b'?As it makes quite a complex difference (pun totally intended).

author: T3sl4co1l
author_rank: Super Contributor
timestamp: March 05, 2021, 03:00:19 pm
content: b being negative isn't an issue, that's just fractional division rather than multiplication, and the definition of the exponent function provides continuity. Surely, a being negative is the bigger problem -- fractional powers are imaginary but integer powers are just fine?https://en.cppreference.com/w/c/numeric/math/powTim

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 05, 2021, 04:47:25 pm
content: Quote from: DiTBho on March 05, 2021, 05:50:49 amI suppose you're not allowed to use the C std math library, because it's all there already. And if you have access to a compliant C compiler, there's no reason you wouldn't have access to this library.So I'm assuming it's just an exercise. Or maybe you're looking for something more efficient (in which case, have you benchmarked the standard pow() function already to know what you'd be competing against?)You can take a look at the following implementation in openlibm:https://github.com/JuliaMath/openlibm/blob/master/src/e_pow.c

author: rstofer
author_rank: Super Contributor
timestamp: March 05, 2021, 05:27:12 pm
content: Quote from: SiliconWizard on March 05, 2021, 04:47:25 pmThat code doesn't look like a homework assignment. I can imagine a team of Applied Math PhDs sitting around discussing the boundary conditions for weeks. Then they spend even more time coming up with the algorithm for the programmer to code. There's some magic math in that code.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 05, 2021, 05:37:13 pm
content: Quote from: rstofer on March 05, 2021, 05:27:12 pmDefinitely. But it gives the basic calculations they use, so that can serve as an inspiration for implementing the same, even if you end up with something a lot less optimized.Now I don't know if the OP's question was actually a homework assignment. If it was, then giving them a "homework assignment" directly usable answer would not do them any favor IMHO. And I also don't know what the value of such an assignment would be. If it were a programming assignment, then I don't really see the point of using anything else than the std pow() function. But if it were an applied math assignment, then it would be interesting, but in this case I would expect the students to at least have a rough idea of what kind of approach they can use to get an approximation of this function.

author: hamster_nz
author_rank: Super Contributor
timestamp: March 05, 2021, 07:27:04 pm
content: BKM might be useful. It is a bit difficult to grok though.https://en.m.wikipedia.org/wiki/BKM_algorithm

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2021, 08:16:17 pm
content: Quote from: SiliconWizard on March 05, 2021, 04:47:25 pmKind of personal challenge for which I will have to rewrite it in pure assembly in order to fit a very old CPU with limited resources.Crazy, I knowIt's done for a larger hobby project, where for historical reasons I want to support all the technology I encountered during the last 25 years of my job and hobby experiences, so in the main big project there are several and different pieces of technology, including things used in the 80s, 90s, 2000s, 2010s and 2020s.For the piece of the puzzle belonging to the 80s, I chose to use a very very old MPU to realize a height sensor, which is used in a part of the big project; in its planned scheme done onLabviewas "proof of concept" between the CPU and the analogical sensor,Data linearizationis done using thenonlinear curve fitting method, which requires three pow(a,b) calculations like:h = K1*pow1(a1,b1) + K2*pow2(a2,b2) + K3*pow3(a3,b3) + qa1,a2,a3 come from ADC sampling, so the final functionality will be height = function(ADC sampled value).b1,b2,b3,k1,k2,k3 come from a wizard functionality offered by Labview to synthesize an interpolator.The CPU is clocked at 2Mhz, it's very slow and limited compared to a modern MPU, there are no time-critical constraints but rather ram-rom-space constraints, since there is only 768 byte of RAM, 1Kbyte of UV-EPROM for the whole program, which should also do other stuff, like talking on the serial line, sampling data on two analog channels, properly filter data, and handling two digital lines to control a couple of motors.The current firmware is already written in assembly. The pow(a,b) will be written in C, then translated into assembly, deep studied, and finally rewritten from scratch in assembly.

author: iMo
author_rank: Super Contributor
timestamp: March 05, 2021, 08:45:30 pm
content: There is certainly a floating point library in asm (or binary) written for a similar MCU (ie from the same family but with larger rom) available.. For example a 32bit floating point lib (incl. sin, cos, tan, exp, ln, pow..) is usually ~3.5kB large with those 8bitters MCUs.. Even I doubt you would be able to cut a bigger chunk off the lib such it fits into your 1kB incl your other stuff..In past 1kB was enough for a complete 8-9digits floating point math in vintage scientific calculators - but those MCUs were of a different arch (BCD instead of BIN)..

author: T3sl4co1l
author_rank: Super Contributor
timestamp: March 05, 2021, 10:14:24 pm
content: Does LabVIEW not produce integer coefficients (a simple polynomial fit)?If not, you will find precisely because of this, why it is cheaper to do so. On a machine with hardware multiply, it's just a matter of pulling down parameters and chugging, on loop (Horner's method); without, it's calls/jumps to a multiplication routine (typically shift and accumulate). If you can constrain LabVIEW to produce results of this form, you will have a much easier -- and faster -- time.There are also rational approximation methods (https://en.wikipedia.org/wiki/Pad%C3%A9_approximant), which on an add-shift machine, might be competitive with polynomial methods -- division is a shift-subtract algorithm, taking similar time to multiplication but fewer terms may be necessary.I suppose this isn't an excuse to wholly avoid implementing pow() -- but it can push off the need for it quite far, and indeed the same method, loaded with different coefficients, might serve to implement that very function, at least over a certain range, and the range (and selection of coefficients) can then be managed by an outside function.How many things are you looking to get into that MPU at once, anyway? And how much storage does it have accessible? If practically unlimited (e.g. parallel or SPI Flash chip, SD card*), how will you access and manage it? With so little ROM to work with, it seems likely that some kind of very basic, very general, interpreted language will be necessary. Perhaps even just to implement access to such things. Which means any real "thinking" (like evaluating pow()) will takevery longindeed -- fast enough for a handheld calculator perhaps, but doubtful for something like a control loop. Well, maybe like temperature control, there's a lot that can be done between seconds of samples. But besides that...*Probably not, at least not in the most convenient form -- FAT16 takes a few kB to implement I think, and is only good to a few hundred MB capacity (or a couple GB with some inconvenience); FAT32 takes a few kB more, and is good for pretty much whatever size is available these days. You might be able to access the SD card as a flat memory store, with less code, but not with FAT, and so you'll have to copy data to the SD card using some raw method (disk image, hex editor, etc.).Hmm, I wonder if you can format an SD card for FAT32 and place exactly one file on it, and have that file be at a consistent sector offset, no fragmentation, etc...Tim

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 05, 2021, 11:23:15 pm
content: Given the very limited resources, doing any FP might be extremely challenging - probably impossible. I'm assuming your old CPU doesn't have any FPU. Doing FP in software with this amount of memory? I doubt it.Anyway, it's probably what T3sl4co1l more or less suggested, but I would switch to piecewise linear interpolation instead of trying to compute those power functions. Just find a decent piecewise linear approximation of each power term. Then the only computation needed will be segment lookup, linear interpolation and additions. All this using integer/fixed-point arithmetic.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2021, 11:25:10 pm
content: What precision is your fixed or floating point? To what precision do you need the result? Do you have an FPU? How much program code size is OK to use? How much ROM is ok to use for tables? How much working RAM can you use?For example, if you are using any 8 bit fixed point or floating point format, and you can afford 64 KB of ROM, then you can get the most accurate possible result with one shift-and-OR and a memory load. BOOM!

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2021, 11:25:31 pm
content: Quote from: T3sl4co1l on March 05, 2021, 10:14:24 pmUnfortunately no. I get irrational coefficients.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2021, 11:37:13 pm
content: Quote from: DiTBho on March 05, 2021, 08:16:17 pmUgh.You're clearly not going to be aiming for a fast implementation. Just getting something to fit into that size at *all* will be challenging.It would have been useful to have this information at the outset.We still don't know what precision and range you need to work with, either for the inputs or the result.

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2021, 11:44:31 pm
content: Quote from: brucehoult on March 05, 2021, 11:25:10 pmI am trying to amplify the signal 4X in order to achieve better precision. The on board ADC is an 8bit unit working in the range of 5V (VRefL= 0V VRef_H= 5V), which means ~20mV5V/(255) is ~20mVBut! Since the measure range is 600..1300mm, I can isolate the corresponding sub voltage range, which is around 0V..1.2V, and can be 4X amplified by an OA.Still ~20mV, but if the analogical sensor is stable enough, this will produce better numerical results.Quote from: brucehoult on March 05, 2021, 11:25:10 pmNoQuote from: brucehoult on March 05, 2021, 11:25:10 pmAt the moment I am using 768 byte of ram in total, but I am ready to prepare a voltage pump in order to program the onboard UV-Eprom (1Kbyte).Quote from: brucehoult on March 05, 2021, 11:25:10 pm64Kbyte is impossible for my system. The best I can do is 32Kbyte for both RAM and ROM.

author: brucehoult
author_rank: Super Contributor
timestamp: March 05, 2021, 11:56:53 pm
content: Quote from: DiTBho on March 05, 2021, 11:44:31 pmBut what numeric range do you consider these 8 bit values to be in? Is it the same for A and B? And the result?Is B an arbitrary number, or is there only a limited set of possibilities that depend on the algorithm, not on the ADC data?Depending on your answers, you can very quickly find that most of the results are either 0 or infinity.

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2021, 10:25:23 am
content: Quote from: brucehoult on March 05, 2021, 11:56:53 pmthe built-in ADC is 8bit, with an equivalent bit noise of 1 bit after filtering, that means what you read and filter is truly 20mV of resolution. Filtering costs something like 200 cycles due to filtering window.The plan is converting the raw data from the ADC into floating-point/fixed-point, applies some interpolating functionQuote from: brucehoult on March 05, 2021, 11:56:53 pmValues "a" and "b" in the exp(a,b) function come from Labview, they are both real rumbers, and they require to be floatingpoint or fixedpoint, but I cannot yet qualify how many fractional bits they need because I am still playing with Labview in order to optimize those values.Quote from: brucehoult on March 05, 2021, 11:56:53 pmThere will be three "b" values, "b1", "b2", "b3", to be used in three "exp" function calls, but they are guaranteed to be constant (Labview says that), while "a" will be a kind of constant that multiply the value from the adc, kind of "a = k * adc_value"and you have to calculate exp(a,b), so exp ( k_const * adc_value, b_const)Quote from: brucehoult on March 05, 2021, 11:56:53 pmYup, including the LUT strategy, which seems more feasible although I haven't yet understood how to do it correctly

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2021, 10:35:03 am
content: This stuff is so impossible that I really wonder how Nasa did program the MPUs for the Apollo space missions. Theirguidance computerhas 2K words of erasable magnetic-core memory and 36 kilowords of read-only core rope memoryAnd this stuff has to do more tasks than just controlling the position of a vertically movable platform ... always impressed by those Big Guys!

author: brucehoult
author_rank: Super Contributor
timestamp: March 06, 2021, 11:02:49 am
content: Quote from: DiTBho on March 06, 2021, 10:35:03 amI'm sure you must be overthinking all of this. It must be able to be linearised or something over the values in the possible range. And especially only talking about 8 bit precision anyway.

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2021, 11:28:40 am
content: Quote from: brucehoult on March 06, 2021, 11:02:49 amHow can you be sure if you haven't seen anything?I wrote the above showed piece of code to acquire data and send them over the serial, so I sampled data within the range {15..1600}mm and put these samples inside a Labview's table, and when I click on the button it suggested a linearization model made with three pow(a,b), as I described above.It means, if you want to linerize theseQuoteYou need to implement this: h = K1*pow1(a1,b1) + K2*pow2(a2,b2) + K3*pow3(a3,b3) + qYou have to optimize a1,b1,a2,b2,a3,b3,q, but you will always have to deal with fpow, fmul, fadd, fand fcmpSo I tried to consider only the subrange of my interest, just to see if it somehow look "locally linear".QuoteUnfortunately, Labview says that it does not, and still suggest to synthesize two exp(a,b) functions.So we have just moved from thish = K1*pow1(a1,b1) + K2*pow2(a2,b2) + K3*pow3(a3,b3) + qto thish = K1*pow1(a1,b1) + K2*pow2(a2,b2) + q

author: paf
author_rank: Regular Contributor
timestamp: March 06, 2021, 01:51:13 pm
content: What is the precision/accuracy of the sensor?How did you get the data?This part of the data suggests there the sensor measurements are not "very accurate":Code:...0.50 130 cm0.45 150 cm0.44 140 cm...My suggestion is transform x into 1/x:Code:0,36364150,39216200,5300,64516400,8500,86957601,11111701,25801,33333901,538461001,666671101,818181202 1302,27273140This way you can get a more linear relation.

author: ledtester
author_rank: Super Contributor
timestamp: March 06, 2021, 02:08:40 pm
content: Quote from: DiTBho on March 06, 2021, 11:28:40 amMaybe I'm misunderstanding something, but have you tried piecewise curve fitting?For the above numbers you get a pretty good fit with quadratic curve fitting if you break up the input range into three intervals: [2.75 .. 1.55], [ 1.55 .. 1.15 ] and [ 1.15 .. 0.45 ].

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2021, 02:36:34 pm
content: Unfortunately the sensor doesn't have any good documentation.I don't know anything about its precision/accuracy.Code:_______/0..20Hz|sensor _____/ OA G=1 |_____ ADC 8bit _____ raw data over serial line\follower| CPU builtin\_______|This is what I am doing at the moment, and how I collected data to prepare the above tables.Quote from: ledtester on March 06, 2021, 02:08:40 pmNot yet. Good pointI have only tried the "NI myDAQ" curve fitting software offered by LabVIEW.The CPU reads the ADC, and sends raw data to the computer without any manipulation.The PC collects data and passes them to the myDAQ software.I am also preparing a similar working scenario for Octave + GNUplot.Quote from: ledtester on March 06, 2021, 02:08:40 pmNice! Thanks! Maybe breaking up the input range into several intervals is the best way to sort it out!Thanks, again, I hadn't thought about it yet

author: rstofer
author_rank: Super Contributor
timestamp: March 06, 2021, 04:36:30 pm
content: I think I would look at a polynomial curve fit and graph the actual and interpolated data. I don't know anything about Labview but Octave (or MATLAB) can do this with a single statement to any degree required.The link covers single polynomial fitting and spline fitting:https://octave.org/doc/v4.4.1/Polynomial-Interpolation.htmlIf the computation is to be done on the uC, all I would need to store in memory are the coefficients.Clearly, sending the raw data to the PC and using more powerful math tools will be a lot easier.

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2021, 05:32:55 pm
content: Just to consider alternatives, which sensor would you use to (contactless) measure a distance in the range of 60cm .. 130cm?

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 06, 2021, 05:52:18 pm
content: Quote from: DiTBho on March 06, 2021, 05:32:55 pmWhat kind of sensor are you considering in this thread? I may have missed it, but all I saw was "analog sensor". Just needs a bit of details so we don't suggest the same.For this range, ultrasonic sensors may be the cheapest and easiest approach? 5mm accuracy should be doable.Otherwise, you may consider time-of-flight sensors such as this:https://www.st.com/en/imaging-and-photonics-solutions/vl53l0x.html(not sure you'd manage 5mm accuracy with this though...)

author: DiTBho
author_rank: Super Contributor
timestamp: March 06, 2021, 06:19:01 pm
content: Quote from: SiliconWizard on March 06, 2021, 05:52:18 pmA sensor that without any contact can measure a distance in the range of 60cm .. 130cm.I am currently using a pure analogical optical reflective IR sensor.I really like thevl53l0xsensor. It's embedded, it's powerful, and it's very small. I think I will use one of these for other projects, thanks

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 06, 2021, 06:24:17 pm
content: Quote from: DiTBho on March 06, 2021, 06:19:01 pmThose are nice and reasonably cheap, but I'm not too sure they would yield the kind of accuracy you're looking for. Something to prototype though.

author: brucehoult
author_rank: Super Contributor
timestamp: March 07, 2021, 12:35:13 am
content: Quote from: DiTBho on March 06, 2021, 11:28:40 amExperience.QuoteWhat are the labels for the above columns? What is the input? What is the output? How does this relate to the formula? What on Earth are pow1, pow2, pow3?Clearly your data are not very accurate given the reversal of 0.44 and 0.45.QuoteIf you are dealing with fpow at runtime on the microcontroller then this is not anything I know of as linearisation.

author: hamster_nz
author_rank: Super Contributor
timestamp: March 07, 2021, 08:20:35 am
content: Quote from: DiTBho on March 06, 2021, 11:28:40 amDo you have values for K1 & K2, and the ranges and precision required for a1, b1, a2 and b2? I would like to play around with them...

author: DiTBho
author_rank: Super Contributor
timestamp: March 07, 2021, 10:58:25 am
content: Quote from: brucehoult on March 07, 2021, 12:35:13 amThe sensor outputs a voltage value for each distance between the sensor and the ground I try to measure. The measuring plane moves vertically, and I have a meter tape to take the measures. So I can report { Voltage, distance } in a table.

author: ledtester
author_rank: Super Contributor
timestamp: March 07, 2021, 01:34:19 pm
content: Have you considered an optical encoder -- either linear or rotary?

author: brucehoult
author_rank: Super Contributor
timestamp: March 08, 2021, 12:56:16 am
content: Quote from: DiTBho on March 07, 2021, 11:29:18 amNone of this makes any sense.Coefficients spat out by a program can be implemented by floating point or fixed point of whatever precision makes sense for the application. "Irrational" or "double precision" is irrelevant. 16 bit fixed point should certainly be more than enough, and can be efficiently handled by any microcontroller ever made.Programs such as Labview of Octave can save you from having to do the actual arithmetic yourself, but they are not a substitute for understanding the math.

author: hamster_nz
author_rank: Super Contributor
timestamp: March 08, 2021, 01:27:16 am
content: Quote from: brucehoult on March 08, 2021, 12:56:16 amFully agree.However, should somebody find themselves in the situation where they do need to calculate fixed-point exponentials please ping me. It isn't that that hard to write a log(x) function using only a lookup table and division, and an exp(x) function using just a table and multiplication.As pow(a,b) = exp(b*log(a)) this is perfectly achievable in fixed point once the bounds for 'a' and 'b' have been established.

author: brucehoult
author_rank: Super Contributor
timestamp: March 08, 2021, 03:32:52 am
content: Quote from: hamster_nz on March 08, 2021, 01:27:16 amThe same lookup table in both cases, of exp(2**n), for appropriate +ve and -ve n?

author: brucehoult
author_rank: Super Contributor
timestamp: March 08, 2021, 03:44:36 am
content: Quote from: hamster_nz on March 08, 2021, 01:27:16 am... also as pow(a, b) = x**(logx(a)*b) for any base x, it's not necessarily best to use e for that base. You can use 10. Or ... if you use 2 as the base then maybe you don't need any table at all (it's just shifts).

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 09:23:19 am
content: Quote from: brucehoult on March 08, 2021, 03:44:36 amThis is a great contribute, and it's probably what I was looking for when I opened this topic! Thanks!

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 09:35:23 am
content: For a similar sensor, I was able to manually synthesize an approximation in this termsdistance = (1 / (k1 * Volt + q1))k1=0.0002391473 (irrational, truncated)q1=-0.0100251467 (irrational, truncated)No pow(a,b) required, just a division, a multiplication, and a sum

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 09:58:00 am
content: Just a proof, but for that similar IR-reflective sensor, this is what I can simplify.distance = k1 * pow(volt,b1) +qk1 = 10650.080 (irrational, truncated)b1 = -0.935 (irrational, truncated)q = - 10.000No more three pow, just one.

author: brucehoult
author_rank: Super Contributor
timestamp: March 08, 2021, 10:03:14 am
content: Quote from: DiTBho on March 08, 2021, 09:35:23 amWe're finally starting to get somewhere.Or try 10000 / (2.391473 * Volt - 100.25)Or maybe a low order polynomial on the top line also.

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 11:20:31 am
content: Quote from: brucehoult on March 08, 2021, 10:03:14 amThanks! Just, don't assume THIS as working model, it's just an example of what I'd like to achieve for the sensor I am using, which is a bit different and it has a different measuring range.I don't know if it's possible, and that's the reason why I am evaluating other solutions and sensorsI mean, if I apply this approach to my sensor, I get an error of +/-70mm for distances > 1000mm

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 12:47:32 pm
content: Code:H{ "success", failure" | [ measured=get_value(value), expected ] } :->(abs(expected - measured) <= tolerance)H[data, tolerance = 20.00] // 20mmCode:data{ volt, expected } ={{ 2.75, 150.00 }, // volt, mm{ 2.55, 200.00 },{ 2.00, 300.00 },{ 1.55, 400.00 },{ 1.25, 500.00 },{ 1.15, 600.00 },{ 0.90, 700.00 },{ 0.80, 800.00 },{ 0.75, 900.00 },{ 0.65, 1000.00 },{ 0.60, 1100.00 },{ 0.55, 1200.00 },{ 0.50, 1300.00 },{ 0.44, 1400.00 },{ 0.45, 1500.00 },};Code:get_value(value) :->k1 = 106500.800a1 = 1023.000 / 5.000 // 10bit ADC, 5V rangeb1 = -0.935q1 = -100.000return k1 * pow(a1 * value, b1) + q1Code:volt=2.750000 failureexpected distance=150.000000measured distance=185.680132volt=2.550000 successexpected distance=200.000000measured distance=206.578036volt=2.000000 successexpected distance=300.000000measured distance=284.762786volt=1.550000 successexpected distance=400.000000measured distance=388.310394volt=1.250000 successexpected distance=500.000000measured distance=497.097488volt=1.150000 failureexpected distance=600.000000measured distance=545.510968volt=0.900000 successexpected distance=700.000000measured distance=711.781893volt=0.800000 successexpected distance=800.000000measured distance=806.289542volt=0.750000 failureexpected distance=900.000000measured distance=862.661992volt=0.650000 successexpected distance=1000.000000measured distance=1000.479909volt=0.600000 successexpected distance=1100.000000measured distance=1085.999996volt=0.550000 successexpected distance=1200.000000measured distance=1186.521333volt=0.500000 successexpected distance=1300.000000measured distance=1306.433339volt=0.440000 failureexpected distance=1400.000000measured distance=1484.994845volt=0.450000 failureexpected distance=1500.000000measured distance=1452.038200A bit better, but ... not so much

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 12:50:59 pm
content: Code:H[data, tolerance = 60.00] // 60mmCode:volt=2.750000 successexpected distance=150.000000measured distance=185.680132volt=2.550000 successexpected distance=200.000000measured distance=206.578036volt=2.000000 successexpected distance=300.000000measured distance=284.762786volt=1.550000 successexpected distance=400.000000measured distance=388.310394volt=1.250000 successexpected distance=500.000000measured distance=497.097488volt=1.150000 successexpected distance=600.000000measured distance=545.510968volt=0.900000 successexpected distance=700.000000measured distance=711.781893volt=0.800000 successexpected distance=800.000000measured distance=806.289542volt=0.750000 successexpected distance=900.000000measured distance=862.661992volt=0.650000 successexpected distance=1000.000000measured distance=1000.479909volt=0.600000 successexpected distance=1100.000000measured distance=1085.999996volt=0.550000 successexpected distance=1200.000000measured distance=1186.521333volt=0.500000 successexpected distance=1300.000000measured distance=1306.433339volt=0.440000 failureexpected distance=1400.000000measured distance=1484.994845volt=0.450000 successexpected distance=1500.000000measured distance=1452.038200"expected" means the value in the table."measured" means the compute value that should approximate it.

author: emece67
author_rank: Frequent Contributor
timestamp: March 08, 2021, 02:03:12 pm
content: .

author: DiTBho
author_rank: Super Contributor
timestamp: March 08, 2021, 02:30:23 pm
content: Yup, this topic is a solid amount of embedded things ... hacking of things, inner digital math on "grinder old CPU", and crazy stuffQuote from: emece67 on March 08, 2021, 02:03:12 pm{ Yes, Yes, Yes }Plus I am open toalternative solutions! For example, yesterday it was suggested to use a different approach for the sensorQuote from: ledtester on March 07, 2021, 01:34:19 pmand now I'm also thinking of opening the motor box and hacking it to get aquadrature sensor. I am very reluctant to do this because it is a very dirty trick, the motor box is sealed and I need to "Dremel cut", and, since a quadrature encoder is a relative-position encoder it would require the frame to "Go back home" to the "zero position" (600mm from the ground) in order to set the zero, which is also something I'd like to avoid.Go Back home and set the zero -> offset = 600mmnow start counting, position = offset + encoder'delta * counted-stepsDunno, I will try it the next weekend

author: hamster_nz
author_rank: Super Contributor
timestamp: March 11, 2021, 09:09:44 am
content: Here's something really basic, that calculate log() and exp() base 2 over limited range using a really silly mix of double and floating point numbers, but should give ideas of how you could implement them when you know what range you will be working over.Code:#include <stdio.h>double exp_table  = {1.000169239705302138, 1.000338508052682318, 1.000677130693066408, 1.001354719892108225,1.002711275050202522, 1.005429901112802726, 1.010889286051700475, 1.021897148654116627,1.044273782427413755, 1.090507732665257690, 1.189207115002721027, 1.414213562373095145,2.000000000000000000, 4.000000000000000000, 16.00000000000000000, 256.0000000000000000,};double my_pow2(double a) {int fixed = a * 4096;double total = 1.0;for(int i = 0; i < 16; i++) {if(fixed & (1<<i))total *= exp_table;}return total; // 2^(a/4096) for a limited range}double log_table  = {1.00000528830729185, 1.00002115339696473, 1.00004230724139576, 1.00008461627269440,1.00016923970530214, 1.00033850805268232, 1.00067713069306641, 1.00135471989210822,1.00271127505020252, 1.00542990111280273, 1.01088928605170048, 1.02189714865411663,1.04427378242741375, 1.09050773266525769, 1.18920711500272103, 1.41421356237309515};int my_log2_fixed(double a) {int fixed = 0;while(a >= 2.0) {fixed++;a /= 2.0;}while(a < 1.0) {fixed --;a *= 2.0;}fixed <<=16;for(int i = 15; i >= 0; i--) {if(a > log_table) {a /= log_table;fixed |= 1<<i;}}return fixed; // log2(a) * 65536}

author: hamster_nz
author_rank: Super Contributor
timestamp: March 11, 2021, 09:41:17 am
content: But why bother curve-fitting at all - just interpolate between points.Code:#include <stdio.h>struct {double x, y, k;} data[] ={{ 2.75, 150.00 }, // volt, mm{ 2.55, 200.00 },{ 2.00, 300.00 },{ 1.55, 400.00 },{ 1.25, 500.00 },{ 1.15, 600.00 },{ 0.90, 700.00 },{ 0.80, 800.00 },{ 0.75, 900.00 },{ 0.65, 1000.00 },{ 0.60, 1100.00 },{ 0.55, 1200.00 },{ 0.50, 1300.00 },{ 0.44, 1400.00 }};double get_value(double i_value) {int i;// Find where we are interpolatingfor(i = 0; i < sizeof(data)/sizeof(data)-2; i++) {if(i_value > data[i+1].x) {break;}}return data.y + (i_value-data.x) * data.k;}int main(int argc, char *argv[]) {// Calc some constantsfor(int i = 0; i < sizeof(data)/sizeof(data)-1; i++) {data.k = (data[i+1].y-data.y) / (data[i+1].x-data.x);}// Check against the table valuesfor(int i = 0; i < sizeof(data)/sizeof(data); i++) {printf("%5.2f, %7.2f, %7.2f\n", data.x, data.y, get_value(data.x));}// Check between two numbersprintf("\n%5.2f, %7.2f, %7.2f\n", 0.85, 750.00, get_value(0.85));}

author: Doctorandus_P
author_rank: Super Contributor
timestamp: March 11, 2021, 12:37:50 pm
content: I accidentally searched:https://html.duckduckgo.com/html?q=fractional+look+up+tableand found:https://www.sciencedirect.com/topics/computer-science/fractional-valueI like the idea of first scaling a number between 0.5 and 1 and then using a LUT or simplified approximation.But scaling it back would need an exponential function so I'm confuses as to whether this is applicable in this situation.

author: gf
author_rank: Super Contributor
timestamp: March 12, 2021, 08:28:13 am
content: Why not simply approximate the transfer function with a polynomial, as already suggested by rstofer?A 5th order polynomial fits nicely (see plot). I would not use a higher order as the provided data are ovbiously noisy.The evaluation requires 5 multiplications and 6 additions then. The coefficients can be either be stored in a table, or immediate values in the code.Code:>> datadata =2.75000 15.000002.55000 20.000002.00000 30.000001.55000 40.000001.25000 50.000001.15000 60.000000.90000 70.000000.80000 80.000000.75000 90.000000.65000 100.000000.60000 110.000000.55000 120.000000.50000 130.000000.44000 140.000000.45000 150.00000>> P = polyfit(data(:,1), data(:,2), 5)P =-12.951 118.581 -429.858 782.454 -750.827 357.198>> x = 0.44:0.01:2.75;>> plot(data(:,1), data(:,2), ".", x, polyval(P,x)); grid on

author: DiTBho
author_rank: Super Contributor
timestamp: March 12, 2021, 10:40:10 am
content: Quote from: gf on March 12, 2021, 08:28:13 amGood idea! I am still studying Octave, and I did a couple of attempts, but then I have been busy with a complete different job task.Quote from: gf on March 12, 2021, 08:28:13 amThe nature of the sensor is IR reflective, that's very noisy by itself, that's also the reason why I want to filter and to amplify the signal. Not yet done, but I will this weekend.I am also waiting for a couple of better ADC at 12 and 16 bit of resolution. I need to write an SPI function to manage them, but hey? look at the current firmware only takes 512 byte, and it manages a mean-window filtering function, the ADC conversion, the serial talking to the host (with a minimal protocol to setup-up working variables), and a 100uS-fine timer used to control the motor.All written in assembly. I love it!I am going to reuse the 100uS-fine timer for a new ultrasonic ranging sensor used with quad rotors. It's modulator is smarter than traditional ultrasonic ranging sensors, and its outputs is a digital pulse of the width directly proportional to the measured distance.I ordered it two days ago, it will probably arrive tomorrow.So I may use both: IR reflective + ultrasonic, or just one. We will see

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 13, 2021, 03:38:15 pm
content: I often use Gnuplot for fitting data to a function I define myself.For example, if you havedata.txtwith input value in the first column, output value in the second column, and if there are any comments they start with a#, you can start Gnuplot, and tell it e.g.f(x) = C0 + x*(C1 + x*(C2 + x*(C3 + x*(C4 + x*C5))));fit f(x) "data.txt" using 1:2 via C0,C1,C2,C3,C4,C5and you can also draw both the sample data and the curve fit using e.g.plot "data.txt" using 1:2 notitle with points lc "black", f(x) notitle with lines lc "red"You can print the coefficients using e.g.print(C0, C1, C2, C3, C4, C5)but Gnuplot will automatically save a text file calledfit.logwhich contains the fitted variables (C0 through C5, above) under the "Final set of parameters" heading; and all kinds of convergence, error, and correlation matrix information that you may or may not find useful.If you want the function in a variable name to be used in the plot, you can use sprintf (which has the same syntax the C printf() function has):fstr = sprintf("f(x) = %f + x*(%f + x*(%f + x*(%f + x*(%f + x*%f))))", C0, C1, C2, C3, C4, C5)so thatset title fstr ; plot "data.txt" using 1:2 notitle with points lc "black", f(x) notitle with lines lc "red"will add the function definition as the title of the plot.I've found this to be very useful when I am still exploring what kind of a function fits my needs most. (In Gnuplot,ABis writtenA**B, and you can use conditional expressions – (condition?value-if-true:value-if-false) – in functions. ^|& are binary operators between integers (exclusive-or, or, and, respectively), so 2^5==7 and not 32. == tests for equalty, and != for inequality.)As an example, when dealing with distancesr, I often try to avoidrand 1/r, preferringr2and 1/r2instead, because ifris calculated from a vector, odd powers need a "slow" square root, whereas even powers are "cheap" (just need multiplications; and only one division for all even powers of the reciprocal of the distance).When implementing the function in fixed point format,int(expression)is very useful, because it truncates the expression to an integer. However, the fit variables (C0 through C5, above) must still be treated as reals, as otherwise Gnuplot cannot converge to a solution. (This means, if you try to useint(C0)in f(x), you can expect Gnuplot to not be able to converge to a solution, because small changes in C0 do not have any effect on the result.)

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 13, 2021, 03:51:35 pm
content: For most of my "manual" (meaning not automatically generated - for this Gnuplot is nice, there are others) graphing needs, I use Scidavis. Many features including curve fitting.

author: Nominal Animal
author_rank: Super Contributor
timestamp: March 13, 2021, 04:13:47 pm
content: Quote from: SiliconWizard on March 13, 2021, 03:51:35 pmIndeed, the way I usually store the derivation of the coefficients is to write the fitting (and plotting) into a script. But mostly, it just fits my workflow.I might be strange, but I don't use Jupyter notebooks (for Sagemath), wxMaxima documents, Octave workspaces, Maple notebooks, etc.; I prefer to save the operations into a text file. It is faster for me tolessorfind+grepdetails to find the particular project, than to open a dozen or so of them in their respective programs to see the content. Then again, I have hundreds of those snippets...For proper documentation, there's LibreOffice and LaTeX and other, better tools.

author: DiTBho
author_rank: Super Contributor
timestamp: March 18, 2021, 10:05:08 pm
content: I have been very busy with other stuff but I haven't forgotten this project.Today I managed to find two hours to modify my board and to implement an new uploader software able to auto-reset the target. The RS232 signal CTS is used for this.Code:uploader-v1 # ./obj/binvect-uart-upld hAllo.binloading binvect ... done, 512 bytes loadedopening /dev/ttyS0 at 8N1-1200bps ... successresetting target and waiting for ack ... doneuploading: [########################################] 100%, successIt works, and it allows me to develop things remotely and to upload them to the target so I can work on it, collects data, experiment stuff, even when I am outdoorsThis uploader also works with the chip in expanded mode. I have already prepared a new board and a special "first stage bootloader" and it's ready to work.If I don't have to go overseas for work, we will see some progress soon.