I think computeRC() needs reevaluation.

This forum is dedicated to software development related to MultiWii.
It is not the right place to submit a setup problem.
Software download
Post Reply
User avatar
Crashpilot1000
Posts: 631
Joined: Tue Apr 03, 2012 7:38 pm

I think computeRC() needs reevaluation.

Post by Crashpilot1000 »

Hi!
The topic says it. While reworking the RCrx part in Harakiri I came across http://code.google.com/p/multiwii/sourc ... RX.cpp#406
computeRC(). I may be wrong but I think it could be done less memory intensive.
First of all the static rcDataMean[RC_CHANS] definition is not needed, since it is cleared on every run and the stored value isn't used. A simple int16_t tempvariable would do it as well, right? When doing a 4 point moving avg, why not use the actual value buffered in another temp int16_t? On the other hand a mov avg with 3 values is sufficient and would boil down to storing two values per channel.
I post here how I've done it right now in my project. Works well.

Code: Select all

static void computeRC(void)                                                 // Just harvest RC Data
{
    static int16_t rcData2Values[MAX_RC_CHANNELS][2];
    static uint8_t bufindex = 0;
    int16_t rawval, avg;
    uint8_t chan;

    for (chan = 0; chan < cfg.rc_auxch + 4; chan++)
    {
        rawval = rcReadRawFunc(chan) << 2;
        if(cfg.rc_lowlat || SerialRCRX)
        {
            avg = (rawval + rcData2Values[chan][0]) >> 3 ;
            rcData2Values[chan][0] = rawval;
        }
        else
        {
            avg = (rawval + rcData2Values[chan][0] + rcData2Values[chan][1]) / 12; // GCC would do the same with a "for" loop
            rcData2Values[chan][bufindex] = rawval;
        }
        if (avg < rcDataSAVE[chan] - 3) rcDataSAVE[chan] = avg + 2;         // rcDataSAVE can pass unchanged here
        else if (avg > rcDataSAVE[chan] + 3) rcDataSAVE[chan] = avg - 2;
    }
    bufindex ^= 1;
}


EDIT: Note: I buffer the data in rcDataSAVE (instead of the direct use of rcData) because of the serial rx.
EDIT:EDIT: uint should do it as well - maybe shorter when compiled.
Cheers
Rob

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: I think computeRC() needs reevaluation.

Post by Alexinparis »

Hi,

yes, you're right:
- there is no need for a static rcDataMean[RC_CHANS] array, a single non static var is enough
- staying on 4 values is probably more efficient (/16 is faster than /12)
- is is also true we can save one index in rcData4Values[RC_CHANS][4] (we can do the same with rcData4Values[RC_CHANS][3])

User avatar
Crashpilot1000
Posts: 631
Joined: Tue Apr 03, 2012 7:38 pm

Re: I think computeRC() needs reevaluation.

Post by Crashpilot1000 »

Yes, I knew you would prefer /16 :) . Maybe that 4 point moving avg was relevant with pure analogue systems but at least my frsky ppsum setup works very good with a 2 element moving average (due to digital airlink, of course) and rewards the pilot with a noticeable lower latency. Just saying, maybe a #define for those radios that are just analog on the last step would be fine.

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: I think computeRC() needs reevaluation.

Post by Alexinparis »

done in _shared
the most generic I could

User avatar
Crashpilot1000
Posts: 631
Joined: Tue Apr 03, 2012 7:38 pm

Re: I think computeRC() needs reevaluation.

Post by Crashpilot1000 »

