Snapshot of ScaledParameter doesn't update when wrapped parameter is set
Steps to reproduce
- Create ScaledParameter
- Change value of wrapped parameter
- Take snapshot of ScaledParameter. => It contains the old value
Expected behaviour
It is expected that also the snapshot of the ScaledParameter reflects the latest value of the wrapped behavior.
Actual behaviour
Snapshot of ScaledParameter is not updated.
System
Windows qcodes release 0.21
Example to reproduce:
import qcodes as qc
from qcodes.tests.instrument_mocks import DummyInstrument
from pprint import pprint
iv_converter = DummyInstrument('iv_converter', gates=('adc1',))
current1 = qc.ScaledParameter(output=iv_converter.adc1, gain=1/1e6, name='current1', unit='A')
# This works fine
current1(4e-6)
pprint(current1.snapshot()) # this snapshot is correct
# Set adc1 to 3
iv_converter.adc1(3)
pprint(current1.snapshot()) # this snapshot "value" is not correct (old value)
@sldesnoo-Delft Thanks for your report. In all honesty I think the ScaledParameter should probably be deprecated and its use replaced by the DelegateParameter. Can you check it DelegateParameter solves your needs?
DelegateParameter does not provide any scaling. I've made a derived class to add fixed scaling, but that does not yet provide the option use a parameter as gain. I'm not sure whether all snapshot options are properly taken into account with this class. It would be nice to have a proper ScaledParameter in qcodes.
class ScaledParameter(qc.DelegateParameter):
def __init__(self, name, source, gain, *args, **kwargs):
super().__init__(name, source, *args, **kwargs)
self._gain = gain
def get_raw(self):
return self.source.get() * self._gain
def set_raw(self, value):
self.source(value / self._gain)
def snapshot_base(self, update = True, params_to_skip_update = None):
snapshot = super().snapshot_base(
update=update,
params_to_skip_update=params_to_skip_update
)
snapshot.update({'gain': self._gain})
if 'value' in snapshot and snapshot['value'] is not None:
snapshot.update(
{
'value': snapshot['value'] * self._gain,
'raw_value': snapshot['raw_value'] * self._gain,
}
)
return snapshot
Sorry I should have been more clear. All QCoDeS parameters have a scale and and an offset. So you can do something like:
from qcodes.instrument.parameter import DelegateParameter, Parameter
a = Parameter(name='a', unit='V', set_cmd=None, get_cmd=None, initial_value=1)
b = DelegateParameter(name="b", unit="KV", source=a, scale=1e3)
a.get()
1
b.get()
0.001
b.snapshot(update=False)
{'__class__': 'qcodes.instrument.parameter.DelegateParameter',
'full_name': 'b',
'value': 0.001,
'raw_value': 1,
'ts': '2021-01-20 12:39:18',
'inter_delay': 0,
'name': 'b',
'scale': 1000.0,
'post_delay': 0,
'label': 'a',
'unit': 'KV',
'source_parameter': {'__class__': 'qcodes.instrument.parameter.Parameter',
'full_name': 'a',
'value': 1,
'raw_value': 1,
'ts': '2021-01-20 12:39:18',
'inter_delay': 0,
'name': 'a',
'post_delay': 0,
'label': 'a',
'unit': 'V'}}
a.set(2)
b.snapshot(update=False)
{'__class__': 'qcodes.instrument.parameter.DelegateParameter',
'full_name': 'b',
'value': 0.002,
'raw_value': 2,
'ts': '2021-01-20 12:39:48',
'inter_delay': 0,
'name': 'b',
'scale': 1000.0,
'post_delay': 0,
'label': 'a',
'unit': 'KV',
'source_parameter': {'__class__': 'qcodes.instrument.parameter.Parameter',
'full_name': 'a',
'value': 2,
'raw_value': 2,
'ts': '2021-01-20 12:39:48',
'inter_delay': 0,
'name': 'a',
'post_delay': 0,
'label': 'a',
'unit': 'V'}}
The scale argument is new to me. Currently this satisfies our needs.
In the future we might want to use a parameter for scale. When an amplifier is controlled as a qcodes instrument, then it would be nice to use the gain parameter of the amplifier as scale of the DelegateParameter.
Thanks agree that it is handy to be able to bind another parameter to the scale. I will think about how to best handle that