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.core import Done, Drivable, Parameter, Property, CommonReadHandler, CommonWriteHandler
from frappy.io import HasIO from frappy.io import HasIO
from frappy_psi.channelswitcher import Channel, ChannelSwitcher from frappy_psi.channelswitcher import Channel, ChannelSwitcher
from frappy_psi.picontrol import HasConvergence from frappy.ctrlby import WrapControlledBy
Status = Drivable.Status Status = Drivable.Status

View File

@@ -36,8 +36,8 @@ and this is an example cfg
'controlled T', 'controlled T',
meaning=['temperature', 20], meaning=['temperature', 20],
output_module='htr_sample', output_module='htr_sample',
p=1, p=100,
i=0.01, i=60,
) )
@@ -60,79 +60,164 @@ example cfg:
import time import time
import math import math
import numpy as np
from frappy.core import Readable, Writable, Parameter, Attached, IDLE, Property from frappy.core import Readable, Writable, Parameter, Attached, IDLE, Property
from frappy.lib import clamp, merge_status from frappy.lib import clamp, merge_status
from frappy.datatypes import LimitsType, EnumType, FloatRange from frappy.datatypes import LimitsType, EnumType, FloatRange
from frappy.errors import SECoPError
from frappy.ctrlby import HasOutputModule, WrapControlledBy from frappy.ctrlby import HasOutputModule, WrapControlledBy
from frappy_psi.convergence import HasConvergence 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): class PImixin(HasOutputModule, Writable):
p = Parameter('proportional term', FloatRange(0), readonly=False) value = Parameter(unit='K', update_unchanged='always')
i = Parameter('integral term', FloatRange(0), readonly=False) 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_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_min = Parameter('min output', FloatRange(), default=0, readonly=False)
output_max = Parameter('max output', FloatRange(), default=0, readonly=False) output_max = Parameter('max output', FloatRange(), default=0, readonly=False)
output_func = Parameter('output function', input_scale = Property('input scale', FloatRange(unit='$'), default=100)
EnumType(lin=0, square=1), readonly=False, value=0) time_scale = Property('time scale', FloatRange(unit='s'), default=60)
value = Parameter(unit='K') overflow = Parameter('overflow', FloatRange(), default=0, readonly=False)
_lastdiff = None _lastdiff = None
_lasttime = 0 _lasttime = 0
_get_range = None # a function get output range from output_module _get_range = None # a function get output range from output_module
_overflow = 0 _overflow = 0
_cvt2int = None _itime_set = None # True: 'itime' was set, False: 'i' was set
_cvt2ext = None _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): def initModule(self):
self.__cache = {}
super().initModule() super().initModule()
if self.output_range != (0, 0): # legacy ! if self.output_range != (0, 0): # legacy !
self.output_min, self.output_max = self.output_range 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): def doPoll(self):
super().doPoll() try:
if not self.control_active: self.__inside_poll = True
return self.__cache = {}
out = self.output_module
now = time.time() 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) deltat = clamp(0, now-self._lasttime, 10)
self._lasttime = now self._lasttime = now
diff = self.target - self.value diff = self.target - value
if self._lastdiff is None: if self._lastdiff is None:
self._lastdiff = diff self._lastdiff = diff
deltadiff = diff - self._lastdiff deltadiff = diff - self._lastdiff
self._lastdiff = diff self._lastdiff = diff
output, omin, omax = self._cvt2int(out.target) if diff:
output += self._overflow + self.p * deltadiff + self.i * deltat * diff ref = self.itime / diff
if output < omin: (slope, _), cov = np.polyfit(self._history[:, 0] - now, self._history[:, 1], 1, cov=True)
self._overflow = max(omin - omax, output - omin) slope_stddev = np.sqrt(max(0, cov[0, 0]))
output = omin if slope * ref > 1 + 2 * slope_stddev * abs(ref):
elif output > omax: # extrapolated value will cross target in less than itime
self._overflow = min(omax - omin, output - omax) if self._overflow:
output = omax
else:
self._overflow = 0 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): def read_status(self):
try:
return self.__cache['status']
except KeyError:
pass
status = IDLE, 'controlling' if self.control_active else 'inactive' status = IDLE, 'controlling' if self.control_active else 'inactive'
if hasattr(super(), 'read_status'): if hasattr(super(), 'read_status'):
status = merge_status(super().read_status(), status) status = merge_status(self.internal_read_status(), status)
return status return status
def cvt2int_square(self, output): def get_range_func(self):
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):
out = self.output_module out = self.output_module
if hasattr(out, 'max_target'): if hasattr(out, 'max_target'):
if hasattr(self, 'min_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) self._get_range = lambda o=self: (o.output_min, o.output_max)
if self.output_min == self.output_max == 0: if self.output_min == self.output_max == 0:
self.output_min, self.output_max = self._get_range() 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 cvt2int(self, output):
# def write_control_active(self, value): return (clamp(x, *self._get_range()) for x in (output, self.output_min, self.output_max))
# super().write_control_active(value)
# out = self.output_module def cvt2ext(self, output):
# if not value: return output
# out.write_target(out.parameters['target'].datatype.default)
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): def set_target(self, value):
if not self.control_active: if not self.control_active:
self.activate_control() 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): class PI(HasConvergence, PImixin):
input_module = Attached(Readable, 'the input module') input_module = Attached(Readable, 'the input module')
def read_value(self): def internal_poll(self):
return self.input_module.value 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): def internal_read_value(self):
return self.input_module.status 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): class PI2(PI):
maxovershoot = Parameter('max. overshoot', FloatRange(0, 100, unit='%'), readonly=False, default=20) 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, \ from frappy.core import StringIO, HasIO, Writable, Parameter, Property, FloatRange, IntRange, BoolType, \
ERROR ERROR
from frappy.errors import CommunicationFailedError, HardwareError from frappy.errors import CommunicationFailedError, HardwareError
from frappy.ctrlby import WrapControlledBy
class IO(StringIO): class IO(StringIO):
@@ -36,7 +37,7 @@ class Heater(HasIO, Writable):
channel = Property('channel (source number)', IntRange(1, 3)) channel = Property('channel (source number)', IntRange(1, 3))
value = Parameter('current reading', FloatRange(0, 0.1, unit='A')) value = Parameter('current reading', FloatRange(0, 0.1, unit='A'))
target = Parameter('current target value', FloatRange(0, 0.1, unit='A'), readonly=False) 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): def query_status(self):
reply, txtvalue = self.communicate('STATUS?').split('\t') reply, txtvalue = self.communicate('STATUS?').split('\t')
@@ -64,13 +65,14 @@ class Heater(HasIO, Writable):
if reply != '0': # not as in manual if reply != '0': # not as in manual
raise CommunicationFailedError(f'Bad reply: {reply!r}') raise CommunicationFailedError(f'Bad reply: {reply!r}')
def read_target(self): def read_value(self):
txtvalue = self.query_status() txtvalue = self.query_status()
current_range = txtvalue[(self.channel - 1) * 4 + 1] current_range = txtvalue[(self.channel - 1) * 4 + 1]
current = txtvalue[(self.channel - 1) * 4 + 1 + 1] # percent of range 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]) value = float(current) / 100 * float(multipliers[current_range])
return value return value
# no measured value available
read_value = read_target class WrappedHeater(WrapControlledBy, Heater):
pass