Skip to content

Commit 72c993d

Browse files
committed
Merge remote-tracking branch 'irnas/master'
2 parents ee93724 + dbb4648 commit 72c993d

File tree

2 files changed

+59
-14
lines changed

2 files changed

+59
-14
lines changed

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,23 @@ Unlike the original Power Profiler Kit, the PPK2 uses Serial to communicate with
1515
## Usage
1616
At this point in time the library provides the basic API with a basic example showing how to read data and toggle DUT power.
1717

18-
To enable power monitoring in Ampere mode implement the following sequence:
18+
To enable power monitoring in Source mode implement the following sequence:
1919
```
2020
ppk2_test = PPK2_API("/dev/ttyACM3") # serial port will be different for you
2121
ppk2_test.get_modifiers()
22-
ppk2_test.use_ampere_meter() # set ampere meter mode
22+
ppk2_test.use_source_meter() # set source meter mode
23+
ppk2_test.set_source_voltage(3300) # set source voltage in mV
2324
ppk2_test.start_measuring() # start measuring
2425
2526
# read measured values in a for loop like this:
2627
for i in range(0, 1000):
2728
read_data = ppk2_test.get_data()
2829
if read_data != b'':
29-
ppk2_test.average_of_sampling_period(read_data)
30-
time.sleep(0.01)
30+
samples = ppk2_test.get_samples(read_data)
31+
print(f"Average of {len(samples)} samples is: {sum(samples)/len(samples)}uA")
32+
time.sleep(0.001) # lower time between sampling -> less samples read in one sampling period
33+
34+
ppk2_test.stop_measuring()
3135
```
3236

3337

src/ppk2_api/ppk2_api.py

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import serial
88
import time
99
import struct
10-
import logging
1110

1211

1312
class PPK2_Command():
@@ -76,6 +75,16 @@ def __init__(self, port):
7675

7776
self.mode = None
7877

78+
self.rolling_avg = None
79+
self.rolling_avg4 = None
80+
self.prev_range = None
81+
self.consecutive_range_samples = 0
82+
83+
self.spike_filter_alpha = 0.18
84+
self.spike_filter_alpha5 = 0.06
85+
self.spike_filter_samples = 3
86+
self.after_spike = 0
87+
7988
# adc measurement buffer remainder and len of remainder
8089
self.remainder = {"sequence": b'', "len": 0}
8190

@@ -162,7 +171,6 @@ def _parse_metadata(self, metadata):
162171
else:
163172
self.modifiers[key][str(ind)] = float(
164173
data_pair[1])
165-
166174
return True
167175
except Exception as e:
168176
# if exception triggers serial port is probably not correct
@@ -176,20 +184,22 @@ def _generate_mask(self, bits, pos):
176184

177185
def _get_masked_value(self, value, meas):
178186
masked_value = (value & meas["mask"]) >> meas["pos"]
187+
if meas["pos"] == 24:
188+
if masked_value == 255:
189+
masked_value = -1
179190
return masked_value
180191

181192
def _handle_raw_data(self, adc_value):
182193
"""Convert raw value to analog value"""
183194
try:
184195
current_measurement_range = min(self._get_masked_value(
185-
adc_value, self.MEAS_RANGE), 5) # 5 is the number of parameters
196+
adc_value, self.MEAS_RANGE), 4) # 5 is the number of parameters
186197
adc_result = self._get_masked_value(adc_value, self.MEAS_ADC) * 4
187-
# print(f"adc result {adc_result}") # 564
188198
bits = self._get_masked_value(adc_value, self.MEAS_LOGIC)
189199
analog_value = self.get_adc_result(
190200
current_measurement_range, adc_result) * 10**6
191201
return analog_value
192-
except:
202+
except Exception as e:
193203
print("Measurement outside of range!")
194204
return None
195205

@@ -221,7 +231,7 @@ def stop_measuring(self):
221231
self._write_serial((PPK2_Command.AVERAGE_STOP, ))
222232

223233
def set_source_voltage(self, mV):
224-
"""Inits device - based on observation only REGULATOR_SET is the command.
234+
"""Inits device - based on observation only REGULATOR_SET is the command.
225235
The other two values correspond to the voltage level.
226236
227237
800mV is the lowest setting - [3,32] - the values then increase linearly
@@ -260,13 +270,44 @@ def get_adc_result(self, current_range, adc_value):
260270
current_range = str(current_range)
261271
result_without_gain = (adc_value - self.modifiers["O"][current_range]) * (
262272
self.adc_mult / self.modifiers["R"][current_range])
263-
264273
adc = self.modifiers["UG"][current_range] * (result_without_gain * (self.modifiers["GS"][current_range] * result_without_gain + self.modifiers["GI"][current_range]) + (
265274
self.modifiers["S"][current_range] * (self.current_vdd / 1000) + self.modifiers["I"][current_range]))
266275

267-
self.rolling_avg = adc
268-
self.rolling_avg4 = adc
269-
276+
prev_rolling_avg = self.rolling_avg
277+
prev_rolling_avg4 = self.rolling_avg4
278+
279+
# spike filtering / rolling average
280+
if self.rolling_avg is None:
281+
self.rolling_avg = adc
282+
else:
283+
self.rolling_avg = self.spike_filter_alpha * adc + (1 - self.spike_filter_alpha) * self.rolling_avg
284+
285+
if self.rolling_avg4 is None:
286+
self.rolling_avg4 = adc
287+
else:
288+
self.rolling_avg4 = self.spike_filter_alpha5 * adc + (1 - self.spike_filter_alpha5) * self.rolling_avg4
289+
290+
if self.prev_range is None:
291+
self.prev_range = current_range
292+
293+
if self.prev_range != current_range or self.after_spike > 0:
294+
if self.prev_range != current_range:
295+
self.consecutive_range_samples = 0
296+
self.after_spike = self.spike_filter_samples
297+
else:
298+
self.consecutive_range_samples += 1
299+
300+
if current_range == "4":
301+
if self.consecutive_range_samples < 2:
302+
self.rolling_avg = prev_rolling_avg
303+
self.rolling_avg4 = prev_rolling_avg4
304+
adc = self.rolling_avg4
305+
else:
306+
adc = self.rolling_avg
307+
308+
self.after_spike -= 1
309+
310+
self.prev_range = current_range
270311
return adc
271312

272313
def _digital_to_analog(self, adc_value):

0 commit comments

Comments
 (0)