From 2cd5778d5b49a40206220b571a4d53009348967b Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Wed, 1 Jun 2022 19:20:10 +0200 Subject: Initial implementation of frequency response measurement --- lab_control/frequency_response.py | 25 ++++++++++ .../test/frequency_response_measurement_test.py | 40 ++++++++++++++++ lab_control/test/mock_lab.py | 54 ++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 lab_control/frequency_response.py create mode 100644 lab_control/test/frequency_response_measurement_test.py create mode 100644 lab_control/test/mock_lab.py (limited to 'lab_control') diff --git a/lab_control/frequency_response.py b/lab_control/frequency_response.py new file mode 100644 index 0000000..ca2002e --- /dev/null +++ b/lab_control/frequency_response.py @@ -0,0 +1,25 @@ +from lab_control.function_generator import FunctionGenerator +from lab_control.oscilloscope import Oscilloscope + +class FrequencyResponseMeasurement: + def __init__(self): + self.minFrequency = None + self.maxFrequency = None + self.steps = None + self.functionGeneratorChannel = None + self.oscilloscopeChannel = None + self.measurementDone = False + self.data = None + + def measure(self, osc: Oscilloscope, fg: FunctionGenerator) -> None: + frequencyRange = self.maxFrequency - self.minFrequency + self.data = [] + + for i in range(0, self.steps): + frequency = self.minFrequency + i * frequencyRange / (self.steps - 1) + fg.setFrequency(self.functionGeneratorChannel, frequency) + response = osc.measureAmplitude(self.oscilloscopeChannel) + self.data.append((frequency, response)) + + self.measurementDone = True + diff --git a/lab_control/test/frequency_response_measurement_test.py b/lab_control/test/frequency_response_measurement_test.py new file mode 100644 index 0000000..caea62a --- /dev/null +++ b/lab_control/test/frequency_response_measurement_test.py @@ -0,0 +1,40 @@ +import pytest + +from lab_control.test.mock_lab import MockLab +from lab_control.frequency_response import FrequencyResponseMeasurement + +@pytest.fixture +def mockLab(): + return MockLab() + +@pytest.fixture +def uut(mockLab): + return FrequencyResponseMeasurement() + +def test_frequencyResponseRamp(mockLab, uut): + uut.minFrequency = 100.0 + uut.maxFrequency = 200.0 + uut.steps = 11 + uut.functionGeneratorChannel = 1 + uut.oscilloscopeChannel = 1 + + # Expect a ramp response from 0 to 2 V + minAmplitude = 0.0 + maxAmplitude = 2.0 + + def amplitudeFunction(f: float) -> float: + assert f >= uut.minFrequency and f <= uut.maxFrequency + frequencyPu = (f - uut.minFrequency) / (uut.maxFrequency - uut.minFrequency) + return minAmplitude + maxAmplitude * frequencyPu + + mockLab.connectChannels(uut.functionGeneratorChannel, uut.oscilloscopeChannel) + mockLab.setAmplitudeFunction(uut.oscilloscopeChannel, amplitudeFunction) + expectedData = [(f, amplitudeFunction(f)) for f in [100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, 200.0]] + + assert not uut.measurementDone + assert uut.data == None + + response = uut.measure(mockLab, mockLab) + + assert uut.measurementDone + assert uut.data == expectedData diff --git a/lab_control/test/mock_lab.py b/lab_control/test/mock_lab.py new file mode 100644 index 0000000..718f319 --- /dev/null +++ b/lab_control/test/mock_lab.py @@ -0,0 +1,54 @@ +from collections.abc import Callable + +from lab_control.function_generator import FunctionGenerator +from lab_control.oscilloscope import Oscilloscope + +class MockLab(FunctionGenerator, Oscilloscope): + class FGChannelState: + def __init__(self): + self.on = False + self.frequency = None + self.amplitude = None + + class OscChannelState: + def __init__(self): + self.amplitudeFunction = None + self.fgChannel = None + + def __init__(self): + self.fgChannels = [MockLab.FGChannelState() for i in range(0, 2)] + self.oscChannels = [MockLab.OscChannelState() for i in range(0, 4)] + + def setOn(self, channel: int) -> None: + self.fgChannels[channel - 1].on = True + + def setOff(self, channel: int) -> None: + self.fgChannels[channel - 1].on = False + + def setFrequency(self, channel: int, frequency: float) -> None: + self.fgChannels[channel - 1].frequency = frequency + + def setAmplitude(self, channel: int, amplitude: float) -> None: + self.fgChannels[channel - 1].amplitude = amplitude + + def setFunction(self, channel: int, function: int) -> None: + pass + + def measureAmplitude(self, channel: int) -> float: + fgChannel = self.oscChannels[channel - 1].fgChannel + return self.oscChannels[channel - 1].amplitudeFunction(self.fgChannels[fgChannel].frequency) + + def measurePeakToPeak(self, channel: int) -> float: + pass + + def measureRMS(self, channel: int) -> float: + pass + + def measureFrequency(self, channel: int) -> float: + pass + + def setAmplitudeFunction(self, channel: int, f: Callable[[float], float]) -> None: + self.oscChannels[channel - 1].amplitudeFunction = f + + def connectChannels(self, fg: int, osc: int) -> None: + self.oscChannels[osc - 1].fgChannel = fg - 1 -- cgit v1.2.3