Hi!
Thanks for the response and considering it! I think many will use #define AVERAGING_ARRAY_LENGTH 2 :) .
BTW. I really don't get the real magic of that line.
AVERAGING_ARRAY_LENGTH 4
..
rcDataMean = (rcDataMean+(AVERAGING_ARRAY_LENGTH/2))/AVERAGING_ARRAY_LENGTH;
..
rcdata of 4 * 1000 would result in rcDataMean = (4000+2)/4 = 1000,5
rcdata of 4 * 2000 would result in rcDataMean = (8000+2)/4 = 2000,5
Since the 0.5 is cut it's doubtful if there is a real rounding increase of precision, seems like it's as usable as my unneccessary "rcReadRawFunc(chan) << 2"...
maybe rcDataMean = rcDataMean/AVERAGING_ARRAY_LENGTH; is as good...
Cheers Rob

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: I think computeRC() needs reevaluation.

Post by Alexinparis »

Think in integer :

3999/4 = 999
4000/4 = 1000
4003/4 = 1000
4004/4 = 1001
=> 1000 for the range [4000 ;4003]

with +2 :

(3997+2)/4 = 999
(3998+2)/4 = 1000
(4001+2)/4 = 1000
(4002+2)/4 = 1001
=> 1000 for the range [3998 :4001] => more accurate

User avatar
climb4hope
Posts: 12
Joined: Mon Jan 27, 2014 11:14 pm
Location: Seattle, WA

Re: I think computeRC() needs reevaluation.

Post by climb4hope »

Hello,

I did this implementation a little differently. I considered using adaptive LPF filter with optionally Jitter filter. The idea is that if the change in RC channel is more than configurable threshold then we apply fast LPF (i.e. with coef 1/2) if the change is small (no moving sticks, just regular noise) then we apply slow LPF (with coef 1/4 or less).
Jitter filter is not necessary needed but it filters out one additional count of the noise. Some variables have different names in below implementation, but the general concept is saved. It works quite well on mine setup.

Code: Select all

uint8_t chIndex;
    int16_t prevChData;
    int16_t currentChData;

    /* Loop Through Each Channel */
    for (chIndex = 0; chIndex < RC_CHANNELS_NUM; chIndex++)
    {
        prevChData = rcData[chIndex];
        currentChData = RC_ReadRawChannelData(chIndex);

#if RC_RECEIVER_IIR_FILTER_ENABLED
        if (abs(prevChData - currentChData) > RC_RECEIVER_IIR_THRESHOLD)
        {
            rcData[chIndex] = (prevChData * ((1 << RC_RECEIVER_IIR_FILTER_COEF) - 1) + currentChData) >> RC_RECEIVER_IIR_FILTER_COEF;
        }
        else
        {
            rcData[chIndex] = (prevChData * ((1 << RC_RECEIVER_IIR_SLOW_FILTER_COEF) - 1) + currentChData) >> RC_RECEIVER_IIR_SLOW_FILTER_COEF;
        }
#else /* RC_RECEIVER_IIR_FILTER_ENABLED */
        /* Record RAW Data into the output array */
        rcData[chIndex] = currentChData;
#endif /* RC_RECEIVER_IIR_FILTER_ENABLED */

        /* Jitter Filter */
        if (prevChData > rcData[chIndex])
        {
            rcData[chIndex]++;
        }
        else if (prevChData < rcData[chIndex])
        {
            rcData[chIndex]--;
        }

        /* rcData comes from MSP and overrides RX Data until rcSerialCount reaches 0 */
        if ((chIndex < RC_CHANNELS_NUM) && (rcSerialCount > 0))
        {
            rcSerialCount --;
#if defined(FAILSAFE)
            failsafeCnt = 0;
#endif /* defined(FAILSAFE) */

            /* only relevant channels are overridden */
            if (rcSerial[chIndex] > 900)
            {
                rcData[chIndex] = rcSerial[chIndex];
            }
        }
    }


I started to work on a bit more modular firmware which I branched from the MultiWii 2.3 and started development in https://code.google.com/p/pksquad-mw/.

Jitter filter is not necessary required, but seems to help with rare 1count noise.

I use:
RC_RECEIVER_IIR_THRESHOLD = 10
RC_RECEIVER_IIR_FILTER_COEF = 1
RC_RECEIVER_IIR_SLOW_FILTER_COEF = 2

Post Reply