improvements when testing leiden

- triple current source
- software loop
This commit is contained in:
2025-10-30 12:24:34 +01:00
parent b45635e4f8
commit 71629c1d3a
6 changed files with 535 additions and 65 deletions

View File

@@ -0,0 +1,20 @@
Node('ah2700.frappy.psi.ch',
'Andeen Hagerlin 2700 Capacitance Bridge',
)
Mod('cap_io',
'frappy_psi.ah2700.Ah2700IO',
'',
uri='linse-leiden-ts:3002',
timeout=60,
)
# this creates also cap_freq and cap_loss
Mod('cap',
'frappy_psi.ah2700.Capacitance',
'capacitance',
io = 'cap_io',
loss_name='loss',
freq_name='freq',
)

110
cfg/main/leiden370_cfg.py Normal file
View File

@@ -0,0 +1,110 @@
Node('leiden370.config.sea.psi.ch',
'''30 K - Leidendil Pulsetube with ls370''',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for leiden370.config',
config = 'leiden370.config',
service = 'main',
)
for name in ['T3K', 'Tstill', 'T50mK', 'Tmxlow', 'Tmxhigh', 'Tmxcx', 'Tblueo',
'Tpt50', 'Tpt3high', 'Tpt3low', 'Twhite', 'Tgreen']:
mname = name.replace('T','T_')
Mod(mname,
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tt',
rel_paths=[name],
value=Param(unit='K'),
extra_modules = ['raw'],
)
Mod(name.replace('T', 'R_'),
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
value=Param(unit='Ohm'),
single_module=f'{mname}.raw'
)
Mod('cmn',
'frappy_psi.sea.SeaReadable', '',
io = 'sea_main',
sea_object = 'cmn',
extra_modules = ['u1', 'u2', 'temp'],
)
Mod('T_cmn',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
value=Param(unit='K'),
single_module='cmn.temp',
)
Mod('V_fixp',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
value=Param(unit='V'),
single_module='cmn.u2',
)
Mod('V_cmn',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
value=Param(unit='V'),
single_module='cmn.u1',
)
Mod('tcs_io',
'frappy_psi.tcs.IO',
'tcs communication',
uri='linse-leiden-ts:3005',
)
Mod('still_htr',
'frappy_psi.tcs.Heater',
'still heater',
io='tcs_io',
channel=2,
)
Mod('mix_htr',
'frappy_psi.tcs.WrappedHeater',
'mixing chamber heater',
io='tcs_io',
channel=3,
)
Mod('drive_mix',
'frappy_psi.picontrol.PIctrl',
'controlled temperature ',
input_module = 'T_mxlow',
output_module = 'mix_htr',
output_min = 0,
output_max = 0.02,
p = 5,
itime = 60,
)
Mod('drive_cmn',
'frappy_psi.picontrol.PIctrl',
'controlled temperature ',
input_module = 'T_cmn',
output_module = 'mix_htr',
output_min = 0,
output_max = 1e-3,
p = 5,
itime = 120,
)
Mod('drive_fixp',
'frappy_psi.picontrol.PI',
'controlled temperature ',
value=Param(unit='V'),
input_module = 'V_fixp',
output_module = 'drive_mix',
output_min = 0.0,
output_max = 0.01,
p = 1,
itime = 120,
)

View File

