118 lines
4.8 KiB
Python
118 lines
4.8 KiB
Python
"""PWM reconstruction vectors and sigrok wait/annotation boundary tests."""
|
|
import importlib.util
|
|
import math
|
|
from pathlib import Path
|
|
import sys
|
|
import types
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
ROOT = Path(__file__).resolve().parents[3]
|
|
spec = importlib.util.spec_from_file_location('pwm_core', ROOT / 'python/logic_analyzer/decoders/pwm_waveform.py')
|
|
core = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(core)
|
|
|
|
|
|
class PwmTests(unittest.TestCase):
|
|
def test_sine_three_phases_and_polarity(self):
|
|
for phase in (0, 2 * math.pi / 3, 4 * math.pi / 3):
|
|
for active in (True, False):
|
|
state = core.PwmChannel(1000000, active)
|
|
result = []
|
|
state.update(0, active) # Initial partial cycle must be ignored.
|
|
state.update(100, not active)
|
|
expected = []
|
|
for i in range(101):
|
|
width = round(500 + 400 * math.sin(2 * math.pi * i / 100 + phase))
|
|
result.extend(state.update(1000 + i * 1000, active))
|
|
result.extend(state.update(1000 + i * 1000 + width, not active))
|
|
expected.append(2 * width / 1000 - 1)
|
|
self.assertEqual(len(result), 100)
|
|
for e, value in zip(result, expected):
|
|
self.assertAlmostEqual(e['value'], value)
|
|
self.assertEqual(e['frequency'], 1000)
|
|
|
|
def test_fixed_windows_include_zero_and_full_duty(self):
|
|
state = core.PwmChannel(1000, carrier_hz=100)
|
|
state.update(0, 0)
|
|
events = state.update(30, 1) + state.update(60, 0)
|
|
self.assertEqual([e['value'] for e in events], [-1]*3 + [1]*3)
|
|
self.assertEqual(state.next_boundary(), 70)
|
|
|
|
def test_fractional_windows_do_not_accumulate_rounding_error(self):
|
|
state = core.PwmChannel(1000, carrier_hz=60)
|
|
state.update(0, 1)
|
|
events = state.update(100000, 1)
|
|
self.assertEqual(len(events), 6000)
|
|
self.assertEqual(events[-1]['end'], 100000)
|
|
self.assertTrue(all(e['duty'] == 1 for e in events))
|
|
|
|
def test_smoothing_step_response(self):
|
|
state = core.PwmChannel(1000, carrier_hz=100, smoothing_ms=10)
|
|
state.update(0, 0)
|
|
state.update(10, 1)
|
|
value = state.update(20, 1)[0]['value']
|
|
self.assertAlmostEqual(value, 1 - 2 * math.exp(-1))
|
|
|
|
def test_partial_capture_has_no_invented_cycle(self):
|
|
state = core.PwmChannel(1000)
|
|
self.assertEqual(state.update(0, 1) + state.update(5, 0)
|
|
+ state.update(10, 1) + state.update(12, 0), [])
|
|
|
|
def test_invalid_settings(self):
|
|
for args in ((0,), (1000, True, -1), (1000, True, 501),
|
|
(1000, True, 0, -1), (float('nan'),)):
|
|
with self.assertRaises(ValueError):
|
|
core.PwmChannel(*args)
|
|
|
|
def test_adapter_optional_channels_and_skip(self):
|
|
class StopCapture(Exception):
|
|
pass
|
|
|
|
class FakeDecoder:
|
|
def register(self, kind):
|
|
return kind
|
|
|
|
def has_channel(self, ch):
|
|
return ch in (0, 2)
|
|
|
|
def put(self, ss, es, output, data):
|
|
self.emitted.append((ss, es, data))
|
|
|
|
def wait(self, conditions):
|
|
if conditions == {}:
|
|
self.samplenum = 0
|
|
else:
|
|
self.test.assertEqual(conditions, [{0: 'e'}, {2: 'e'}, {'skip': 10}])
|
|
self.samplenum += 10
|
|
if self.samplenum > 30:
|
|
self.samplenum = 30
|
|
raise StopCapture()
|
|
return (0, 255, 1)
|
|
|
|
stub = types.ModuleType('sigrokdecode')
|
|
stub.Decoder, stub.OUTPUT_ANN, stub.SRD_CONF_SAMPLERATE = FakeDecoder, 0, 1
|
|
with patch.dict(sys.modules, {'sigrokdecode': stub, 'common.setgui_decoders.pwm_waveform': core}):
|
|
spec = importlib.util.spec_from_file_location('pwm_adapter', ROOT / 'tools/dsview/decoders/pwm_waveform/pd.py')
|
|
adapter = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(adapter)
|
|
decoder = adapter.Decoder()
|
|
decoder.test = self
|
|
decoder.options = {o['id']: o['default'] for o in decoder.options}
|
|
decoder.options['carrier_hz'] = 100
|
|
decoder.emitted = []
|
|
decoder.metadata(1, 1000)
|
|
decoder.start()
|
|
with self.assertRaises(StopCapture):
|
|
decoder.decode()
|
|
decoder.end()
|
|
self.assertEqual(len(decoder.emitted), 10)
|
|
self.assertEqual({e[2][0] for e in decoder.emitted}, {0, 2, 3, 5})
|
|
curves = [e for e in decoder.emitted if e[2][0] < 3]
|
|
self.assertEqual(curves[0][:2], (5, 15))
|
|
self.assertEqual(curves[0][2][1][-1], 'PWM1 -1.000000000 -1.000000000')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|