pqopen-lib 0.7.8__py3-none-any.whl → 0.7.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pqopen/powersystem.py CHANGED
@@ -88,7 +88,8 @@ class PowerSystem(object):
88
88
  "mains_signaling_tracer": {},
89
89
  "debug_channels": False,
90
90
  "energy_channels": {},
91
- "one_period_fundamental": False}
91
+ "one_period_fundamental": 0,
92
+ "rms_trapz_rule": False}
92
93
  self._prepare_calc_channels()
93
94
  self.output_channels: Dict[str, DataChannelBuffer] = {}
94
95
  self._last_processed_sidx = 0
@@ -100,6 +101,7 @@ class PowerSystem(object):
100
101
  self._last_zc_frac = 0.0
101
102
  self._calculation_mode = "NORMAL"
102
103
  self._last_known_freq = self.nominal_frequency
104
+ self._fund_freq_list = np.zeros(1)
103
105
  self._channel_update_needed = False
104
106
 
105
107
 
@@ -214,13 +216,20 @@ class PowerSystem(object):
214
216
  self._features["energy_channels"] = {"persist_file": persist_file, "energy_counters": energy_counters}
215
217
  self._channel_update_needed = True
216
218
 
217
- def enable_one_period_fundamental(self):
219
+ def enable_one_period_fundamental(self, freq_agg_cycles: int = 50):
218
220
  """
219
221
  Enables the calculation of one (single) period fundamental values
220
222
  """
221
- self._features["one_period_fundamental"] = True
223
+ self._features["one_period_fundamental"] = freq_agg_cycles
224
+ self._fund_freq_list = np.zeros(freq_agg_cycles)
222
225
  self._channel_update_needed = True
223
226
 
227
+ def enable_rms_trapz_rule(self):
228
+ """
229
+ Enables the trapezoidal integration rule for rms calculation
230
+ """
231
+ self._features["rms_trapz_rule"] = True
232
+
224
233
  def _resync_nper_abs_time(self, zc_idx: int):
225
234
  if not self._features["nper_abs_time_sync"]:
226
235
  return None
@@ -320,14 +329,12 @@ class PowerSystem(object):
320
329
  self._zero_crossings.append(actual_zc)
321
330
  if self._zero_cross_counter <= 1:
322
331
  continue
323
- # Calculate Frequency
324
- frequency = self._samplerate/(self._zero_crossings[-1] + actual_zc_frac - self._zero_crossings[-2] - self._last_zc_frac)
325
- self._last_zc_frac = actual_zc_frac
326
332
  # Add actual zero cross counter to debug channel if enabled
327
333
  if "pidx" in self._calc_channels["one_period"]['_debug']:
328
334
  self._calc_channels["one_period"]['_debug']['pidx'].put_data_single(self._zero_crossings[-1], self._zero_cross_counter)
329
335
  # Process one period calculation, start with second zc
330
- self._process_one_period(self._zero_crossings[-2], self._zero_crossings[-1], frequency)
336
+ self._process_one_period(self._zero_crossings[-2], self._zero_crossings[-1], actual_zc_frac)
337
+ self._last_zc_frac = actual_zc_frac
331
338
  if ((self._zero_cross_counter-1) % self.nper) == 0 and (self._zero_cross_counter > self.nper):
332
339
  # Process multi-period
333
340
  self._process_multi_period(self._zero_crossings[-self.nper - 1], self._zero_crossings[-1])
@@ -336,14 +343,17 @@ class PowerSystem(object):
336
343
 
337
344
  self._last_processed_sidx = stop_acq_sidx
338
345
 
339
- def _process_one_period(self, period_start_sidx: int, period_stop_sidx: int, frequency: float):
346
+ def _process_one_period(self, period_start_sidx: int, period_stop_sidx: int, actual_zc_frac: float= 0):
340
347
  """
341
348
  Processes data for a single period, calculating voltage, current, and power.
342
349
 
343
350
  Parameters:
344
351
  period_start_sidx: Start sample index of the period.
345
352
  period_stop_sidx: Stop sample index of the period.
353
+ frequency: Fundamental frequency
346
354
  """
355
+ # Calculate Frequency
356
+ frequency = self._samplerate/(period_stop_sidx + actual_zc_frac - period_start_sidx - self._last_zc_frac)
347
357
  self._calc_channels["one_period"]['power']['freq'].put_data_single(period_stop_sidx, frequency)
348
358
  if "sidx" in self._calc_channels["one_period"]['_debug']:
349
359
  self._calc_channels["one_period"]['_debug']['sidx'].put_data_single(period_stop_sidx, period_stop_sidx)
@@ -365,7 +375,21 @@ class PowerSystem(object):
365
375
  msv_edge, msv_value = phase._mains_signaling_tracer.process(u_values[::10])
366
376
  for phys_type, output_channel in phase._calc_channels["one_period"]["voltage"].items():
367
377
  if phys_type == "trms":
