jeelabs / jeelib

JeeLib for Arduino IDE: Ports, RF12, and RF69 drivers from JeeLabs
https://jeelabs.org/202x/sw/jeelib/
The Unlicense
489 stars 215 forks source link

Add (auto-) tune capability to RF12 driver and RF12demo #57

Closed jcw closed 10 years ago

jcw commented 10 years ago

With the changes in progress on the rf12demo branch, it would be nice to be able to automatically seek the best frequency to receive a specific node.

Perhaps as follows:

During this process, reception from other nodes will be deteriorated (or maybe disabled altogether). Once the best offset has been found, the opposite offset should be added to the remote configuration, as compensation.

martynj3 commented 10 years ago

The 'listen and nudge' method may not converge in the general case - loop loss is not static, seeking the saddle point when the surface is bouncing around is problematic. The alternative is to get the module to do the work - provided the preamble is adequate, payload is white(ish) and the offset is reasonable, strobe out the AFC offset. That is a good estimate of the current delta ( a couple of iterations will confirm this) The next issue is what to do with the delta? The root cause of the delta for each pairing is that the two crystals involved do not agree on what is F0. Without a calibration source, it cannot be determined which is 'wrong' (they both are probably 'wrong' with ∆A + ∆B = ∆observed). Assuming a star topology, then the central node could be assumed to be 'right' and all the ∆ should be compensated in each leaf. This would suit external calibration of the central node at some stage - each leaf could re-compensate at driver level without intervention. Sounds too dynamic? Unfortunately there is no choice - the delta has three main components. Original factory crystal error (+ stress from reflow soldering), ageing and ambient temperature. A static system could trim out the first, but only at a given point in time and fixed temperature. As for the compensation mechanism - IMHO fudging the PLL multiplier is not the right mechanism. The problem is anticipated in the module implementation and a cap bank provided for trimming - the ∆F/∆C relationship is known empirically (differs between SMD and Metal Can types). The Cpad steps are perhaps a little coarse but I think adequate. For optimum reception between pairs, the objective is I think to get the approximation of the desired carrier F and the receiver's guess of that close enough for the AFC to do its job and correct for the remaining error dynamically at each packet reception.

jcw commented 10 years ago

Ah, yes - caps adjustment. Good point. Yet another variable.

Yes - to simplify, I suggest insisting on an SMD-crystal based unit for the central node (or a known calibrated one). And then use that on its untuned frequency setting as reference. This all falls under advanced use anyway.

Also: we don't need perfection, just close-enough to capture the most of the packets most of the time. It may well be that people won't even bother, except for the most remote node(s).

martynj3 commented 10 years ago

This suggests that the cap bank setting becomes an EPROM item. Defaults if unset or CRC fails. Provide public access to AFC_delta - tuning sketch loaded in remotes, iterates on traffic for a while and then writes 'optimum' cap value for subsequent initialisations. I have the magic ∆F/∆C numbers.... BTW - it would be nice to clean up the long-standing systematic offset between SMD and Metal can. The current cap bank default is arbitrarily in the middle of the range - ideally it should be two defaults. Determining which to chose by detecting the crystal type is an exercise for the reader... ;>) (it can be done!)

jcw commented 10 years ago

Ok, so now we have 4 bits of crystal adjustment and 12 bits of frequency offset data to add to EEPROM.

More bits would be nice: the V10 flag bit (not sure), the quiet bit ('q' cmd), and the capture setting ('c' cmd) which is already in there. These are all higher-level, i.e. for RF12demo not the RF12 driver.

JohnOH commented 10 years ago
There are three bits available after my fiddling.
John.
--On 30/09/2013 14:51, Jean-Claude
  Wippler wrote:

  Ok, so now we have 4 bits of crystal adjustment and 12 bits of
    frequency offset data to add to EEPROM.
  More bits would be nice: the V10 flag bit (not sure), the quiet
    bit ('q' cmd), and the capture setting ('c' cmd) which is
    already in there. These are all higher-level, i.e. for RF12demo
    not the RF12 driver.
  —
    Reply to this email directly or view
      it on GitHub.
JohnOH commented 10 years ago
Sorry, that is two bits. If we want to be hard on backwards compatibility v10 could be dispensed with. v10 is used by rf12.cpp in RF12demo branch to identify if the default frequency offset (1600) is required.

John.
martynj3 commented 10 years ago

The test samples showed typical errors in the +-20ppm range with outliers less than +-40ppm offset. Allowing a generous say +-50ppm adjustment will only influence the last few bits of the 12bit offset size if interpolation is needed after adjusting the cap bank first.

JohnOH commented 10 years ago

I'm not sure I follow your thinking Martin. I think of the offset mechanism as a means to position ones operation frequency as desired. The spin off benefit of tuning specific nodes to the centre frequency of the central unit isn't the whole purpose - for me that is.

martynj3 commented 10 years ago

John - yes, my comment was as clear as mud. I hope the edited version makes more sense

jcw commented 10 years ago

One issue is getting all the nodes in a netgroup on as much the exact same frequency as possible, to be able to optimise range and power consumption. The other is the ability to pick multiple adjacent sub-bands, something I haven't played with yet, but which could also help with overcoming that 1% usage rule. AFAIK, some of the frequencies below 868 used to be allocated to things like audio headphones, but are now available for other uses - allowing 100% utilisation, even. Probably a bit country-specific, but lets hope things are nevertheless moving to more globally uniform rules.

I don't think we can / should address all issues now, but it's good to map out the field to avoid limiting future options.

jcw commented 10 years ago

And while I'm at it: there's one unused combination in two of the packet header bits (the current 3 uses are: send, req-ack, and ack).

I'm considering using that remaining option for a "req-fast-ack". This would make the RF12demo-specific "collect mode" (1c) obsolete, and move the choice between single-hop-acks and end-to-end acks into the RF12 driver. Single-hope acks would be sent by the receiving node (JeeLink, etc), while end-to-end acks would pass through and require an application-level ack, such as HouseMon, with an optional payload.

Either that or a toggle for regular ack replies, to weed out duplicates in the case of retries. Haven't decided.

JohnOH commented 10 years ago

*update Got it back from my email.

My response is: "Determining which to chose by detecting the crystal type is an exercise for the reader... ;>) (it can be done!)"

Can you please say more? I will put into RF12Tune using a spare bit if I understand it.

martynj3 commented 10 years ago

The crystal type can be detected via a side effect.  The sensitivity to the capacitor load bank is different (∆F/∆C).  I have some empirical data on this tucked away somewhere. It's worth knowing the crystal type because of this - but probably not worth the extra effort of auto-detection, easier to make it a user input to the tune-up utility. 

JohnOH commented 10 years ago

It would be straightforward to have two options, CAN or SMD, could you let me have the CPAD command/values? Otherwise, do you need full control over the CPAD value?

jcw commented 10 years ago

My answer now, would be to keep a separate branch for this code, and point to it from the new wiki page, to explain what it does and what it is for. The RF12 driver is being using in too many places to make any changes than bug fixes. Going forward, my focus will be on the new RF69 driver(s).