Created
October 19, 2018 13:15
-
-
Save philpem/09c8edc732ae435a43c34f5fb6e765d6 to your computer and use it in GitHub Desktop.
Si44xx Class E matching (Jupyter notebook)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Split TX/RX Class-E matching network per AN627 section 5.3 #\n", | |
"This iPython notebook implements the transmit matching procedure specified in Silicon Labs AN627.\n", | |
"\n", | |
"First we load NumPy and set up some useful constants." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from __future__ import print_function\n", | |
"from enum import Enum\n", | |
"import numpy as np\n", | |
"\n", | |
"from ipywidgets import interact, interactive, fixed, interact_manual\n", | |
"import ipywidgets as widgets\n", | |
"\n", | |
"MHz=1e6\n", | |
"\n", | |
"uF=1e-6\n", | |
"nF=1e-9\n", | |
"pF=1e-12\n", | |
"\n", | |
"mH=1e-3\n", | |
"uH=uF\n", | |
"nH=nF\n", | |
"pH=pF\n", | |
"\n", | |
"mW=mH\n", | |
"\n", | |
"mA=mH\n", | |
"uA=uH\n", | |
"\n", | |
"class CHIPS(Enum):\n", | |
" Si4060 = 0 # Si4060/Si4460/Si4467\n", | |
" Si4461 = 1 # Si4461\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Next we define the design parameters:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 25, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Transmit frequency in Hz (\"operating frequency\")\n", | |
"FO = 868.0*MHz\n", | |
"\n", | |
"# RF power supply voltage in Volts\n", | |
"VDD_RF = 3.3\n", | |
"\n", | |
"# set the chip type\n", | |
"CHIP = CHIPS.Si4461\n", | |
"\n", | |
"# Shunt capacitance in Farad\n", | |
"if CHIP == CHIPS.Si4060:\n", | |
" CSHUNT = 1.25*pF\n", | |
"elif CHIP == CHIPS.Si4461:\n", | |
" CSHUNT = 2.0*pF\n", | |
"else:\n", | |
" raise ValueError(\"Invalid chiptype\")\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## 5.3.1 -- Step 1: Select a value for L_Choke ##\n", | |
"\n", | |
"This is based on a straight-line fit of the data given in section 5.3.1." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"112.19959999999999" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"lchoke = (-2.803e-16 * FO) + 3.555e-7\n", | |
"lchoke/nH" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"**TODO: pick the nearest E12 value**" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## 5.3.2 -- Step 2: Choose/calculate values for L0-C0 series-resonant tank ##\n", | |
"\n", | |
"Design guidelines:\n", | |
"\n", | |
" * The L0-C0 tank must resonate at Fo (FREQ)\n", | |
" * The value of L0 should be chosen to be as large as possible, while:\n", | |
" * Remaining low enough that self-resonance is not an issue\n", | |
" * Close to standard 5%-tolerance values" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Resonant frequency: 869.816 MHz\n", | |
"Frequency error: 0.209 %\n" | |
] | |
} | |
], | |
"source": [ | |
"L0=9.3*nH\n", | |
"C0=3.6*pF\n", | |
"fresonant = 1./(2.*np.pi*np.sqrt(L0*C0))\n", | |
"print(\"Resonant frequency: %0.3f MHz\" % (fresonant/MHz))\n", | |
"\n", | |
"# calculate error vs. FO\n", | |
"ferror = (fresonant - FO) / FO\n", | |
"print(\"Frequency error: %0.3f %%\" % (ferror * 100.0))\n", | |
"\n", | |
"# impedance at resonance -- Xl and Xc = 0, therefore Z = 0 (in theory)\n", | |
"# in practice, Z = parasitic resistance of L and C" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## 5.3.3 -- Step 3: Calculate required value for Zload ##\n", | |
"\n", | |
"Calculate the required value of load impedance to be presented to the output of the resonant tank at the operating frequency (FO)." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Load impedance: (27.0616565534+31.1884365599j) ohm\n" | |
] | |
} | |
], | |
"source": [ | |
"ANG_RAD=np.deg2rad(49.0524)\n", | |
"zload = (0.2815/(2*np.pi*FO*CSHUNT)) * (np.cos(ANG_RAD)+(1j*np.sin(ANG_RAD)))\n", | |
"print(\"Load impedance: %s ohm\" % zload)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## 5.3.4 -- Step 4, estimate the required PA_PWR_LVL register value from the calculated value of a hypothetical voltage-limiting resistor ##" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"V_DD = 1.045 V\n", | |
"I_DD = 22.387 mA\n", | |
"R_DC = 100.718 Ohms\n" | |
] | |
} | |
], | |
"source": [ | |
"POUT = 23.4*mW\n", | |
"\n", | |
"vdd = np.sqrt(POUT / (2.*(np.pi**2)*FO*CSHUNT))\n", | |
"print(\"V_DD = %0.3f V\" % (vdd))\n", | |
"\n", | |
"idd = 2.*(np.pi**2)*FO*CSHUNT*vdd\n", | |
"print(\"I_DD = %0.3f mA\" % (idd / mA))\n", | |
"\n", | |
"rdc = (VDD_RF - vdd) / idd\n", | |
"print(\"R_DC = %0.3f Ohms\" % (rdc))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Next we assume the PA is in switched programmable current-source mode (`PA_MODE.PA_MODE` = `SWC` = `1`). This is less efficient but provides better power flatness.\n", | |
"\n", | |
"We work out a set of `PA_BIAS_CLKDUTY.OB` and `PA_PWR_LVL.DDAC` values which would give the desired PA bias current." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"OB: 17 (0x11)\n", | |
"DDAC: 124 (0x7C)\n", | |
"I: 22.32 mA\n" | |
] | |
} | |
], | |
"source": [ | |
"# Set maximum DDAC value\n", | |
"if CHIP == CHIPS.Si4060:\n", | |
" DDAC_MAX = 0x7F # e.g. Si4461\n", | |
"elif CHIP == CHIPS.Si4461:\n", | |
" DDAC_MAX = 0x7F # e.g. Si4461\n", | |
"else:\n", | |
" raise ValueError(\"Invalid chiptype\")\n", | |
"\n", | |
"# Set maximum OB value\n", | |
"OB_MAX = 0x3F\n", | |
"\n", | |
"# OB = 0 = 10uA/finger, OB=1=20uA, ...\n", | |
"\n", | |
"for ob in range(0, OB_MAX):\n", | |
" # Calculate resulting per-finger current\n", | |
" i_ob = (ob + 1) * 10*uA\n", | |
" \n", | |
" # Calculate required DDAC -- round down to avoid exceeding I_DD\n", | |
" ddac = int(idd / i_ob)\n", | |
" \n", | |
" # Does this OB setting result in DDAC <= DDAC_MAX?\n", | |
" if ddac <= DDAC_MAX:\n", | |
" break\n", | |
"\n", | |
"# Back-calculate the actual current\n", | |
"iactual = ((ob + 1) * 10*uA) * ddac\n", | |
"\n", | |
" \n", | |
"print(\"OB: %3d (0x%02X)\" % (ob, ob))\n", | |
"print(\"DDAC: %3d (0x%02X)\" % (ddac, ddac))\n", | |
"print(\"I: %6.2f mA\" % (iactual/mA))" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.5.2" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
4FSK symbol mapping and preamble requirements (FLEX)
Si4x6x errata re. 4FSK
4FSK sync word
Ins and outs of non-standard preamble detection
Si446x DSA notes -- Digital Signal Arrival detector, see https://www.silabs.com/documents/public/data-sheets/Si4468-7.pdf
Unknowns for Class-E matching: the relationship between PA_PWR_LVL and switcher loss/resistance
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Useful references:
Matching network design (SiLabs knowledge base)
What is the Si4432 PA output impedance?
What are the advantages and disadvantages of switched current mode?
Class-E power vs. RDC
External PA Matching
RSSI squelching (limiting RX sensitivity)
And some about the chip:
Si4463 patch and startup delay
Alternative power amps:
Maxim MAX2601/MAX2602 (Can't find any S-parameter files)
-- MAX2602 match data for 120MHz
NXP -- ADS data but no S-params
Infineon -- S-param data available, can use with RFSim99
Dev boards:
Si4461 RF Pico Board