368
- u_rms = np.sqrt(np.mean(np.power(u_values, 2)))
378
+ if self._features["rms_trapz_rule"]:
379
+ add_start_idx_sample = 1 if self._last_zc_frac < 0 else 0
380
+ add_stop_idx_sample = 1 if actual_zc_frac > 0 else 0
381
+ u_trapz_values = phase._u_channel.read_data_by_index(phase_period_start_sidx-add_start_idx_sample, phase_period_stop_sidx+add_stop_idx_sample)
382
+ sample_points = np.arange(len(u_values), dtype=np.float64)
383
+ if add_start_idx_sample:
384
+ u_trapz_values[0] = (u_trapz_values[1] - u_trapz_values[0])*(1+self._last_zc_frac) + u_trapz_values[0]
385
+ sample_points = np.insert(sample_points,0,self._last_zc_frac)
386
+ if add_stop_idx_sample:
387
+ u_trapz_values[-1] = (u_trapz_values[-1] - u_trapz_values[-2])*self._last_zc_frac + u_trapz_values[-2]
388
+ sample_points = np.insert(sample_points,len(sample_points),sample_points[-1]+actual_zc_frac)
389
+ integral = np.trapezoid(np.power(u_trapz_values,2), sample_points)
390
+ u_rms = np.sqrt(integral * frequency / self._samplerate)
391
+ else:
392
+ u_rms = np.sqrt(np.mean(np.power(u_values, 2)))
369
393
  output_channel.put_data_single(phase_period_stop_sidx, u_rms)
370
394
  if phys_type == "msv_bit":
371
395
  if msv_edge is not None:
@@ -376,7 +400,10 @@ class PowerSystem(object):
376
400
  output_channel.put_data_single(phase_period_stop_sidx, np.abs(np.diff(u_values)).max())
377
401
  if phys_type == "fund_rms":
378
402
  # Use sample-discrete frequency, not the exact one for full cycle
379
- fund_amp, fund_phase = calc_single_freq(u_values, self._samplerate/len(u_values), self._samplerate)
403
+ self._fund_freq_list = np.roll(self._fund_freq_list,-1)
404
+ self._fund_freq_list[-1] = self._samplerate/len(u_values)
405
+ mean_freq = self._fund_freq_list[self._fund_freq_list>0].mean()
406
+ fund_amp, fund_phase = calc_single_freq(u_values, mean_freq, self._samplerate)
380
407
  output_channel.put_data_single(phase_period_stop_sidx, fund_amp)
381
408
  for phys_type, output_channel in phase._calc_channels["half_period"]["voltage"].items():
382
409
  if phys_type == "trms":
@@ -677,7 +704,7 @@ class PowerPhase(object):
677
704
  self._calc_channels["one_period"]["voltage"]["msv_mag"] = DataChannelBuffer('U{:s}_1p_msv'.format(self.name), agg_type='max', unit="V")
678
705
  self._calc_channels["one_period"]["voltage"]["msv_bit"] = DataChannelBuffer('U{:s}_msv_bit'.format(self.name), unit="")
679
706
 
680
- if "one_period_fundamental" in features and features["one_period_fundamental"]:
707
+ if "one_period_fundamental" in features and features["one_period_fundamental"] > 0:
681
708
  self._calc_channels["one_period"]["voltage"]["fund_rms"] = DataChannelBuffer('U{:s}_1p_H1_rms'.format(self.name), agg_type='rms', unit="V")
682
709
 
683
710
  # Create Current Channels
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pqopen-lib
3
- Version: 0.7.8
3
+ Version: 0.7.9
4
4
  Summary: A power quality processing library for calculating parameters from waveform data
5
5
  Project-URL: Homepage, https://github.com/DaqOpen/pqopen-lib
6
6
  Project-URL: Issues, https://github.com/DaqOpen/pqopen-lib/issues
@@ -3,10 +3,10 @@ pqopen/eventdetector.py,sha256=NKZU7GbeorZdkYu3ET4lhMaeynw70GhIGO2p1xH4aTA,11962
3
3
  pqopen/goertzel.py,sha256=JhehuEj-xNnwQEh4Ti8dXiGvfDmxbdEoaxIsFswZNcM,2008
4
4
  pqopen/helper.py,sha256=bM_wDck5OfeEy96U_2FjCwZuLZRPYyKVeiYD3-vzP6M,1761
5
5
  pqopen/powerquality.py,sha256=Qwyaj7BQqQPRivei140mv-Leh6u9uIQzViKLOY7bHyw,17877
6
- pqopen/powersystem.py,sha256=t_IXWTOKbdDa-JnWsibbT-H7Wb4vbv1W-n5QvBgZRhU,41752
6
+ pqopen/powersystem.py,sha256=JC7GI_1F7T3RlFHtnbw3UxGGVKV5Q7TlpiR0vzPbWYk,43610
7
7
  pqopen/storagecontroller.py,sha256=AhVaPgIh4CBKKMJm9Ja0dOjVd4dLppWprxeeg3vrmAk,31266
8
8
  pqopen/zcd.py,sha256=ueq-a59gOFFeIUzI61vO4G5sSuBDAm30Y_FfGgwDPV0,5704
9
- pqopen_lib-0.7.8.dist-info/METADATA,sha256=9xZCEZLIn2OHXRpwyaRwwE5w33xIkhbXVMQ00-Nu-3c,4780
10
- pqopen_lib-0.7.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
- pqopen_lib-0.7.8.dist-info/licenses/LICENSE,sha256=yhYwu9dioytbAvNQa0UBwaBVcALqiOoBViEs4HLW6aU,1064
12
- pqopen_lib-0.7.8.dist-info/RECORD,,
9
+ pqopen_lib-0.7.9.dist-info/METADATA,sha256=IUKnOMFcjwyDCOEe5hBS7ZtrLs19me75EjLWCZZkwp4,4780
10
+ pqopen_lib-0.7.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ pqopen_lib-0.7.9.dist-info/licenses/LICENSE,sha256=yhYwu9dioytbAvNQa0UBwaBVcALqiOoBViEs4HLW6aU,1064
12
+ pqopen_lib-0.7.9.dist-info/RECORD,,