diff --git a/.gitignore b/.gitignore
index 7ea2a23..e8b42d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,9 +71,11 @@ software/FlowMeasurement/*.png
firmware/.settings/*.prefs
firmware/.project
firmware/Debug/*
+firmware/Debug*
firmware/Release/*
*.launch
# EmBitz
*.ebTemp
+*.fail
diff --git a/.gitmodules b/.gitmodules
index dd06663..00dbe41 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -8,3 +8,6 @@
[submodule "Kicad-Wago-733"]
path = Kicad-Wago-733
url = https://github.com/phd0/Kicad-Wago-733.git
+[submodule "simulations/PyLTSpice"]
+ path = simulations/PyLTSpice
+ url = https://github.com/nunobrum/PyLTSpice.git
diff --git a/README.md b/README.md
index 3d2072e..6400aca 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+[](https://aisler.net/p/new?url=https://github.com/JochiSt/OpenFlowMeter/blob/main/OpenFlowMeter.kicad_pcb&ref=github)
# OpenFlowMeter
## Purpose
Measuring flow of gases and maybe liquids.
diff --git a/firmware/.cproject b/firmware/.cproject
index 7edf440..95cd6f3 100644
--- a/firmware/.cproject
+++ b/firmware/.cproject
@@ -25,7 +25,7 @@
-
+
@@ -164,6 +164,270 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -181,6 +445,9 @@
+
+
+
diff --git a/firmware/Inc/config.h b/firmware/Inc/config.h
index ae3c35d..eb714bc 100644
--- a/firmware/Inc/config.h
+++ b/firmware/Inc/config.h
@@ -6,7 +6,7 @@ extern "C" {
#endif
#include
-
+#include "pcb_version.h"
#include "pid.h"
#define ISATURATION_LSB 3970
@@ -14,6 +14,7 @@ extern "C" {
extern const float LSB2U;
extern const float LSB2I;
+extern const float U2I;
typedef struct {
float Ugain;
@@ -83,10 +84,19 @@ typedef struct {
* only the high gain is stored here, the lower gain is always 1
* @{
*/
+#if defined(PCB_V2)
gain_config_t GAIN[2];
+#endif
/** @}*/
+#if defined(PCB_V3)
+ float U_R1[2];
+ float U_R2[2];
+ float I_R1[2];
+ float I_R2[2];
+#endif
+
/** @}*/
} config_t;
diff --git a/firmware/Inc/pcb_version.h b/firmware/Inc/pcb_version.h
new file mode 100644
index 0000000..f262638
--- /dev/null
+++ b/firmware/Inc/pcb_version.h
@@ -0,0 +1,30 @@
+#pragma once
+
+/**
+ * PCB v1 compatibility mode
+ */
+//#define PCB_V1
+/******************************************************************************/
+/**
+ * PCB v2 compatibility mode
+ * enables:
+ * - dual gain ADC readout
+ * - I2C sensor readout
+ */
+//#define PCB_V2
+#if defined(PCB_V2)
+#undef PCB_V1
+#endif
+/******************************************************************************/
+/**
+ * PCB v3 compatibility mode
+ * enables:
+ * - dual gain ADC readout
+ * - offset for ADC / differential amplifier
+ * - I2C sensor readout
+ */
+//#define PCB_V3
+#if defined(PCB_V3)
+#undef PCB_V1
+#undef PCB_V2
+#endif
diff --git a/firmware/Inc/utils.h b/firmware/Inc/utils.h
index 5b7e7b3..044cbb1 100644
--- a/firmware/Inc/utils.h
+++ b/firmware/Inc/utils.h
@@ -25,5 +25,6 @@ uint8_t upper(uint16_t val);
uint8_t lower(uint16_t val);
float convertPT100_R2T(float resistance);
+float getVoltageBeforeAmplifier(float Uadc, float Ubias, float R1, float R2);
#endif //__UTILS_H__
diff --git a/firmware/Src/config.c b/firmware/Src/config.c
index d341e26..f03c1e5 100644
--- a/firmware/Src/config.c
+++ b/firmware/Src/config.c
@@ -10,6 +10,8 @@ config_t cfg;
const float LSB2U = 3.3 / 4096;
const float LSB2I = 3.3 / 4096 * 10e-3;
+const float U2I = 10e-3; // TODO insert right value here
+
void generateDefaultCFG(config_t *cfg){
// set the board ID
cfg->board_ID = 1;
@@ -39,6 +41,7 @@ void generateDefaultCFG(config_t *cfg){
cfg->PID_flags.PID0_active = 0;
cfg->PID_flags.PID1_active = 0;
+#if defined(PCB_V2)
// gain settings from calculations / optimisation
cfg->GAIN[0].Igain = 1 + 47.0e3 / 5.6e3;
cfg->GAIN[0].Ugain = 1 + 33.0e3 / 5.6e3;
@@ -49,6 +52,16 @@ void generateDefaultCFG(config_t *cfg){
cfg->GAIN[1].Ugain = 1 + 33.0e3 / 5.6e3;
cfg->GAIN[1].Ibias = 0.12;
cfg->GAIN[1].Ubias = 0.01;
+#endif
+#if defined(PCB_V3)
+ for(int i=0; i<2; i++){
+ cfg->U_R1[i] = 47e3;
+ cfg->U_R2[i] = 5.6e3;
+ cfg->I_R1[i] = 47e3;
+ cfg->I_R2[i] = 5.6e3;
+ }
+#endif
+
}
/**
@@ -69,13 +82,23 @@ void printCfg(config_t *cfg){
printf("SMOO: %d\r\n", cfg->SMOO);
printf("SMOOMAX: %d\r\n", cfg->SMOO_MAX);
+#if defined(PCB_V2)
printf("\r\n");
- printf("Gain:");
+ printf("Gain:\r\n");
printf(" CH0 I %f U%f\r\n", cfg->GAIN[0].Igain, cfg->GAIN[0].Ugain);
printf(" CH1 I %f U%f\r\n", cfg->GAIN[1].Igain, cfg->GAIN[1].Ugain);
- printf("Offset:");
+ printf("Offset:\r\n");
printf(" CH0 I %f U%f\r\n", cfg->GAIN[0].Ibias, cfg->GAIN[0].Ubias);
printf(" CH1 I %f U%f\r\n", cfg->GAIN[1].Ibias, cfg->GAIN[1].Ubias);
+#endif
+#if defined(PCB_V3)
+ printf("\r\n");
+ printf("Resistors:\r\n");
+ for(int i=0; i<2; i++){
+ printf(" U R1 %f R2 %f\r\n", cfg->U_R1[i], cfg->U_R2[i]);
+ printf(" I R1 %f R2 %f\r\n", cfg->I_R1[i], cfg->I_R2[i]);
+ }
+#endif
printf("\r\n");
printf("PID 0: (%d)\r\n", cfg->PID_flags.PID0_active);
diff --git a/firmware/Src/main.c b/firmware/Src/main.c
index 3e84ad6..24a8a28 100644
--- a/firmware/Src/main.c
+++ b/firmware/Src/main.c
@@ -30,6 +30,7 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
+#include "pcb_version.h"
#include "syscalls.h"
#include "utils.h"
#include "i2c_scanner.h"
@@ -57,34 +58,7 @@
//#define PRINT_UART_ADC // print the ADC data
//#define PRINT_UART_CALC_TEMP // print the calculated temperatures
/******************************************************************************/
-/**
- * PCB v1 compatibility mode
- */
-#define PCB_V1
-/******************************************************************************/
-/**
- * PCB v2 compatibility mode
- * enables:
- * - dual gain ADC readout
- * - I2C sensor readout
- */
-//#define PCB_V2
-#if defined(PCB_V2)
-#undef PCB_V1
-#define I2C_SENSOR_READOUT
-#endif
-/******************************************************************************/
-/**
- * PCB v3 compatibility mode
- * enables:
- * - dual gain ADC readout
- * - offset for ADC / differential amplifier
- * - I2C sensor readout
- */
-//#define PCB_V3
-#if defined(PCB_V3)
-#undef PCB_V1
-#undef PCB_V2
+#if defined(PCB_V2) || defined(PCB_V3)
#define I2C_SENSOR_READOUT
#endif
/******************************************************************************/
@@ -399,8 +373,17 @@ int main(void)
// calculate coarse current and voltage for each channel
for(int i=0; i<2; i++){
+#if defined(PCB_V1)
+ current[i] = (*avr_current[i][0] * LSB2I);
+ voltage[i] = (*avr_voltage[i][0] * LSB2U);
+#elif defined(PCB_V2)
current[i] = (*avr_current[i][0] * LSB2I) + cfg.GAIN[i].Ibias/1000.;
voltage[i] = (*avr_voltage[i][0] * LSB2U) + cfg.GAIN[i].Ubias;
+#elif defined(PCB_V3)
+ // TODO implement proper voltage / current reading
+ current[i] = (*avr_current[i][0] * LSB2I);
+ voltage[i] = (*avr_voltage[i][0] * LSB2U);
+#endif
}
#if defined(PCB_V2)
@@ -436,10 +419,22 @@ int main(void)
offset[i] = 3.3 * (*PWMoffset[i]) / 4096;
}
- // adjust the offset voltage
-
- // if offset voltage is fine, we can use the high gain
-
+ for(int i=0; i<2; i++){
+ // check for saturation
+ if(*avr_voltage[i][1] >= USATURATION_LSB || *avr_current[i][1] >= ISATURATION_LSB){
+ // one of the high gain measurement is in saturation
+ // adjust the offset voltage
+ *PWMoffset[i] += 10;
+ continue;
+ }else if(*avr_voltage[i][1] == 0 || *avr_current[i][1] == 0){
+ *PWMoffset[i] += 10;
+ continue;
+ }else{
+ // if offset voltage is fine, we can use the high gain
+ voltage[i] = getVoltageBeforeAmplifier(*avr_voltage[i][1] * LSB2U, offset[i], cfg.U_R1[i], cfg.U_R2[i]);
+ current[i] = getVoltageBeforeAmplifier(*avr_current[i][1] * LSB2U, offset[i], cfg.I_R1[i], cfg.I_R2[i]) * U2I;
+ }
+ }
#endif
/** calculate temperatures ********************************************/
for(int i=0; i<2; i++){
@@ -449,23 +444,24 @@ int main(void)
/** run the PID controllers *******************************************/
for(int i=0; i<2; i++){
runPID(&pid[i]);
-
/** update the output, if the PID is active *************************/
if(pid[0].active){
*PWMcurrent[i] = PIDout[i];
}else{
*PWMcurrent[i] = PWM[i];
}
+ /** update the offset ***********************************************/
+ *PWMoffset[i] = 0.9 * (*PWMcurrent[i]);
}
- // link the PID active to the configuration active
+ /** link the PID active to the configuration active *******************/
pid[0].active = cfg.PID_flags.PID0_active;
pid[1].active = cfg.PID_flags.PID1_active;
}
- /*************************************************************************
+ /***************************************************************************
* Print some variables via UART
- ************************************************************************/
+ **************************************************************************/
if( cnt_print_uart >= cfg.interval_PRINT_UART
&& cfg.interval_PRINT_UART < 255
){
diff --git a/firmware/Src/utils.c b/firmware/Src/utils.c
index 153507d..dab8dca 100644
--- a/firmware/Src/utils.c
+++ b/firmware/Src/utils.c
@@ -19,3 +19,14 @@ float convertPT100_R2T(float resistance){
const float R0 = 100;
return (resistance - R0)/(R0 * A);
}
+
+/**
+ * calculate the voltage before the biases amplifier
+ * @param Ubias bias voltage
+ * @param Uadc measured voltage of the ADC (amplifier output)
+ * @param R1 gain setting resistor (upper)
+ * @param R2 gain setting resistor (lower)
+ */
+float getVoltageBeforeAmplifier(float Uadc, float Ubias, float R1, float R2){
+ return (R1 * Ubias + R2 * Uadc)/(R1 + R2);
+}
diff --git a/firmware/calculations/offset_amplifier.py b/firmware/calculations/offset_amplifier.py
new file mode 100644
index 0000000..a64f835
--- /dev/null
+++ b/firmware/calculations/offset_amplifier.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+
+"""
+from sympy import Symbol, symbols, solve, pprint, Eq
+
+Up, Un = symbols("U_+, U_-")
+
+
+Uadc = Symbol("U_adc")
+Ubias = Symbol("U_bias")
+
+R1, R2 = symbols("R_1, R_2")
+
+I_R1R2 = (Uadc - Ubias) / (R1 + R2)
+
+Un = I_R1R2 * R2 + Ubias
+
+eq1 = Eq( Up , Un )
+pprint(eq1)
+
+Uin = symbols("U_in")
+eq1 = eq1.subs(Up, Uin)
+pprint(eq1)
+
+sol = solve(eq1, Uin)[0].factor()
+pprint(sol)
+
diff --git a/simulations/CurrentSource/current_source_mod_v1.asc b/simulations/CurrentSource/current_source_mod_v1.asc
index a42f60a..3dc6406 100644
--- a/simulations/CurrentSource/current_source_mod_v1.asc
+++ b/simulations/CurrentSource/current_source_mod_v1.asc
@@ -197,7 +197,7 @@ SYMATTR Value 8
SYMBOL res 352 912 R0
SYMATTR InstName R19
SYMATTR Value 8
-TEXT -768 712 Left 2 !.dc V3 0 3.3 0.1\n.param R_PT100 100
+TEXT -768 712 Left 2 ;.dc V3 0 3.3 0.1\n.param R_PT100 100
TEXT -552 216 Left 2 ;R2 and R4 define current per input voltage
TEXT -760 472 Left 2 ;max. 3.3V
TEXT -384 504 Left 2 ;"protection" resistor
@@ -206,6 +206,7 @@ TEXT -80 832 Left 2 ;PT100 temperature sensor
TEXT -760 880 Left 2 ;.tran 1\n.save V(voltage_measure) V(current_measure) I(Pt100)\n.step param R_PT100 100 150 10\n.measure Vmeas_avg avg V(voltage_measure)\n.measure Imeas_avg avg V(current_measure)\n.measure Ipt100_avg avg I(Pt100)
TEXT -784 848 Left 3 ;Simulate current vs PT100
TEXT -784 680 Left 3 ;Simulate current vs input voltage
+TEXT -1328 536 Left 2 !.tran 1\n.TEMP=30\n.param R_PT100 {100*(1+3.85e-3*TEMP)}
LINE Normal 576 192 576 608 2
LINE Normal 1376 192 576 192 2
LINE Normal 576 608 1376 608 2
diff --git a/simulations/CurrentSource/simulate_current_source.py b/simulations/CurrentSource/simulate_current_source.py
new file mode 100644
index 0000000..e8c8732
--- /dev/null
+++ b/simulations/CurrentSource/simulate_current_source.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+"""
+
+"""
+import os
+import sys
+
+from functools import partial # import partial for tweaking callback
+import numpy as np
+
+sys.path.append("../PyLTSpice/")
+from PyLTSpice import SimCommander, LTSteps, RawRead
+
+sys.path.append("../../software/")
+sys.path.append("../../software/pyUSBtin")
+from OpenFlowMeter import PT100
+
+def processing_data(raw_filename, log_file, Uset):
+ print("Handling the simulation data of %s, log file %s" % (raw_filename, log_file))
+ LTR = RawRead(raw_filename)
+ # print all stored traces
+ #print(LTR.get_trace_names())
+
+ # print simulation properties
+ #print(LTR.get_raw_property())
+
+ current_setpoint= np.mean(LTR.get_trace("V(current_setpoint)").get_wave(0))
+
+ current_pt100 = np.mean(LTR.get_trace("I(PT100)").get_wave(0))*1000
+
+ current_measure = np.mean(LTR.get_trace("V(current_measure)").get_wave(0))
+ voltage_measure = np.mean(LTR.get_trace("V(voltage_measure)").get_wave(0))
+
+ print("I set ", current_setpoint)
+ print("I PT100 ", current_pt100)
+ print("I measure", current_measure)
+ print("U measure", voltage_measure)
+
+ R_PT100 = voltage_measure / (current_measure * 10 / 1000)
+ print("R_PT100: ", R_PT100)
+ print("Temperature", PT100.convertPT100_T(R_PT100))
+
+
+# select spice model
+
+LTC = SimCommander(
+ "./current_source_mod_v1.asc",
+ parallel_sims=2 # limit number of parallel simulations)
+ )
+LTC.set_parameters(temp=40)
+
+for Uset in [0.5, 1, 1.5, 2, 2.5, 3, 3.3]:
+ LTC.set_component_value('V3', Uset)
+ LTC.run(callback=partial(processing_data, Uset=None))
+
+LTC.wait_completion()
+
+# Sim Statistics
+print('Successful/Total Simulations: ' + str(LTC.okSim) + '/' + str(LTC.runno))
\ No newline at end of file
diff --git a/simulations/OFMfull/BiasGainAmplifier.asc b/simulations/OFMfull/BiasGainAmplifier.asc
new file mode 100644
index 0000000..9b0bc0d
--- /dev/null
+++ b/simulations/OFMfull/BiasGainAmplifier.asc
@@ -0,0 +1,90 @@
+Version 4
+SHEET 1 1604 680
+WIRE 112 -352 80 -352
+WIRE 112 -336 112 -352
+WIRE 80 -304 80 -352
+WIRE -128 -288 -176 -288
+WIRE 48 -288 -128 -288
+WIRE 160 -272 112 -272
+WIRE 224 -272 160 -272
+WIRE 384 -272 304 -272
+WIRE 528 -272 384 -272
+WIRE 544 -272 528 -272
+WIRE 48 -256 16 -256
+WIRE 384 -256 384 -272
+WIRE 528 -256 528 -272
+WIRE 80 -224 80 -240
+WIRE 160 -192 160 -272
+WIRE -496 -160 -496 -176
+WIRE 384 -160 384 -192
+WIRE 528 -160 528 -176
+WIRE 16 -96 16 -256
+WIRE 160 -96 160 -112
+WIRE 160 -96 16 -96
+WIRE 160 -80 160 -96
+WIRE -496 -64 -496 -80
+WIRE 160 64 160 0
+WIRE 272 64 160 64
+WIRE 416 64 352 64
+WIRE 320 240 320 192
+WIRE 160 272 160 64
+WIRE 288 272 160 272
+WIRE 416 272 416 64
+WIRE 416 272 352 272
+WIRE 480 272 416 272
+WIRE 288 304 224 304
+WIRE 96 336 32 336
+WIRE 224 336 224 304
+WIRE 224 336 96 336
+WIRE 320 368 320 336
+FLAG -496 -64 0
+FLAG -496 -176 +3V3
+FLAG 80 -224 +3V3
+FLAG 112 -336 0
+FLAG 528 -160 0
+FLAG 544 -272 AMPout
+IOPIN 544 -272 Out
+FLAG 96 336 GainSwitch
+FLAG -128 -288 AMPin
+FLAG 384 -160 0
+FLAG 320 368 0
+FLAG 320 192 +3V3
+FLAG -176 -288 AMPin
+IOPIN -176 -288 In
+FLAG 32 336 SWITCH
+IOPIN 32 336 In
+FLAG 480 272 Ubias
+IOPIN 480 272 In
+SYMBOL res 144 -96 R0
+WINDOW 3 34 86 Left 2
+SYMATTR Value 5k6
+SYMATTR InstName R2
+SYMBOL voltage -496 -176 R0
+WINDOW 123 0 0 Left 0
+WINDOW 39 0 0 Left 0
+SYMATTR InstName V3
+SYMATTR Value 3.3
+SYMBOL res 512 -272 R0
+SYMATTR InstName R5
+SYMATTR Value 10k
+SYMBOL res 144 -208 R0
+SYMATTR InstName R1
+SYMATTR Value 39k
+SYMBOL cap 368 -256 R0
+SYMATTR InstName C1
+SYMATTR Value 100n
+SYMBOL res 320 -288 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R6
+SYMATTR Value 100
+SYMBOL Opamps\\LT1491 80 -208 M180
+SYMATTR InstName U3
+SYMBOL ZZZ\\SwitchAnalog\\cd4066 320 288 R0
+WINDOW 38 3 35 Left 0
+SYMATTR InstName U2
+SYMBOL res 368 48 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R3
+SYMATTR Value 10Meg
diff --git a/simulations/OFMfull/BiasGainAmplifier.asy b/simulations/OFMfull/BiasGainAmplifier.asy
new file mode 100644
index 0000000..8d1a390
--- /dev/null
+++ b/simulations/OFMfull/BiasGainAmplifier.asy
@@ -0,0 +1,16 @@
+Version 4
+SymbolType BLOCK
+RECTANGLE Normal -112 -56 112 56
+WINDOW 0 0 -56 Bottom 2
+PIN -112 -32 LEFT 8
+PINATTR PinName AMPin
+PINATTR SpiceOrder 1
+PIN -112 0 LEFT 8
+PINATTR PinName SWITCH
+PINATTR SpiceOrder 2
+PIN -112 32 LEFT 8
+PINATTR PinName Ubias
+PINATTR SpiceOrder 3
+PIN 112 0 RIGHT 8
+PINATTR PinName AMPout
+PINATTR SpiceOrder 4
diff --git a/simulations/OFMfull/OFMfull.asc b/simulations/OFMfull/OFMfull.asc
new file mode 100644
index 0000000..bcffd5c
--- /dev/null
+++ b/simulations/OFMfull/OFMfull.asc
@@ -0,0 +1,79 @@
+Version 4
+SHEET 1 1380 1152
+WIRE 528 272 432 272
+WIRE 528 304 448 304
+WIRE 992 304 752 304
+WIRE 1024 304 992 304
+WIRE 528 336 464 336
+WIRE 208 432 160 432
+WIRE 432 432 432 272
+WIRE 432 432 208 432
+WIRE -608 448 -688 448
+WIRE -400 448 -400 432
+WIRE -400 448 -432 448
+WIRE -368 448 -400 448
+WIRE 208 464 160 464
+WIRE 432 464 208 464
+WIRE -688 496 -688 448
+WIRE 432 544 432 464
+WIRE 528 544 432 544
+WIRE 48 576 -128 576
+WIRE 448 576 448 304
+WIRE 448 576 48 576
+WIRE 528 576 448 576
+WIRE 992 576 752 576
+WIRE 1024 576 992 576
+WIRE -688 608 -688 576
+WIRE 400 608 336 608
+WIRE 464 608 464 336
+WIRE 464 608 400 608
+WIRE 528 608 464 608
+WIRE -128 640 -128 576
+WIRE 128 656 64 656
+WIRE 336 656 336 608
+WIRE 336 656 304 656
+WIRE 64 704 64 656
+WIRE -128 736 -128 720
+WIRE 64 816 64 784
+FLAG -400 432 current_setpoint
+FLAG 400 608 UBias
+FLAG 48 576 Switch
+FLAG 992 304 IADC
+FLAG 992 576 UADC
+FLAG -128 736 0
+FLAG 208 432 Imeas
+FLAG 208 464 Umeas
+FLAG -688 608 0
+FLAG -688 448 IPWM
+FLAG 64 816 0
+SYMBOL current_source -112 448 R0
+SYMATTR InstName X1
+SYMBOL BiasGainAmplifier 640 304 R0
+SYMATTR InstName X2
+SYMBOL BiasGainAmplifier 640 576 R0
+SYMATTR InstName X3
+SYMBOL voltage -128 624 R0
+WINDOW 123 0 0 Left 0
+WINDOW 39 0 0 Left 0
+SYMATTR InstName Vswitch
+SYMATTR Value {Uswitch}
+SYMBOL voltage -688 480 R0
+WINDOW 3 39 42 Left 2
+WINDOW 123 0 0 Left 0
+WINDOW 39 0 0 Left 0
+SYMATTR InstName V3
+SYMATTR Value PULSE(0 3.3 0 1n 1n {Ton_I} {Tperiod})
+SYMBOL pwm_filter_v1 -528 448 R0
+SYMATTR InstName X4
+SYMBOL voltage 64 688 R0
+WINDOW 3 39 42 Left 2
+WINDOW 123 0 0 Left 0
+WINDOW 39 0 0 Left 0
+SYMATTR InstName V4
+SYMATTR Value PULSE(0 3.3 0 1n 1n {Ton_B} {Tperiod})
+SYMBOL pwm_filter_v1 208 656 R0
+SYMATTR InstName X5
+TEXT -280 264 Left 2 !.tran 0 30ms 20ms startup uic\n;.op\n.TEMP=30
+TEXT -640 624 Left 2 !.options gmin=1e-10\n.options abstol=1e-10\n.options reltol=0.003\n.options chgtol=1e-14\n.options trtol=1\n.options sstol=0.001\n.options MinDeltaGmin=0.0001\n \n.options srcsteps=0
+TEXT -1312 32 Left 2 !* calculate PWM frequency\n* MasterClock Frequency = 54MHz\n.param FCLK={54Meg}\n \n* ARR = 10bit = 1024\n* ARR = 12bit = 4096\n.param ARR = {4096}\n \n* Prescaler\n.param PSC ={0}\n \n * calculate PWM frequency\n.param FPWM = { FCLK / ( (ARR + 1) * (PSC + 1) ) }\n.param Tperiod = { 1 / FPWM }\n \n* PWM timer setting\n.param CCR_I = 2048\n.param CCR_B = 2048\n \n * calculate DutyCycle\n.param DutyCycle_I = { CCR_I / ARR }\n.param DutyCycle_B = { CCR_B / ARR }\n \n* calculate Pulse Parameters\n.param Ton_I ={DutyCycle_I / FPWM}\n.param Ton_B={DutyCycle_B / FPWM}
+TEXT -640 920 Left 2 !.step param Uswitch list 0 3.3
diff --git a/simulations/OFMfull/TestCurrentSource.asc b/simulations/OFMfull/TestCurrentSource.asc
new file mode 100644
index 0000000..f325739
--- /dev/null
+++ b/simulations/OFMfull/TestCurrentSource.asc
@@ -0,0 +1,24 @@
+Version 4
+SHEET 1 1380 1152
+WIRE 208 432 160 432
+WIRE 432 432 208 432
+WIRE -400 448 -400 432
+WIRE -400 448 -448 448
+WIRE -368 448 -400 448
+WIRE -448 464 -448 448
+WIRE 208 464 160 464
+WIRE 432 464 208 464
+WIRE -448 560 -448 544
+FLAG -400 432 current_setpoint
+FLAG 208 432 Imeas
+FLAG 208 464 Umeas
+FLAG -448 560 0
+SYMBOL current_source -112 448 R0
+SYMATTR InstName X1
+SYMBOL voltage -448 448 R0
+WINDOW 123 0 0 Left 0
+WINDOW 39 0 0 Left 0
+SYMATTR InstName V1
+SYMATTR Value PULSE(0 3.3 0.1 1 1 0 2)
+TEXT -280 264 Left 2 !.tran 1.1\n;.op\n.TEMP=30
+TEXT -640 624 Left 2 ;.options gmin=1e-10\n.options abstol=1e-10\n.options reltol=0.003\n.options chgtol=1e-14\n.options trtol=1\n.options sstol=0.001\n.options MinDeltaGmin=0.0001\n \n.options srcsteps=0
diff --git a/simulations/OFMfull/analyse_OFMfull.py b/simulations/OFMfull/analyse_OFMfull.py
new file mode 100644
index 0000000..ce36c9c
--- /dev/null
+++ b/simulations/OFMfull/analyse_OFMfull.py
@@ -0,0 +1,214 @@
+# -*- coding: utf-8 -*-
+"""
+
+"""
+import matplotlib.pyplot as plt
+import numpy as np
+
+from simADC import SimADC
+
+def PWM2Voltage(PWM):
+ return 3.3 * PWM / 4096
+
+def getVoltageBeforeAmplifier(UADC, Uoffset, R1=39e3, R2=5.6e3):
+ return (R1 * Uoffset + R2 * UADC)/(R1 + R2)
+
+def LSB2U(LSB):
+ return LSB / 4096 * 3.3
+
+def U2I(U):
+ """
+ converts measured OFM current voltage into mA
+ """
+ return U * 10e-3 * 1000
+
+def analyse_OFMfull(filename):
+ if not filename:
+ return
+
+ npzfile = np.load(filename)
+
+ result_PWM_I = npzfile['result_PWM_I'].astype(float)
+ result_PWM_B = npzfile['result_PWM_B'].astype(float)
+ result_uadc_in = npzfile['result_uadc_in']
+ result_iadc_in = npzfile['result_iadc_in']
+ result_uswitch = npzfile['result_uswitch']
+
+ result_uadc = SimADC(result_uadc_in)
+ result_iadc = SimADC(result_iadc_in)
+
+ fig, ax = plt.subplots(2, 1, figsize=(8,10))
+
+ switch_off = np.where(result_uswitch < 1.0 )
+ switch_on = np.where(result_uswitch > 1.0 )
+
+ switch_pos = [switch_off, switch_on]
+
+ ###########################################################################
+ # PWM
+ color = 'tab:blue'
+ for i in [0,1]:
+ ax[i].set_ylabel("ADC input voltage", color=color)
+ ax[i].tick_params(axis='y', labelcolor=color)
+ ax[i].set_ylim( [0,3.5] )
+
+ index = np.argsort(result_PWM_I[switch_pos[i]])
+ ax[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ result_uadc_in[switch_pos[i]][index],
+ label="UADC in",
+ color=color
+ )
+
+ ax[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ result_iadc_in[switch_pos[i]][index],
+ label="IADC in",
+ linestyle='--',
+ color=color,
+ )
+
+ ax[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ result_uswitch[switch_pos[i]][index],
+ color=color,
+ linestyle='dotted',
+ label="switch voltage"
+ )
+
+ for i in [0,1]:
+ ax[i].set_xlabel("current PWM setting / LSB")
+
+ ax2 = [
+ ax[0].twinx(),
+ ax[1].twinx()
+ ]
+
+ color = 'green'
+ for i in [0,1]:
+ ax2[i].set_ylabel("raw values / LSB", color=color)
+ ax2[i].spines['right'].set_position(('outward', 0))
+ ax2[i].tick_params(axis='y', labelcolor=color)
+ #ax2[i].set_yscale('log', base=2)
+ ax2[i].set_ylim( [0,5000] )
+
+ ax2[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ result_uadc[switch_pos[i]][index],
+ label="UADC",
+ color=color)
+
+ ax2[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ result_iadc[switch_pos[i]][index],
+ label="IADC",
+ linestyle='--',
+ color=color)
+
+ ax2[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ result_PWM_B[switch_pos[i]][index],
+ label="bias PWM",
+ linestyle='-',
+ color=color)
+
+ ax3 = [
+ ax[0].twinx(),
+ ax[1].twinx()
+ ]
+
+
+ color = 'orange'
+ for i in [0,1]:
+ ax3[i].set_ylabel("voltage before amplifier / V", color=color)
+ ax3[i].spines['right'].set_position(('outward', 55))
+ ax3[i].tick_params(axis='y', labelcolor=color)
+ ax3[i].set_ylim( [0,3.5] )
+
+
+ if i == 1:
+ ax3[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ getVoltageBeforeAmplifier(
+ LSB2U(result_uadc[switch_pos[i]][index]),
+ PWM2Voltage(result_PWM_B[switch_pos[i]][index])),
+ color=color,
+ linewidth=5,
+ label="voltage before amplifier")
+ else:
+ ax3[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ LSB2U(result_uadc[switch_pos[i]][index]),
+ color=color,
+ linewidth=5,
+ label="voltage before amplifier")
+
+ ###########################################################################
+
+ ax4 = [
+ ax[0].twinx(),
+ ax[1].twinx()
+ ]
+
+ color = 'red'
+ for i in [0,1]:
+ ax4[i].set_ylabel("current / mA", color=color)
+ ax4[i].spines['right'].set_position(('outward', 55+55))
+ ax4[i].tick_params(axis='y', labelcolor=color)
+
+ if i == 1:
+ ax4[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ U2I(getVoltageBeforeAmplifier(
+ LSB2U(result_uadc[switch_pos[i]][index]),
+ PWM2Voltage(result_PWM_B[switch_pos[i]][index]))),
+ color=color,
+ label="current before amplifier")
+ else:
+ ax4[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ U2I(LSB2U(result_uadc[switch_pos[i]][index])),
+ color=color,
+ label="current before amplifier")
+
+ ax5 = [
+ ax[0].twinx(),
+ ax[1].twinx()
+ ]
+
+ color = 'black'
+ for i in [0,1]:
+ ax5[i].set_ylabel("resistance / Ohm", color=color)
+ ax5[i].spines['right'].set_position(('outward', 55+55+40))
+ ax5[i].tick_params(axis='y', labelcolor=color)
+
+ if i == 1:
+ ax5[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+
+ getVoltageBeforeAmplifier(
+ LSB2U(result_uadc[switch_pos[i]][index]),
+ PWM2Voltage(result_PWM_B[switch_pos[i]][index]))
+ /
+ U2I(getVoltageBeforeAmplifier(
+ LSB2U(result_iadc[switch_pos[i]][index]),
+ PWM2Voltage(result_PWM_B[switch_pos[i]][index])))*1000
+ ,
+ color=color,
+ label="current before amplifier")
+ else:
+ ax5[i].plot(
+ result_PWM_I[switch_pos[i]][index],
+ LSB2U(result_uadc[switch_pos[i]][index])/
+ U2I(LSB2U(result_iadc[switch_pos[i]][index]))*1000,
+ color=color,
+ label="current before amplifier")
+
+ for i in[0,1]:
+ ax[i].legend()
+
+ fig.tight_layout()
+ plt.show()
+
+if __name__ == "__main__":
+ analyse_OFMfull('OFMfull_20230310_142123.npz')
\ No newline at end of file
diff --git a/simulations/OFMfull/current_source.asc b/simulations/OFMfull/current_source.asc
new file mode 100644
index 0000000..01eaaa4
--- /dev/null
+++ b/simulations/OFMfull/current_source.asc
@@ -0,0 +1,215 @@
+Version 4
+SHEET 1 1380 1144
+WIRE 272 -32 272 -48
+WIRE 272 80 272 48
+WIRE 576 80 576 64
+WIRE 48 96 48 48
+WIRE 16 112 -48 112
+WIRE 96 128 80 128
+WIRE 208 128 176 128
+WIRE 16 144 0 144
+WIRE 48 176 48 160
+WIRE 0 256 0 144
+WIRE 128 256 0 256
+WIRE 272 256 272 176
+WIRE 272 256 208 256
+WIRE 480 256 272 256
+WIRE 656 256 608 256
+WIRE 768 256 736 256
+WIRE 800 256 768 256
+WIRE 912 256 880 256
+WIRE 0 272 0 256
+WIRE 272 304 272 256
+WIRE 0 368 0 352
+WIRE 768 416 768 256
+WIRE 816 416 768 416
+WIRE 912 432 912 256
+WIRE 912 432 880 432
+WIRE 1104 432 912 432
+WIRE -512 448 -640 448
+WIRE -368 448 -512 448
+WIRE -48 448 -48 112
+WIRE -48 448 -288 448
+WIRE 48 448 -48 448
+WIRE 272 448 272 384
+WIRE 272 448 128 448
+WIRE 480 448 608 256
+WIRE 480 448 272 448
+WIRE 608 448 480 256
+WIRE 656 448 608 448
+WIRE 768 448 736 448
+WIRE 816 448 768 448
+WIRE 768 480 768 448
+WIRE 768 576 768 560
+WIRE 480 672 368 672
+WIRE 272 688 272 448
+WIRE 368 688 368 672
+WIRE 656 736 592 736
+WIRE 768 736 736 736
+WIRE 800 736 768 736
+WIRE 912 736 880 736
+WIRE 272 784 272 768
+WIRE 368 784 368 768
+WIRE 368 784 272 784
+WIRE 272 816 272 784
+WIRE 768 896 768 736
+WIRE 816 896 768 896
+WIRE 272 912 272 896
+WIRE 368 912 272 912
+WIRE 912 912 912 736
+WIRE 912 912 880 912
+WIRE 1104 912 912 912
+WIRE 272 928 272 912
+WIRE 368 928 368 912
+WIRE 608 928 480 672
+WIRE 656 928 608 928
+WIRE 768 928 736 928
+WIRE 816 928 768 928
+WIRE 480 944 592 736
+WIRE 768 960 768 928
+WIRE 368 1024 368 1008
+WIRE 480 1024 480 944
+WIRE 480 1024 368 1024
+WIRE 768 1056 768 1040
+WIRE 272 1104 272 1008
+FLAG 272 -48 +24V
+FLAG 0 368 0
+FLAG 272 1104 0
+FLAG 576 80 0
+FLAG 576 -16 +24V
+FLAG 48 48 +24V
+FLAG 48 176 0
+FLAG 848 400 +24V
+FLAG 848 464 0
+FLAG 768 576 0
+FLAG 1104 432 current_measure
+IOPIN 1104 432 Out
+FLAG 1104 912 voltage_measure
+IOPIN 1104 912 Out
+FLAG -512 448 current_setpoint
+FLAG 848 880 +24V
+FLAG 848 944 0
+FLAG 768 1056 0
+FLAG -640 448 current_setpoint
+IOPIN -640 448 In
+SYMBOL res 256 -48 R0
+SYMATTR InstName R1
+SYMATTR Value 47
+SYMBOL res 224 240 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R2
+SYMATTR Value 100k
+SYMBOL res 144 432 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R3
+SYMATTR Value 47k
+SYMBOL res -16 256 R0
+SYMATTR InstName R4
+SYMATTR Value 47k
+SYMBOL res 256 800 R0
+SYMATTR InstName PT100
+SYMATTR Value {R_PT100}
+SYMBOL res -272 432 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R6
+SYMATTR Value 1k
+SYMBOL res 256 288 R0
+SYMATTR InstName R7
+SYMATTR Value 220
+SYMBOL voltage 576 -32 R0
+WINDOW 123 0 0 Left 2
+WINDOW 39 0 0 Left 2
+SYMATTR InstName V1
+SYMATTR Value 24
+SYMBOL pnp 208 176 M180
+SYMATTR InstName Q2
+SYMATTR Value BC857C
+SYMBOL Opamps\\LT1490A 48 64 R0
+WINDOW 3 -138 14 Left 2
+SYMATTR InstName U1
+SYMBOL res 192 112 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R5
+SYMATTR Value 100
+SYMBOL Opamps\\LT1490A 848 368 R0
+SYMATTR InstName U2
+SYMBOL res 752 240 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R8
+SYMATTR Value 22k
+SYMBOL res 752 432 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R9
+SYMATTR Value 22k
+SYMBOL res 896 240 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R10
+SYMATTR Value 18k
+SYMBOL res 784 576 R180
+WINDOW 0 36 76 Left 2
+WINDOW 3 36 40 Left 2
+SYMATTR InstName R11
+SYMATTR Value 18k
+SYMBOL Opamps\\LT1490A 848 848 R0
+SYMATTR InstName U3
+SYMBOL res 752 720 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R12
+SYMATTR Value 10k
+SYMBOL res 752 912 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R13
+SYMATTR Value 10k
+SYMBOL res 896 720 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R14
+SYMATTR Value 10k
+SYMBOL res 784 1056 R180
+WINDOW 0 36 76 Left 2
+WINDOW 3 36 40 Left 2
+SYMATTR InstName R15
+SYMATTR Value 10k
+SYMBOL res 256 672 R0
+SYMATTR InstName R16
+SYMATTR Value 8
+SYMBOL res 352 672 R0
+SYMATTR InstName R17
+SYMATTR Value 8
+SYMBOL res 256 912 R0
+SYMATTR InstName R18
+SYMATTR Value 8
+SYMBOL res 352 912 R0
+SYMATTR InstName R19
+SYMATTR Value 8
+TEXT -768 712 Left 2 ;.dc V3 0 3.3 0.1\n.param R_PT100 100
+TEXT -552 216 Left 2 ;R2 and R4 define current per input voltage
+TEXT -856 400 Left 2 ;max. 3.3V
+TEXT -384 504 Left 2 ;"protection" resistor
+TEXT 936 216 Left 2 ;differential amplifier\nmeasure voltage across R7
+TEXT -80 832 Left 2 ;PT100 temperature sensor
+TEXT -760 880 Left 2 ;.tran 1\n.save V(voltage_measure) V(current_measure) I(Pt100)\n.step param R_PT100 100 150 10\n.measure Vmeas_avg avg V(voltage_measure)\n.measure Imeas_avg avg V(current_measure)\n.measure Ipt100_avg avg I(Pt100)
+TEXT -784 848 Left 3 ;Simulate current vs PT100
+TEXT -784 680 Left 3 ;Simulate current vs input voltage
+TEXT -1328 536 Left 2 !.param R_PT100 {100*(1+3.85e-3*TEMP)}\n*.param R_PT100 115.4
+LINE Normal 576 192 576 608 2
+LINE Normal 1376 192 576 192 2
+LINE Normal 576 608 1376 608 2
+LINE Normal 576 608 576 608 2
+LINE Normal -32 240 -32 240 2
+LINE Normal 240 208 -32 208 2
+LINE Normal 240 384 240 208 2
+LINE Normal 240 400 240 384 2
+LINE Normal -32 400 240 400 2
+LINE Normal -32 208 -32 400 2
+LINE Normal -32 208 -32 208 2
+RECTANGLE Normal -624 560 448 -144 2
diff --git a/simulations/OFMfull/current_source.asy b/simulations/OFMfull/current_source.asy
new file mode 100644
index 0000000..6ebf8a8
--- /dev/null
+++ b/simulations/OFMfull/current_source.asy
@@ -0,0 +1,13 @@
+Version 4
+SymbolType BLOCK
+RECTANGLE Normal -256 -40 272 40
+WINDOW 0 8 -40 Bottom 2
+PIN -256 0 LEFT 8
+PINATTR PinName current_setpoint
+PINATTR SpiceOrder 1
+PIN 272 -16 RIGHT 8
+PINATTR PinName current_measure
+PINATTR SpiceOrder 2
+PIN 272 16 RIGHT 8
+PINATTR PinName voltage_measure
+PINATTR SpiceOrder 3
diff --git a/simulations/OFMfull/pwm_filter_v1.asc b/simulations/OFMfull/pwm_filter_v1.asc
new file mode 100644
index 0000000..6bcf8cc
--- /dev/null
+++ b/simulations/OFMfull/pwm_filter_v1.asc
@@ -0,0 +1,56 @@
+Version 4
+SHEET 1 1648 680
+WIRE -384 -208 -384 -224
+WIRE 304 -160 128 -160
+WIRE -384 -112 -384 -128
+WIRE 192 -64 192 -80
+WIRE 128 -48 128 -160
+WIRE 160 -48 128 -48
+WIRE 304 -32 304 -160
+WIRE 304 -32 224 -32
+WIRE 368 -32 304 -32
+WIRE 416 -32 368 -32
+WIRE -208 -16 -336 -16
+WIRE -96 -16 -128 -16
+WIRE -32 -16 -96 -16
+WIRE 80 -16 48 -16
+WIRE 160 -16 80 -16
+WIRE -96 0 -96 -16
+WIRE 80 0 80 -16
+WIRE 192 16 192 0
+WIRE -96 80 -96 64
+WIRE 80 80 80 64
+FLAG 192 16 0
+FLAG -96 80 0
+FLAG 80 80 0
+FLAG -384 -112 0
+FLAG -384 -224 3V3
+FLAG 192 -80 3V3
+FLAG 368 -32 Uout
+FLAG 416 -32 Uout
+IOPIN 416 -32 Out
+FLAG -336 -16 PWMin
+IOPIN -336 -16 In
+SYMBOL res -112 -32 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R1
+SYMATTR Value 10k
+SYMBOL res 64 -32 R90
+WINDOW 0 0 56 VBottom 2
+WINDOW 3 32 56 VTop 2
+SYMATTR InstName R2
+SYMATTR Value 10k
+SYMBOL cap -112 0 R0
+SYMATTR InstName C1
+SYMATTR Value 100n
+SYMBOL cap 64 0 R0
+SYMATTR InstName C2
+SYMATTR Value 100n
+SYMBOL Opamps\\LT1490A 192 -96 R0
+SYMATTR InstName U1
+SYMBOL voltage -384 -224 R0
+WINDOW 123 0 0 Left 0
+WINDOW 39 0 0 Left 0
+SYMATTR InstName V2
+SYMATTR Value 3.3
diff --git a/simulations/OFMfull/pwm_filter_v1.asy b/simulations/OFMfull/pwm_filter_v1.asy
new file mode 100644
index 0000000..828c8b1
--- /dev/null
+++ b/simulations/OFMfull/pwm_filter_v1.asy
@@ -0,0 +1,10 @@
+Version 4
+SymbolType BLOCK
+RECTANGLE Normal -80 -24 96 24
+WINDOW 0 8 -24 Bottom 2
+PIN -80 0 LEFT 8
+PINATTR PinName PWMin
+PINATTR SpiceOrder 1
+PIN 96 0 RIGHT 8
+PINATTR PinName Uout
+PINATTR SpiceOrder 2
diff --git a/simulations/OFMfull/simADC.py b/simulations/OFMfull/simADC.py
new file mode 100644
index 0000000..dafb006
--- /dev/null
+++ b/simulations/OFMfull/simADC.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+"""
+
+"""
+
+import numpy as np
+
+def SimADC(Uin = 0, Uref = 3.3):
+ LSBs = Uin / Uref * 4096
+ return np.round(LSBs).astype(int)
\ No newline at end of file
diff --git a/simulations/OFMfull/simulate_OFM.py b/simulations/OFMfull/simulate_OFM.py
new file mode 100644
index 0000000..70af47e
--- /dev/null
+++ b/simulations/OFMfull/simulate_OFM.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+"""
+
+"""
+import os
+import sys
+
+import numpy as np
+import time
+
+from analyse_OFMfull import analyse_OFMfull
+from simADC import SimADC
+
+result_PWM_I = np.array([])
+result_PWM_B = np.array([])
+result_uadc_in = np.array([])
+result_iadc_in = np.array([])
+result_uswitch = np.array([])
+
+def processing_data(raw_filename, log_file, PWMI, PWMB):
+ sys.path.append("../PyLTSpice/")
+ from PyLTSpice import RawRead
+
+ print("Handling the simulation data of %s, log file %s" % (raw_filename, log_file))
+ LTR = RawRead(raw_filename)
+
+ # print simulation properties
+ #import pprint
+ #pprint.pprint(LTR.get_raw_property())
+
+ global result_PWM_I
+ global result_PWM_B
+ global result_uadc_in
+ global result_iadc_in
+ global result_uswitch
+
+ print("PWM I", PWMI)
+ print("PWM B", PWMB)
+
+ steps = LTR.get_steps()
+ for step in range(len(steps)):
+
+ print("Steps", steps[step])
+
+ uswitch = np.mean(LTR.get_trace("V(switch)").get_wave(step)[:-10])
+
+ uadc_in = np.mean(LTR.get_trace("V(uadc)").get_wave(step)[:-10])
+ iadc_in = np.mean(LTR.get_trace("V(iadc)").get_wave(step)[:-10])
+
+ uadc = SimADC(uadc_in)
+ iadc = SimADC(iadc_in)
+
+ print(uswitch)
+ print(uadc_in, iadc_in)
+ print(uadc, iadc)
+
+ result_PWM_I = np.append(result_PWM_I, PWMI)
+ result_PWM_B = np.append(result_PWM_B, PWMB)
+
+ result_uadc_in = np.append(result_uadc_in, uadc_in)
+ result_iadc_in = np.append(result_iadc_in, iadc_in)
+ result_uswitch = np.append(result_uswitch, uswitch)
+
+ ###########################################################################
+ # we no longer need the simulation output, so we can delete the files
+ # otherwise the discspace might become problematic
+ prefix = str(raw_filename).split('.raw')[0]
+ for ending in ['raw','net','op.raw','log']:
+ try:
+ os.remove(prefix + '.' + ending)
+ except Exception as e:
+ print(e)
+ pass
+
+###############################################################################
+if __name__ == "__main__":
+ sys.path.append("../PyLTSpice/")
+ from PyLTSpice import SimCommander
+ from functools import partial, update_wrapper # import partial for tweaking callback
+
+ # select spice model
+ LTC = SimCommander(
+ "./OFMfull.asc",
+ parallel_sims=2 # limit number of parallel simulations)
+ )
+
+
+ for pwm_set_i in [ 10, 100, 512, 1024, 1500, 2048, 4096 ]:
+ #for pwm_set_i in [ 10, 1024 ]:
+
+ LTC.set_parameter('temp', 40)
+
+
+ LTC.set_parameter('CCR_I', pwm_set_i)
+ LTC.set_parameter('CCR_B', pwm_set_i)
+
+ PWMI = LTC.get_parameter('CCR_I')
+ PWMB = LTC.get_parameter('CCR_B')
+
+ sim_callback = partial(processing_data, PWMI=float(PWMI), PWMB=float(PWMB))
+ update_wrapper(sim_callback, processing_data)
+ LTC.run(callback=sim_callback)
+
+ LTC.wait_completion()
+ # Sim Statistics
+ print('Successful/Total Simulations: ' + str(LTC.okSim) + '/' + str(LTC.runno))
+
+
+ # save results in numpy file format
+ npz_filename = "OFMfull_%s.npz"%(time.strftime("%Y%m%d_%H%M%S"))
+
+ np.savez(npz_filename,
+ result_PWM_I = result_PWM_I,
+ result_PWM_B = result_PWM_B,
+ result_uadc_in = result_uadc_in,
+ result_iadc_in = result_iadc_in,
+ result_uswitch = result_uswitch,
+ )
+
+ analyse_OFMfull(npz_filename)
+
diff --git a/simulations/PyLTSpice b/simulations/PyLTSpice
new file mode 160000
index 0000000..10d7999
--- /dev/null
+++ b/simulations/PyLTSpice
@@ -0,0 +1 @@
+Subproject commit 10d7999f861ac82f37c1cb8e3c0f70322896fab6