EPS: add calculations for battery charger and output protection

Solar_module_XY
Petr Malanik 3 years ago
parent 89fff228bc
commit 3f19319c78

@ -26,89 +26,347 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 27,
"metadata": {}, "source": [
"# Current sense aplifier preliminary design \n",
"\n",
"supply_voltage = 4.2\n",
"max_current = 2.0\n",
"acceptable_power_loss = 0.1 #watts\n",
"amp_ratios = [50,100,200]\n",
"sense_voltage = 3.3\n",
"\n",
"adc_resolution = 4096\n",
"divider_R1 = 100 # kilo-ohms\n",
"\n",
"max_power = supply_voltage * max_current\n",
"\n",
"acceptable_voltage_drop = acceptable_power_loss / supply_voltage\n",
"print(\"Acceptable voltage drop: {}V\".format(round(acceptable_voltage_drop,2)))\n",
"power_loss_percentage = acceptable_power_loss/max_power*100\n",
"print(\"Power loss percentage: {}%\".format(round(power_loss_percentage,2)))\n",
"\n",
"amp_ratios.sort()\n",
"\n",
"print(\"--------------- Full - range ---------------\")\n",
"for ratio in amp_ratios:\n",
" ideal_resistor = supply_voltage / ratio / max_current\n",
" power_loss = ideal_resistor * max_current**2\n",
"\n",
" print(\"Ideal resistor: {}R\".format(ideal_resistor))\n",
" print(\"Power loss: {}W\".format(power_loss))\n",
" print(\"--------------------------------------------\")\n",
"\n",
"if sense_voltage < supply_voltage:\n",
" divider_R2 = round((sense_voltage * divider_R1) / (supply_voltage - sense_voltage),3)\n",
" print(\"Output voltage divider: R1 = {} kΩ, R2 = {} kΩ\".format(divider_R1,divider_R2))\n",
"\n",
"max_output_voltage = min(supply_voltage, supply_voltage)\n",
"resolution = round(max_current/adc_resolution*1000,2)\n",
"print(\"Resolution: {}mA\".format(resolution))\n",
"\n",
"print(\"---------------- Acceptable ----------------\")\n",
"acceptable_resistor = acceptable_voltage_drop/max_current\n",
"power_loss = acceptable_resistor * max_current**2\n",
"\n",
"ideal_ratio = None\n",
"for ratio in amp_ratios:\n",
" if acceptable_voltage_drop * ratio < supply_voltage:\n",
" ideal_ratio = ratio\n",
" else:\n",
" break\n",
"\n",
"max_output_voltage = acceptable_voltage_drop * ideal_ratio\n",
"print(\"Maximal output voltage: {}V\".format(max_output_voltage))\n",
"\n",
"if sense_voltage < max_output_voltage:\n",
" divider_R2 = round((sense_voltage * divider_R1) / (max_output_voltage - sense_voltage),3)\n",
" print(\"Output voltage divider: R1 = {} kΩ, R2 = {} kΩ\".format(divider_R1,divider_R2))\n",
"\n",
"resolution = round(max_current/adc_resolution*1000,2)\n",
"\n",
"print(\"Ideal ratio: {}\".format(ideal_ratio))\n",
"print(\"Ideal resistor: {}R\".format(acceptable_resistor))\n",
"print(\"Power loss: {}W\".format(power_loss))\n",
"print(\"Resolution: {}mA\".format(resolution))"
],
"outputs": [ "outputs": [
{ {
"output_type": "stream", "output_type": "stream",
"name": "stdout", "name": "stdout",
"text": [ "text": [
"--------------------------------------------\nIdeal resistor: 0.0132R\nPower loss: 0.33W\n" "Acceptable voltage drop: 0.02V\n",
] "Power loss percentage: 1.19%\n",
}, "--------------- Full - range ---------------\n",
{ "Ideal resistor: 0.042R\n",
"output_type": "error", "Power loss: 0.168W\n",
"ename": "IndexError", "--------------------------------------------\n",
"evalue": "Replacement index 0 out of range for positional args tuple", "Ideal resistor: 0.021R\n",
"traceback": [ "Power loss: 0.084W\n",
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "--------------------------------------------\n",
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", "Ideal resistor: 0.0105R\n",
"\u001b[0;32m/tmp/ipykernel_112179/3645271640.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Ideal resistor: {}R\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mideal_resistor\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Power loss: {}W\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpower_loss\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Resolution: {}A\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "Power loss: 0.042W\n",
"\u001b[0;31mIndexError\u001b[0m: Replacement index 0 out of range for positional args tuple" "--------------------------------------------\n",
"Output voltage divider: R1 = 100 kΩ, R2 = 366.667 kΩ\n",
"Resolution: 0.49mA\n",
"---------------- Acceptable ----------------\n",
"Maximal output voltage: 2.380952380952381V\n",
"Ideal ratio: 100\n",
"Ideal resistor: 0.011904761904761904R\n",
"Power loss: 0.047619047619047616W\n",
"Resolution: 0.49mA\n"
] ]
} }
], ],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 4,
"source": [ "source": [
"max_sense_voltage = 3.3\n", "# Current sense aplifier design evaluating\n",
"max_output_current = 5.0\n", "\n",
"supply_voltage = 2.8\n",
"sense_voltage = 3.3\n",
"sense_resistor = 0.01\n",
"amp_ratio = 50\n",
"divider_R1 = 100 # kilo-ohms\n",
"selected_R2 = 270 # kilo-ohms\n",
"\n",
"adc_resolution = 4096\n", "adc_resolution = 4096\n",
"\n", "\n",
"max_acceptable_power_loss = 0.1\n", "max_current = supply_voltage / sense_resistor / amp_ratio\n",
"power_disipation = sense_resistor * max_current**2\n",
"voltage_drop = sense_resistor * max_current\n",
"resolution = round(max_current/adc_resolution*1000,3)\n",
"\n", "\n",
"amp_ratios = [50,100,200]\n",
"\n", "\n",
"for ratio in amp_ratios:\n", "print(\"Maximal current: {}A\".format(round(max_current,2)))\n",
"print(\"Maximal power disipation: {}W\".format(round(power_disipation,2)))\n",
"print(\"Maximal voltage drop: {}V\".format(round(voltage_drop,2)))\n",
"\n", "\n",
" ideal_resistor = max_sense_voltage/ratio / max_output_current\n", "if sense_voltage > supply_voltage:\n",
" power_loss = ideal_resistor * max_output_current**2\n", " resolution *= 1 / (supply_voltage/sense_voltage)\n",
" resolution = \n", "\n",
" print(\"--------------------------------------------\")\n", "print(\"Resolution: {} mA\".format(round(resolution,2)))\n",
" print(\"Ideal resistor: {}R\".format(ideal_resistor))\n", "\n",
" print(\"Power loss: {}W\".format(power_loss))\n", "if sense_voltage < supply_voltage:\n",
" print(\"Resolution: {}A\".format())\n", " divider_R2 = round((sense_voltage * divider_R1) / (supply_voltage - sense_voltage),2)\n",
"\n" " print(\"Output voltage divider: R1 = {} kΩ, R2 = {} kΩ\".format(divider_R1,divider_R2))\n",
] " divider_leakage = supply_voltage / ((divider_R1 + divider_R2)*1000)\n",
}, " print(\"Maximum divider leakage: {} uA\".format(round(divider_leakage*1000000),2))\n",
{ "\n",
"cell_type": "code", "print(\"---------------- Selected divider ----------------\")\n",
"execution_count": 14, "maximum_divider_voltage = supply_voltage * (selected_R2 / (selected_R2 + divider_R1))\n",
"metadata": {}, "print(\"Maximum divider voltage: {} V\".format(round(maximum_divider_voltage,2)))\n",
"resolution *= 1 / (maximum_divider_voltage/sense_voltage)\n",
"print(\"Resolution: {} mA\".format(round(resolution,2)))"
],
"outputs": [ "outputs": [
{ {
"output_type": "stream", "output_type": "stream",
"name": "stdout", "name": "stdout",
"text": [ "text": [
"Length: 1.1136363636363635\nWraps: 16.880069721867685\n" "Maximal current: 2.8A\n",
"Maximal power disipation: 0.08W\n",
"Maximal voltage drop: 0.03V\n",
"Resolution: 0.81 mA\n",
"---------------- Selected divider ----------------\n",
"Maximum divider voltage: 2.04 V\n",
"Resolution: 1.3 mA\n"
] ]
} }
], ],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 1,
"source": [ "source": [
"# Battery heating wire calculator\n",
"import math\n", "import math\n",
"\n", "\n",
"bat_diameter = 21\n", "bat_diameter = 21 # in mm\n",
"wrap_length = bat_diameter * math.pi / 1000\n", "heating_power = 2 # watts\n",
"heating_power = 2\n", "voltage = 3.7\n",
"voltage = 3.5\n",
"wire_resistance = 5.5 # per meter\n", "wire_resistance = 5.5 # per meter\n",
"\n", "\n",
"wrap_length = bat_diameter * math.pi / 1000\n",
"current = heating_power / voltage\n", "current = heating_power / voltage\n",
"resistance = voltage / current\n", "resistance = voltage / current\n",
"length = resistance / wire_resistance\n", "length = resistance / wire_resistance\n",
"wraps = length / wrap_length\n", "wraps = length / wrap_length\n",
"\n", "\n",
"print(\"Length: {}\".format(length))\n", "print(\"Length: {}\".format(length))\n",
"print(\"Wraps: {}\".format(wraps))\n", "print(\"Wraps: {}\".format(wraps))"
],
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Length: 1.2445454545454548\n",
"Wraps: 18.86433914223418\n"
]
}
],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 24,
"source": [
"# LTC4231\n",
"\n",
"# Voltage settings\n",
"undervoltage_rising = 3\n",
"undervoltage_falling = 2.9\n",
"overvoltage_falling = 4.4\n",
"input_voltage = 3.7\n",
"\n",
"# Design parameters\n",
"resistance_total = 2000000\n",
"overcurrent_threshold = 5\n",
"soa_time = 0.0005\n",
"\n",
"# Sence voltage constants from LTC4231 datasheet\n",
"sense_voltage_slow = 0.05\n",
"sense_voltage_min = 0.065\n",
"sense_voltage_fast = 0.08\n",
"sense_voltage_max = 0.09\n",
"\n",
"R4 = (0.795/overvoltage_falling) * resistance_total\n",
"R3 = ((overvoltage_falling/undervoltage_rising) - 1) * R4\n",
"R2 = ((undervoltage_rising/undervoltage_falling) - 1) * (overvoltage_falling/undervoltage_rising) * R4\n",
"R1 = ((overvoltage_falling/0.795) - 1) * R4 - R3 - R2\n",
"\n",
"print(\"R4 value = {}k\".format(round(R4/1000)))\n",
"print(\"R3 value = {}k\".format(round(R3/1000)))\n",
"print(\"R2 value = {}k\".format(round(R2/1000)))\n",
"print(\"R1 value = {}k\".format(round(R1/1000)))\n",
"\n",
"divider_leakage = input_voltage/(R1 + R2 + R3 + R4)\n",
"sense_resistor = sense_voltage_slow/overcurrent_threshold\n",
"current_limit_fast = sense_voltage_fast / sense_resistor\n",
"sense_resistor_power = sense_resistor * current_limit_fast**2\n",
"current_limit_max = sense_voltage_max/sense_resistor\n",
"\n",
"print(\"Divider leakage = {} uA\".format(divider_leakage*1000000))\n",
"print(\"Sensing resistor = {} mR\".format(sense_resistor*1000))\n",
"print(\"Sensing resistor power dissipation = {} W\".format(sense_resistor_power))\n",
"print(\"Worst case current = {} A\".format(current_limit_max))\n",
"\n",
"load_capacitor_charge = (0.0001 * input_voltage) / (sense_voltage_min / sense_resistor)\n",
"mosfet_dissipation = input_voltage * current_limit_max\n",
"overcurrent_triptime = (soa_time - load_capacitor_charge)/4 + load_capacitor_charge\n",
"timer_capacitor = overcurrent_triptime/input_voltage\n",
"\n",
"print(\"OC timer charge = {} ms\".format(round(load_capacitor_charge*1000,2)))\n",
"print(\"MOSFET power dissipation = {} W\".format(round(mosfet_dissipation,2)))\n",
"print(\"Time to OC protection trip = {} ms\".format(round(overcurrent_triptime*1000,2)))\n",
"print(\"Timer capacitor C_T value = {} nF\".format(round(timer_capacitor*1000000,2)))"
],
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"R4 value = 361k\n",
"R3 value = 169k\n",
"R2 value = 18k\n",
"R1 value = 1452k\n",
"Divider leakage = 1.85 uA\n",
"Sensing resistor = 10.0 mR\n",
"Sensing resistor power dissipation = 0.64 W\n",
"Worst case current = 9.0 A\n",
"OC timer charge = 0.06 ms\n",
"MOSFET power dissipation = 33.3 W\n",
"Time to OC protection trip = 0.17 ms\n",
"Timer capacitor C_T value = 45.32 nF\n"
]
}
],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 22,
"source": [
"#BQ25798\n",
"\n",
"## Termistor settings\n",
"# JEITA profile temperature points\n",
"temp_T1 = 0 # °C\n",
"temp_T5 = 60\n",
"\n", "\n",
"# NTC resistance at temperature points\n",
"termistor_at_T1 = 29250.0\n",
"termistor_at_T5 = 2900.0\n",
"\n",
"# Voltage of temperature level in fraction of REGN voltage\n",
"temp_T1_threshold = 0.733\n",
"temp_T5_threshold = 0.342\n",
"\n",
"resistor_RT2 = (termistor_at_T1*termistor_at_T5 * ((1.0/temp_T5_threshold)-(1.0/temp_T1_threshold))) / ((termistor_at_T1 * ((1.0/temp_T1_threshold) - 1))-(termistor_at_T5 * ((1.0/temp_T5_threshold) - 1)))\n",
"resistor_RT1 = ((1.0/temp_T1_threshold) - 1) / ( (1.0 / resistor_RT2) + (1.0/termistor_at_T1) )\n",
"\n",
"print(\"Battery termistor resistor network\")\n",
"print(\"RT1 = {} k\".format(round(resistor_RT1/1000,2)))\n",
"print(\"RT2 = {} k\".format(round(resistor_RT2/1000,2)))\n",
"\n",
"## Input current limitation\n",
"maximal_input_current_draw = 0.9 # in Amp\n",
"divider_R1 = 100 # in kOhms\n",
"\n",
"voltage_REGN = 4.8\n",
"\n",
"voltage_ILIM = 1 + 0.8 * maximal_input_current_draw\n",
"divider_R2 = round((voltage_ILIM * divider_R1) / (voltage_REGN - voltage_ILIM),3)\n",
"print(\"ILIM voltage divider: R1 = {} kΩ, R2 = {} kΩ\".format(divider_R1,divider_R2))\n",
"\n", "\n",
"\n" "\n"
] ],
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Battery termistor resistor network\n",
"RT1 = 5.02 k\n",
"RT2 = 26.07 k\n",
"ILIM voltage divider: R1 = 100 kΩ, R2 = 55.844 kΩ\n"
]
}
],
"metadata": {}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 42,
"metadata": {}, "source": [
"outputs": [], "# TPS6300\n",
"source": [] "\n",
"output_voltages = [1.8,3.3,5.0]\n",
"resistor_R2 = 200 # in kOhms, recommended 100-500 kR\n",
"\n",
"feedback_voltage = 0.5 # V\n",
"\n",
"for output_voltage in output_voltages:\n",
" resistor_R1 = resistor_R2 * (output_voltage/feedback_voltage-1)\n",
" print(\"Resistor R2 for output voltage {} V is: {} kΩ\".format(output_voltage, resistor_R1))\n"
],
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Resistor R2 for output voltage 1.8 V is: 520.0 kΩ\n",
"Resistor R2 for output voltage 3.3 V is: 1120.0 kΩ\n",
"Resistor R2 for output voltage 5.0 V is: 1800.0 kΩ\n"
]
}
],
"metadata": {}
} }
] ]
} }
Loading…
Cancel
Save