summaryrefslogtreecommitdiffstats
path: root/lab_control
diff options
context:
space:
mode:
authorEddy Pedroni <eddy@0xf7.com>2022-06-01 19:20:10 +0200
committerEddy Pedroni <eddy@0xf7.com>2022-06-01 19:20:10 +0200
commit2cd5778d5b49a40206220b571a4d53009348967b (patch)
tree02f83ff5261fdc6258542b85d12b2c846a49c0d4 /lab_control
parent6b709f4423d132742207b5cf01a64f0707a77927 (diff)
Initial implementation of frequency response measurement
Diffstat (limited to 'lab_control')
-rw-r--r--lab_control/frequency_response.py25
-rw-r--r--lab_control/test/frequency_response_measurement_test.py40
-rw-r--r--lab_control/test/mock_lab.py54
3 files changed, 119 insertions, 0 deletions
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