@@ -0,0 +1,213 @@
{"tt": {"base": "/tt", "params": [
{"path": "", "type": "int", "kids": 18},
{"path": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "autoscan", "type": "bool", "readonly": false, "cmd": "tt autoscan", "kids": 4},
{"path": "autoscan/synchronized", "type": "bool", "readonly": false, "cmd": "tt autoscan/synchronized"},
{"path": "autoscan/interval", "type": "text", "readonly": false, "cmd": "tt autoscan/interval"},
{"path": "autoscan/pause", "type": "text", "readonly": false, "cmd": "tt autoscan/pause"},
{"path": "autoscan/dwell", "type": "text", "readonly": false, "cmd": "tt autoscan/dwell"},
{"path": "T3K", "type": "float", "kids": 14},
{"path": "T3K/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt T3K/active"},
{"path": "T3K/autorange", "type": "bool", "readonly": false, "cmd": "tt T3K/autorange", "description": "autorange (common for all channels)"},
{"path": "T3K/range", "type": "text", "readonly": false, "cmd": "tt T3K/range", "description": "resistance range in Ohm"},
{"path": "T3K/range_num", "type": "int"},
{"path": "T3K/excitation", "type": "text", "readonly": false, "cmd": "tt T3K/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "T3K/excitation_num", "type": "int"},
{"path": "T3K/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "T3K/pause", "type": "int", "readonly": false, "cmd": "tt T3K/pause", "description": "pause time [sec] after channel change"},
{"path": "T3K/filter", "type": "int", "readonly": false, "cmd": "tt T3K/filter", "description": "filter average time [sec]"},
{"path": "T3K/dwell", "type": "int", "readonly": false, "cmd": "tt T3K/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "T3K/status", "type": "text"},
{"path": "T3K/curve", "type": "text", "readonly": false, "cmd": "tt T3K/curve", "kids": 1},
{"path": "T3K/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt T3K/curve/points", "visibility": 3},
{"path": "T3K/alarm", "type": "float", "readonly": false, "cmd": "tt T3K/alarm"},
{"path": "T3K/raw", "type": "float"},
{"path": "Tstill", "type": "float", "kids": 14},
{"path": "Tstill/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tstill/active"},
{"path": "Tstill/autorange", "type": "bool", "readonly": false, "cmd": "tt Tstill/autorange", "description": "autorange (common for all channels)"},
{"path": "Tstill/range", "type": "text", "readonly": false, "cmd": "tt Tstill/range", "description": "resistance range in Ohm"},
{"path": "Tstill/range_num", "type": "int"},
{"path": "Tstill/excitation", "type": "text", "readonly": false, "cmd": "tt Tstill/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tstill/excitation_num", "type": "int"},
{"path": "Tstill/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tstill/pause", "type": "int", "readonly": false, "cmd": "tt Tstill/pause", "description": "pause time [sec] after channel change"},
{"path": "Tstill/filter", "type": "int", "readonly": false, "cmd": "tt Tstill/filter", "description": "filter average time [sec]"},
{"path": "Tstill/dwell", "type": "int", "readonly": false, "cmd": "tt Tstill/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tstill/status", "type": "text"},
{"path": "Tstill/curve", "type": "text", "readonly": false, "cmd": "tt Tstill/curve", "kids": 1},
{"path": "Tstill/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tstill/curve/points", "visibility": 3},
{"path": "Tstill/alarm", "type": "float", "readonly": false, "cmd": "tt Tstill/alarm"},
{"path": "Tstill/raw", "type": "float"},
{"path": "T50mK", "type": "float", "kids": 14},
{"path": "T50mK/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt T50mK/active"},
{"path": "T50mK/autorange", "type": "bool", "readonly": false, "cmd": "tt T50mK/autorange", "description": "autorange (common for all channels)"},
{"path": "T50mK/range", "type": "text", "readonly": false, "cmd": "tt T50mK/range", "description": "resistance range in Ohm"},
{"path": "T50mK/range_num", "type": "int"},
{"path": "T50mK/excitation", "type": "text", "readonly": false, "cmd": "tt T50mK/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "T50mK/excitation_num", "type": "int"},
{"path": "T50mK/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "T50mK/pause", "type": "int", "readonly": false, "cmd": "tt T50mK/pause", "description": "pause time [sec] after channel change"},
{"path": "T50mK/filter", "type": "int", "readonly": false, "cmd": "tt T50mK/filter", "description": "filter average time [sec]"},
{"path": "T50mK/dwell", "type": "int", "readonly": false, "cmd": "tt T50mK/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "T50mK/status", "type": "text"},
{"path": "T50mK/curve", "type": "text", "readonly": false, "cmd": "tt T50mK/curve", "kids": 1},
{"path": "T50mK/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt T50mK/curve/points", "visibility": 3},
{"path": "T50mK/alarm", "type": "float", "readonly": false, "cmd": "tt T50mK/alarm"},
{"path": "T50mK/raw", "type": "float"},
{"path": "Tmxlow", "type": "float", "kids": 14},
{"path": "Tmxlow/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxlow/active"},
{"path": "Tmxlow/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxlow/autorange", "description": "autorange (common for all channels)"},
{"path": "Tmxlow/range", "type": "text", "readonly": false, "cmd": "tt Tmxlow/range", "description": "resistance range in Ohm"},
{"path": "Tmxlow/range_num", "type": "int"},
{"path": "Tmxlow/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxlow/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tmxlow/excitation_num", "type": "int"},
{"path": "Tmxlow/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tmxlow/pause", "type": "int", "readonly": false, "cmd": "tt Tmxlow/pause", "description": "pause time [sec] after channel change"},
{"path": "Tmxlow/filter", "type": "int", "readonly": false, "cmd": "tt Tmxlow/filter", "description": "filter average time [sec]"},
{"path": "Tmxlow/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxlow/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tmxlow/status", "type": "text"},
{"path": "Tmxlow/curve", "type": "text", "readonly": false, "cmd": "tt Tmxlow/curve", "kids": 1},
{"path": "Tmxlow/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxlow/curve/points", "visibility": 3},
{"path": "Tmxlow/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxlow/alarm"},
{"path": "Tmxlow/raw", "type": "float"},
{"path": "Tmxhigh", "type": "float", "kids": 14},
{"path": "Tmxhigh/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxhigh/active"},
{"path": "Tmxhigh/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxhigh/autorange", "description": "autorange (common for all channels)"},
{"path": "Tmxhigh/range", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/range", "description": "resistance range in Ohm"},
{"path": "Tmxhigh/range_num", "type": "int"},
{"path": "Tmxhigh/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tmxhigh/excitation_num", "type": "int"},
{"path": "Tmxhigh/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tmxhigh/pause", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/pause", "description": "pause time [sec] after channel change"},
{"path": "Tmxhigh/filter", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/filter", "description": "filter average time [sec]"},
{"path": "Tmxhigh/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tmxhigh/status", "type": "text"},
{"path": "Tmxhigh/curve", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/curve", "kids": 1},
{"path": "Tmxhigh/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxhigh/curve/points", "visibility": 3},
{"path": "Tmxhigh/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxhigh/alarm"},
{"path": "Tmxhigh/raw", "type": "float"},
{"path": "Tmxcx", "type": "float", "kids": 14},
{"path": "Tmxcx/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxcx/active"},
{"path": "Tmxcx/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxcx/autorange", "description": "autorange (common for all channels)"},
{"path": "Tmxcx/range", "type": "text", "readonly": false, "cmd": "tt Tmxcx/range", "description": "resistance range in Ohm"},
{"path": "Tmxcx/range_num", "type": "int"},
{"path": "Tmxcx/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxcx/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tmxcx/excitation_num", "type": "int"},
{"path": "Tmxcx/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tmxcx/pause", "type": "int", "readonly": false, "cmd": "tt Tmxcx/pause", "description": "pause time [sec] after channel change"},
{"path": "Tmxcx/filter", "type": "int", "readonly": false, "cmd": "tt Tmxcx/filter", "description": "filter average time [sec]"},
{"path": "Tmxcx/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxcx/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tmxcx/status", "type": "text"},
{"path": "Tmxcx/curve", "type": "text", "readonly": false, "cmd": "tt Tmxcx/curve", "kids": 1},
{"path": "Tmxcx/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxcx/curve/points", "visibility": 3},
{"path": "Tmxcx/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxcx/alarm"},
{"path": "Tmxcx/raw", "type": "float"},
{"path": "Tblueo", "type": "float", "kids": 14},
{"path": "Tblueo/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tblueo/active"},
{"path": "Tblueo/autorange", "type": "bool", "readonly": false, "cmd": "tt Tblueo/autorange", "description": "autorange (common for all channels)"},
{"path": "Tblueo/range", "type": "text", "readonly": false, "cmd": "tt Tblueo/range", "description": "resistance range in Ohm"},
{"path": "Tblueo/range_num", "type": "int"},
{"path": "Tblueo/excitation", "type": "text", "readonly": false, "cmd": "tt Tblueo/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tblueo/excitation_num", "type": "int"},
{"path": "Tblueo/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tblueo/pause", "type": "int", "readonly": false, "cmd": "tt Tblueo/pause", "description": "pause time [sec] after channel change"},
{"path": "Tblueo/filter", "type": "int", "readonly": false, "cmd": "tt Tblueo/filter", "description": "filter average time [sec]"},
{"path": "Tblueo/dwell", "type": "int", "readonly": false, "cmd": "tt Tblueo/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tblueo/status", "type": "text"},
{"path": "Tblueo/curve", "type": "text", "readonly": false, "cmd": "tt Tblueo/curve", "kids": 1},
{"path": "Tblueo/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tblueo/curve/points", "visibility": 3},
{"path": "Tblueo/alarm", "type": "float", "readonly": false, "cmd": "tt Tblueo/alarm"},
{"path": "Tblueo/raw", "type": "float"},
{"path": "Tpt50", "type": "float", "kids": 14},
{"path": "Tpt50/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt50/active"},
{"path": "Tpt50/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt50/autorange", "description": "autorange (common for all channels)"},
{"path": "Tpt50/range", "type": "text", "readonly": false, "cmd": "tt Tpt50/range", "description": "resistance range in Ohm"},
{"path": "Tpt50/range_num", "type": "int"},
{"path": "Tpt50/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt50/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tpt50/excitation_num", "type": "int"},
{"path": "Tpt50/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tpt50/pause", "type": "int", "readonly": false, "cmd": "tt Tpt50/pause", "description": "pause time [sec] after channel change"},
{"path": "Tpt50/filter", "type": "int", "readonly": false, "cmd": "tt Tpt50/filter", "description": "filter average time [sec]"},
{"path": "Tpt50/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt50/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tpt50/status", "type": "text"},
{"path": "Tpt50/curve", "type": "text", "readonly": false, "cmd": "tt Tpt50/curve", "kids": 1},
{"path": "Tpt50/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt50/curve/points", "visibility": 3},
{"path": "Tpt50/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt50/alarm"},
{"path": "Tpt50/raw", "type": "float"},
{"path": "Tpt3high", "type": "float", "kids": 14},
{"path": "Tpt3high/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt3high/active"},
{"path": "Tpt3high/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt3high/autorange", "description": "autorange (common for all channels)"},
{"path": "Tpt3high/range", "type": "text", "readonly": false, "cmd": "tt Tpt3high/range", "description": "resistance range in Ohm"},
{"path": "Tpt3high/range_num", "type": "int"},
{"path": "Tpt3high/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt3high/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tpt3high/excitation_num", "type": "int"},
{"path": "Tpt3high/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tpt3high/pause", "type": "int", "readonly": false, "cmd": "tt Tpt3high/pause", "description": "pause time [sec] after channel change"},
{"path": "Tpt3high/filter", "type": "int", "readonly": false, "cmd": "tt Tpt3high/filter", "description": "filter average time [sec]"},
{"path": "Tpt3high/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt3high/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tpt3high/status", "type": "text"},
{"path": "Tpt3high/curve", "type": "text", "readonly": false, "cmd": "tt Tpt3high/curve", "kids": 1},
{"path": "Tpt3high/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt3high/curve/points", "visibility": 3},
{"path": "Tpt3high/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt3high/alarm"},
{"path": "Tpt3high/raw", "type": "float"},
{"path": "Tpt3low", "type": "float", "kids": 14},
{"path": "Tpt3low/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt3low/active"},
{"path": "Tpt3low/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt3low/autorange", "description": "autorange (common for all channels)"},
{"path": "Tpt3low/range", "type": "text", "readonly": false, "cmd": "tt Tpt3low/range", "description": "resistance range in Ohm"},
{"path": "Tpt3low/range_num", "type": "int"},
{"path": "Tpt3low/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt3low/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tpt3low/excitation_num", "type": "int"},
{"path": "Tpt3low/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tpt3low/pause", "type": "int", "readonly": false, "cmd": "tt Tpt3low/pause", "description": "pause time [sec] after channel change"},
{"path": "Tpt3low/filter", "type": "int", "readonly": false, "cmd": "tt Tpt3low/filter", "description": "filter average time [sec]"},
{"path": "Tpt3low/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt3low/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tpt3low/status", "type": "text"},
{"path": "Tpt3low/curve", "type": "text", "readonly": false, "cmd": "tt Tpt3low/curve", "kids": 1},
{"path": "Tpt3low/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt3low/curve/points", "visibility": 3},
{"path": "Tpt3low/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt3low/alarm"},
{"path": "Tpt3low/raw", "type": "float"},
{"path": "Twhite", "type": "float", "kids": 14},
{"path": "Twhite/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Twhite/active"},
{"path": "Twhite/autorange", "type": "bool", "readonly": false, "cmd": "tt Twhite/autorange", "description": "autorange (common for all channels)"},
{"path": "Twhite/range", "type": "text", "readonly": false, "cmd": "tt Twhite/range", "description": "resistance range in Ohm"},
{"path": "Twhite/range_num", "type": "int"},
{"path": "Twhite/excitation", "type": "text", "readonly": false, "cmd": "tt Twhite/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Twhite/excitation_num", "type": "int"},
{"path": "Twhite/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Twhite/pause", "type": "int", "readonly": false, "cmd": "tt Twhite/pause", "description": "pause time [sec] after channel change"},
{"path": "Twhite/filter", "type": "int", "readonly": false, "cmd": "tt Twhite/filter", "description": "filter average time [sec]"},
{"path": "Twhite/dwell", "type": "int", "readonly": false, "cmd": "tt Twhite/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Twhite/status", "type": "text"},
{"path": "Twhite/curve", "type": "text", "readonly": false, "cmd": "tt Twhite/curve", "kids": 1},
{"path": "Twhite/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Twhite/curve/points", "visibility": 3},
{"path": "Twhite/alarm", "type": "float", "readonly": false, "cmd": "tt Twhite/alarm"},
{"path": "Twhite/raw", "type": "float"},
{"path": "Tgreen", "type": "float", "kids": 14},
{"path": "Tgreen/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tgreen/active"},
{"path": "Tgreen/autorange", "type": "bool", "readonly": false, "cmd": "tt Tgreen/autorange", "description": "autorange (common for all channels)"},
{"path": "Tgreen/range", "type": "text", "readonly": false, "cmd": "tt Tgreen/range", "description": "resistance range in Ohm"},
{"path": "Tgreen/range_num", "type": "int"},
{"path": "Tgreen/excitation", "type": "text", "readonly": false, "cmd": "tt Tgreen/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "Tgreen/excitation_num", "type": "int"},
{"path": "Tgreen/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "Tgreen/pause", "type": "int", "readonly": false, "cmd": "tt Tgreen/pause", "description": "pause time [sec] after channel change"},
{"path": "Tgreen/filter", "type": "int", "readonly": false, "cmd": "tt Tgreen/filter", "description": "filter average time [sec]"},
{"path": "Tgreen/dwell", "type": "int", "readonly": false, "cmd": "tt Tgreen/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "Tgreen/status", "type": "text"},
{"path": "Tgreen/curve", "type": "text", "readonly": false, "cmd": "tt Tgreen/curve", "kids": 1},
{"path": "Tgreen/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tgreen/curve/points", "visibility": 3},
{"path": "Tgreen/alarm", "type": "float", "readonly": false, "cmd": "tt Tgreen/alarm"},
{"path": "Tgreen/raw", "type": "float"},
{"path": "analog2", "type": "float", "readonly": false, "cmd": "tt analog2"},
{"path": "remote", "type": "bool"},
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"}]},
"cmn": {"base": "/cmn", "params": [
{"path": "", "type": "none", "kids": 6},
{"path": "send", "type": "text", "readonly": false, "cmd": "cmn send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "u1", "type": "float"},
{"path": "temp", "type": "float"},
{"path": "u2", "type": "float"},
{"path": "chan", "type": "enum", "enum": {"auto": 0, "chan1": 1, "chan2": 2}, "readonly": false, "cmd": "cmn chan"}]}}

View File

@@ -34,7 +34,7 @@ from frappy.lib import formatStatusBits
from frappy.core import Done, Drivable, Parameter, Property, CommonReadHandler, CommonWriteHandler
from frappy.io import HasIO
from frappy_psi.channelswitcher import Channel, ChannelSwitcher
from frappy_psi.picontrol import HasConvergence
from frappy.ctrlby import WrapControlledBy
Status = Drivable.Status

View File

@@ -36,8 +36,8 @@ and this is an example cfg
'controlled T',
meaning=['temperature', 20],
output_module='htr_sample',
p=1,
i=0.01,
p=100,
i=60,
)
@@ -60,79 +60,164 @@ example cfg:
import time
import math
import numpy as np
from frappy.core import Readable, Writable, Parameter, Attached, IDLE, Property
from frappy.lib import clamp, merge_status
from frappy.datatypes import LimitsType, EnumType, FloatRange
from frappy.errors import SECoPError
from frappy.ctrlby import HasOutputModule, WrapControlledBy
from frappy_psi.convergence import HasConvergence
def ext_poll_value(mobj):
prev = mobj.parameters['value'].timestamp
mobj.doPoll()
if mobj.parameters['value'].timestamp <= prev:
# value was not updated
mobj.read_value()
# disable polling for the next interval
interval = mobj.pollInfo.interval
if interval:
mobj.pollInfo.last_main = (time.time() // interval) * interval
return mobj.value
class PImixin(HasOutputModule, Writable):
p = Parameter('proportional term', FloatRange(0), readonly=False)
i = Parameter('integral term', FloatRange(0), readonly=False)
value = Parameter(unit='K', update_unchanged='always')
p = Parameter('proportional term', FloatRange(0), readonly=False, default=1)
i = Parameter('integral term', FloatRange(0), readonly=False, default=1)
status = Parameter(update_unchanged='never')
itime = Parameter('integration time', FloatRange(0, unit='s'), default=60, readonly=False)
control_active = Parameter(readonly=False)
# output_module is inherited
output_range = Property('legacy output range', LimitsType(FloatRange()), default=(0,0))
output_range = Property('legacy output range', LimitsType(FloatRange()), default=(0, 0))
output_min = Parameter('min output', FloatRange(), default=0, readonly=False)
output_max = Parameter('max output', FloatRange(), default=0, readonly=False)
output_func = Parameter('output function',
EnumType(lin=0, square=1), readonly=False, value=0)
value = Parameter(unit='K')
input_scale = Property('input scale', FloatRange(unit='$'), default=100)
time_scale = Property('time scale', FloatRange(unit='s'), default=60)
overflow = Parameter('overflow', FloatRange(), default=0, readonly=False)
_lastdiff = None
_lasttime = 0
_get_range = None # a function get output range from output_module
_overflow = 0
_cvt2int = None
_cvt2ext = None
_itime_set = None # True: 'itime' was set, False: 'i' was set
_history = None
__errcnt = 0
__inside_poll = False
__cache = None
# with input units K and output units %:
# units for p: % / K
# units for i: % / K / min
def initModule(self):
self.__cache = {}
super().initModule()
if self.output_range != (0, 0): # legacy !
self.output_min, self.output_max = self.output_range
self.get_range_func()
self.addCallback('value', self.__inside, 'value')
self.addCallback('status', self.__inside, 'status')
def __inside(self, value, pname):
if self.__inside_poll is not None:
self.__cache[pname] = value
def doPoll(self):
super().doPoll()
if not self.control_active:
return
out = self.output_module
try:
self.__inside_poll = True
self.__cache = {}
now = time.time()
value = self.read_value()
if self._history is None:
# initialize a fixed size array, with fake time axis to avoid errors in np.polyfit
self._history = np.array([(now+i, self.value) for i in range(-9,1)])
else:
# shift fixed size array, and change last point
self._history[:-1] = self._history[1:]
self._history[-1] = (now, value)
if not self.control_active:
self._lastdiff = 0
return
self.read_status()
out = self.output_module
deltat = clamp(0, now-self._lasttime, 10)
self._lasttime = now
diff = self.target - self.value
diff = self.target - value
if self._lastdiff is None:
self._lastdiff = diff
deltadiff = diff - self._lastdiff
self._lastdiff = diff
output, omin, omax = self._cvt2int(out.target)
output += self._overflow + self.p * deltadiff + self.i * deltat * diff
if output < omin:
self._overflow = max(omin - omax, output - omin)
output = omin
elif output > omax:
self._overflow = min(omax - omin, output - omax)
output = omax
else:
if diff:
ref = self.itime / diff
(slope, _), cov = np.polyfit(self._history[:, 0] - now, self._history[:, 1], 1, cov=True)
slope_stddev = np.sqrt(max(0, cov[0, 0]))
if slope * ref > 1 + 2 * slope_stddev * abs(ref):
# extrapolated value will cross target in less than itime
if self._overflow:
self._overflow = 0
out.update_target(self.name, self._cvt2ext(output))
self.log.info('clear overflow')
output, omin, omax = self.cvt2int(out.target)
output += self._overflow + (
self.p * deltadiff +
self.i * deltat * diff / self.time_scale) / self.input_scale
if omin <= output <= omax:
self._overflow = 0
else:
# save overflow for next step
if output < omin:
self._overflow = output - omin
output = omin
else:
self._overflow = output - omax
output = omax
out.update_target(self.name, self.cvt2ext(output))
self.__errcnt = 0
except Exception as e:
if self.control_active:
self.__errcnt += 1
if self.__errcnt > 5:
self.__errcnt = 0
self.log.warning('too many errors - switch control off')
self.write_control_active(False)
raise
finally:
self.__inside_poll = False
self.__cache = {}
self.overflow = self._overflow
def write_overflow(self, value):
self._overflow = value
def internal_poll(self):
super().doPoll()
def internal_read_value(self):
return super().read_value()
def internal_read_status(self):
return super().read_status()
def read_value(self):
try:
return self.__cache['value']
except KeyError:
return self.internal_read_value()
def read_status(self):
try:
return self.__cache['status']
except KeyError:
pass
status = IDLE, 'controlling' if self.control_active else 'inactive'
if hasattr(super(), 'read_status'):
status = merge_status(super().read_status(), status)
status = merge_status(self.internal_read_status(), status)
return status
def cvt2int_square(self, output):
return (math.sqrt(max(0, clamp(x, *self._get_range()))) for x in (output, self.output_min, self.output_max))
def cvt2ext_square(self, output):
return output ** 2
def cvt2int_lin(self, output):
return (clamp(x, *self._get_range()) for x in (output, self.output_min, self.output_max))
def cvt2ext_lin(self, output):
return output
def write_output_func(self, value):
def get_range_func(self):
out = self.output_module
if hasattr(out, 'max_target'):
if hasattr(self, 'min_target'):
@@ -147,32 +232,72 @@ class PImixin(HasOutputModule, Writable):
self._get_range = lambda o=self: (o.output_min, o.output_max)
if self.output_min == self.output_max == 0:
self.output_min, self.output_max = self._get_range()
self.output_func = value
self._cvt2int = getattr(self, f'cvt2int_{self.output_func.name}')
self._cvt2ext = getattr(self, f'cvt2ext_{self.output_func.name}')
# not needed, done by HasOutputModule.write_control_active
# def write_control_active(self, value):
# super().write_control_active(value)
# out = self.output_module
# if not value:
# out.write_target(out.parameters['target'].datatype.default)
def cvt2int(self, output):
return (clamp(x, *self._get_range()) for x in (output, self.output_min, self.output_max))
def cvt2ext(self, output):
return output
def calc_itime(self, prop, integ):
return prop * self.time_scale / integ
def write_p(self, value):
if self._itime_set:
self.i = value * self.time_scale / self.itime
elif self._itime_set is False: # means also not None
self.itime = value * self.time_scale / self.i
def write_i(self, value):
self._itime_set = False
self.itime = self.p * self.time_scale / value
def write_itime(self, value):
self._itime_set = True
self.i = self.p * self.time_scale / value
def set_target(self, value):
if not self.control_active:
self.activate_control()
self.target = value
self.doPoll()
class PImixinSquare(PImixin):
"""unchecked: use square as output function"""
def cvt2int(self, output):
return (math.sqrt(max(0, 100 * clamp(x, *self._get_range())))
for x in (output, self.output_min, self.output_max))
def cvt2ext(self, output):
return output ** 2 / 100
class PI(HasConvergence, PImixin):
input_module = Attached(Readable, 'the input module')
def read_value(self):
return self.input_module.value
def internal_poll(self):
inp = self.input_module
inp.doPoll()
interval = inp.pollInfo.interval
if interval > 0:
# disable next internal poll
inp.pollInfo.last_main = (time.time() // interval) * interval
self.read_value()
self.read_status()
def read_status(self):
return self.input_module.status
def internal_read_value(self):
return self.input_module.read_value()
def internal_read_status(self):
return self.input_module.read_status()
def write_target(self, target):
super().write_target(target)
self.convergence_start()
# unchecked!
class PI2(PI):
maxovershoot = Parameter('max. overshoot', FloatRange(0, 100, unit='%'), readonly=False, default=20)

View File

@@ -21,6 +21,7 @@
from frappy.core import StringIO, HasIO, Writable, Parameter, Property, FloatRange, IntRange, BoolType, \
ERROR
from frappy.errors import CommunicationFailedError, HardwareError
from frappy.ctrlby import WrapControlledBy
class IO(StringIO):
@@ -36,7 +37,7 @@ class Heater(HasIO, Writable):
channel = Property('channel (source number)', IntRange(1, 3))
value = Parameter('current reading', FloatRange(0, 0.1, unit='A'))
target = Parameter('current target value', FloatRange(0, 0.1, unit='A'), readonly=False)
on = Parameter('turn current on/off', BoolType(), readonly=False)
on = Parameter('turn current on/off', BoolType(), readonly=False, default=False)
def query_status(self):
reply, txtvalue = self.communicate('STATUS?').split('\t')
@@ -64,13 +65,14 @@ class Heater(HasIO, Writable):
if reply != '0': # not as in manual
raise CommunicationFailedError(f'Bad reply: {reply!r}')
def read_target(self):
def read_value(self):
txtvalue = self.query_status()
current_range = txtvalue[(self.channel - 1) * 4 + 1]
current = txtvalue[(self.channel - 1) * 4 + 1 + 1] # percent of range
multipliers = {'1': 99e-6, '2': 990e-6, '3': 9900e-6, '4': 99e-3}
multipliers = {'1': 1e-4, '2': 1e-3, '3': 1e-2, '4': 1e-1}
value = float(current) / 100 * float(multipliers[current_range])
return value
# no measured value available
read_value = read_target
class WrappedHeater(WrapControlledBy, Heater):
pass