Derive peak value from two points on a sinewave?

Discussion in 'Math' started by THE_RB, Nov 2, 2012.

  1. THE_RB

    Thread Starter AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Hi, I'm doing a DSP application on quite limited microcontroller hardware, and need a fast crude process to find a sinewave peak value based on two points on the sinewave which are guaranteed to be 90 degrees apart.

    The two points are already full-wave rectified, so there are no negative values. Both values are already in the range 0-127 (7bit binary).

    Normally this is found as the "square root of the sum of the two squares", which obviously works fine but I need to do this fast with no squares or roots, hopefully just with some additions/subtractions, and binary mult/divide (left/right shifts on a micro).

    I also prefer not to use a lookup table. The good news is that the final accuracy only needs to be +/- 3%.

    As an example I am currently using this calc;
    peak = biggest - dif/4
    (dif = biggest-smallest, where biggest and smallest are the two values), and it gets pretty close;

    Code ( (Unknown Language)):
    1.  
    2. Big Small   RMS Mine
    3. 0   100 71  75
    4. 36  90  71  76
    5. 71  71  71  71
    6.  
    This gives a result within about 8% of the real RMS value, so it's almost accurate enough but leaves me with a problem of turning the RMS result into a peak result (ie *1.41).

    If anyone has a fast simple way of getting a peak value within +/-3% or so it would be much appreciated! :)
     
  2. nigelwright7557

    Senior Member

    May 10, 2008
    487
    71
    To mpy by 1.41 mpy by 14 then divide by 10 using integers.
     
  3. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
    No.

    To multiply by 1.414, multiply by 362 and divide by 256 (i.e. use the upper byte).

    If the multiplication has the potential to exceed 16 bits, then there are ways of dealing with this,

    such as...

    multiply by 106 and divide by 256, then add the original number.

    (In your case, the number is 7 bits and hence the product will not exceed 16 bits).
     
    Last edited: Nov 3, 2012
  4. THE_RB

    Thread Starter AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Thanks guys, I can do simplified mucltiplications and divisions.

    What I'm really after is some input from math guys if there is a simple way to do the calc to find the peak sine value based on the 2 points at 90 degrees apart on the sine wave.

    It's not a big rush, i've been checking out the possibility of using a lookup table which can do the job but is not the method I would prefer. Maybe someone has some type of simple transfer function etc to do the job?
     
  5. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
    Why not go the square root of the sum of the squares route?
    I am sure we can come up with an efficient way to calculate the square root.
    I once did it for logarithm.
     
  6. THE_RB

    Thread Starter AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Because I'd like to do it in about 5 to 10 assembler cycles... ;)

    Something like the old 2D graphics trick for fast hypotenuse; h = a + (b/2) where you add half the smaller number to the larger number, instead of; 2 squares an additon and a square root.

    I've checked my other code and can work with either a peak result or a RMS result, so I can work with;
    0 + 100 -> 100 (result is the sine peak)
    71 + 71 -> 100
    or alternatively
    0 + 100 -> 71 (result is the RMS)
    71 + 71 -> 71

    What I have so far (for example) is;
    big + (small * 0.375)

    Code ( (Unknown Language)):
    1.  
    2. Small   Big PEAK    Mine
    3. 0   100 100 100
    4. 36  90  100 103
    5. 71  71  100 98
    6.  
    That gets me within about 3-4% of accurate, and is not too bad as *0.375 is *3/8, which is easy to do in binary as *3 then >> 3.

    But I'd like it more accurate if possible. :)
     
  7. Ron H

    AAC Fanatic!

    Apr 14, 2005
    7,050
    656
    I don't get it. Do you know the phase of the two samples? If not, how can you calculate the peak? Samples at 45° and 135° will be at the same level.
     
  8. THE_RB

    Thread Starter AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Hi Ron, sorry I probably didn't explain well enough. The data corresponds to a sine. The two samples are always exactly 90 degrees apart in relation to the (known) sine frequency.

    I needs a very fast simpel way to get the peak value from the height of the two samples (which are already "full wave rectified" so heights are all positive).
     
  9. Ron H

    AAC Fanatic!

    Apr 14, 2005
    7,050
    656
    But what are the phases of the samples, relative to the sine?
     
  10. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
    Does your MCU have hardware multiply or divide?
     
  11. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
  12. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
    If you can do a multiply to find the square, try

    if x > y

    y1 = (y * y) / 256

    y2 = y1 / 2

    r = x + y1 + y2
     
  13. THE_RB

    Thread Starter AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    That is unknown but irrelevant, there is always 90 degrees between the two samples. It's irrelevant because the full wave rectification gives two identical 180 degree half sines, and then each of those is two identical quadrants (mirrored). So only two points at 90 degrees apart are needed to calc the sine peak.

    To MrChips; thanks for the CORDIC reference, it was a good read but even though using relatively simple code it's similar to successive approximation which can require numerous cycles, so it's very slow compared to my present solution which is only one iteration of a few assember instructions.

    Interesting, and thank you. I'll have a play with that and see how it goes for time and accuracy. :)
     
  14. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
    Sorry, my proposed solution only works at a given value of r = 100.
    I will have to rethink this.
     
  15. Ron H

    AAC Fanatic!

    Apr 14, 2005
    7,050
    656
    Yeah, I finally figured that out on my own. Sometimes I'm a little dense.:(
     
  16. Tesla23

    Active Member

    May 10, 2009
    318
    67
    The approach you are trying is best shown graphically:
    [​IMG]

    where you are doing a linear approximation, breaking at x=y.

    A slightly CORDIC inspired approximation is:
    0 <= y < x/2 : amp = x + 0.236*y
    x/2 < y < x : amp = 1.414*x + 1.019*y - 0.7208

    This gives an error between 0 and +2.7% (it's always positive so there is further tweaking you can do). You may get something reasonable by playing around with binary inspired approximations to this.
     
  17. MrChips

    Moderator

    Oct 2, 2009
    12,418
    3,355
    I have fixed the algorithm but now it requires one multiply and one divide and some shifts:

    if x > y

    y1 = y * y / x

    y2 = y1 / 2

    y3 = y2 / 8

    r = x + y2 - y3
     
    Last edited: Nov 10, 2012
  18. THE_RB

    Thread Starter AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Thanks Tesla23 that has given me something to think about. At first glance I'm not favoring splitting the calc into 1 of 2 processes, it already has the time cost of the first split if(x>y) and then the second split and dual multiplications is going to make it slow I think...

    Thanks MrChips. :) The new algo is not as bad as it looks time wise;

    if x > y
    y1 = y * y / x // this is still a bit unpleasant
    y2 = y1 / 2 // fast, can be >>1
    y3 = y2 / 8 // fast, can be another >>3
    r = x + y2 - y3 // fast, can be done on the fly

    I have not had time to check it out just yet but should get some time over the next few days. :)
     
  19. Tesla23

    Active Member

    May 10, 2009
    318
    67
    A slight refinement on Mr Chips algorithm:

    for y < x

    amp = (1 - 2^{-5} - 2^{-6})x + (2^{-1} - 2^{-4})y

    or

    amp = 0.953*x + 0.4375*y

    gives max error < 5%
     
Loading...