Skip to content

Commit c3dfe0d

Browse files
committed
Term version read and window hide added
Now the term version is read and checked if it fits to the library. Added a function to hide the term window. This is useful for integrations to prevent the user from manually operating the GUI when running a measurement remotely. Added example of how to measure DC with Remote at different currents and then measure EIS. Thales/Term version 5.8.6 is required.
1 parent 2542d81 commit c3dfe0d

15 files changed

Lines changed: 847 additions & 387 deletions

File tree

Examples/BasicIntroduction/BasicIntroduction.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
"\n",
8484
"if __name__ == \"__main__\":\n",
8585
" zenniumConnection = ThalesRemoteConnection()\n",
86-
" zenniumConnection.connectToTerm(TARGET_HOST, \"ScriptRemote\")"
86+
" zenniumConnection.connectToTerm(TARGET_HOST)"
8787
]
8888
},
8989
{

Examples/BasicIntroduction/BasicIntroduction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def spectrum(scriptHandle, lower_frequency, upper_frequency, number_of_points):
3131

3232
if __name__ == "__main__":
3333
zenniumConnection = ThalesRemoteConnection()
34-
zenniumConnection.connectToTerm(TARGET_HOST, "ScriptRemote")
34+
zenniumConnection.connectToTerm(TARGET_HOST)
3535

3636
zahnerZennium = ThalesRemoteScriptWrapper(zenniumConnection)
3737
zahnerZennium.forceThalesIntoRemoteScript()
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
{
2+
"cells": [
3+
{
4+
"attachments": {},
5+
"cell_type": "markdown",
6+
"metadata": {},
7+
"source": [
8+
"# Polarization and EIS at different currents\n",
9+
"\n",
10+
"In this example the [Zahner DC Sequencer](https://doc.zahner.de/manuals/sequencer.pdf) is used and EIS is measured.\n",
11+
"With the DC Sequencer, OCP is measured first and then constant current is output. The constant current phase is followed by an impedance spectra. This example can be used as a template when measuring at different current densities, e.g. fuel cells.\n",
12+
"\n",
13+
"The feature of this script is that the [Jinja2](https://jinja.palletsprojects.com/en/3.1.x/) template engine is used to create the sequence files with different currents, which are then executed.\n",
14+
"\n",
15+
"For the DC Sequencer alone there is a separate [example](https://github.com/Zahner-elektrik/Thales-Remote-Python/blob/main/Examples/DCSequencer/DCSequencer.ipynb)."
16+
]
17+
},
18+
{
19+
"cell_type": "code",
20+
"execution_count": 1,
21+
"metadata": {},
22+
"outputs": [],
23+
"source": [
24+
"import os\n",
25+
"import jinja2\n",
26+
"from thales_remote.connection import ThalesRemoteConnection\n",
27+
"from thales_remote.script_wrapper import (\n",
28+
" PotentiostatMode,\n",
29+
" ScanDirection,\n",
30+
" ThalesRemoteScriptWrapper,\n",
31+
" FileNaming,\n",
32+
" ScanStrategy,\n",
33+
")\n"
34+
]
35+
},
36+
{
37+
"attachments": {},
38+
"cell_type": "markdown",
39+
"metadata": {},
40+
"source": [
41+
"# Function to generate the seq sequence files\n",
42+
"\n",
43+
"There is a sequence file as template with the name *ocp_constant_current_template.txt*, this file contains the placeholders, which are then filled with Jinja2. For example, the placeholders are: `\\PYVAR{dc_time}`. The function `fillTemplateFile()` is then passed the parameters as keyworded variables (kwargs) for example: `dc_time=2.0`.\n",
44+
"\n",
45+
"Extract from the sequence file:\n",
46+
"```\n",
47+
" start_cycle\t\n",
48+
" samples(10)\n",
49+
" ocp(TIM2)\n",
50+
" hold_cur(CUR1,TIM1)\n",
51+
" end_cycle\n",
52+
" \n",
53+
" start_variables\n",
54+
" TIM1=\\PYVAR{dc_time}\n",
55+
" TIM2=\\PYVAR{ocp_time}\n",
56+
" CUR1=\\PYVAR{dc_current}\n",
57+
" end_variables\n",
58+
"```\n",
59+
"\n",
60+
"At 10 Hz the measurements are performed, first an OCP phase and then a constant current phase.\n",
61+
"\n",
62+
"When the template is filled, the complete file is written according to the corresponding path with the filename."
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": 2,
68+
"metadata": {},
69+
"outputs": [],
70+
"source": [
71+
"def fillTemplateFile(templateFile: str, outputFile: str, **kwargs):\n",
72+
" \"\"\"\n",
73+
" Function to fill in template files.\n",
74+
"\n",
75+
" For example, the following placeholders must be in the passed template:\n",
76+
" `\\PYVAR{dc_time}`\n",
77+
"\n",
78+
" Then the value for the template must be passed as an additional parameter as keyworded variable (kwargs):\n",
79+
" `dc_time=2.0`\n",
80+
"\n",
81+
" :param templateFile: path of the file containing the templates.\n",
82+
" :param outputFile: path to the file containing the completed templates.\n",
83+
" :param **kwargs: template parameters which should be filled in as keyworded variable.\n",
84+
" \"\"\"\n",
85+
" latex_jinja_env = jinja2.Environment(\n",
86+
" variable_start_string=\"\\PYVAR{\",\n",
87+
" variable_end_string=\"}\",\n",
88+
" trim_blocks=True,\n",
89+
" autoescape=False,\n",
90+
" loader=jinja2.FileSystemLoader(os.path.abspath(\".\")),\n",
91+
" )\n",
92+
"\n",
93+
" template = latex_jinja_env.get_template(templateFile)\n",
94+
"\n",
95+
" fileString = template.render(**kwargs)\n",
96+
"\n",
97+
" fileString = bytearray(fileString, \"utf-8\")\n",
98+
" f = open(outputFile, \"wb\")\n",
99+
" f.write(fileString)\n",
100+
" f.close()\n",
101+
"\n",
102+
" return\n"
103+
]
104+
},
105+
{
106+
"attachments": {},
107+
"cell_type": "markdown",
108+
"metadata": {},
109+
"source": [
110+
"# Initialize the Measurement\n",
111+
"\n",
112+
"The list `currentSteps` defines the DC currents at which DC is measured and at which impedance is measured.\n",
113+
"The variable `amplitude` specifies the amplitude which is used for all currents.\n",
114+
"\n",
115+
"Afterwards the connection to the already running Thales/Term software is established."
116+
]
117+
},
118+
{
119+
"cell_type": "code",
120+
"execution_count": 3,
121+
"metadata": {},
122+
"outputs": [],
123+
"source": [
124+
"if __name__ == \"__main__\":\n",
125+
" currentSteps = [0, 0.5, 1, 1.5, 2]\n",
126+
" amplitude = 0.05\n",
127+
"\n",
128+
" zenniumConnection = ThalesRemoteConnection()\n",
129+
" zenniumConnection.connectToTerm(\"localhost\")\n",
130+
" zahnerZennium = ThalesRemoteScriptWrapper(zenniumConnection)\n",
131+
" zahnerZennium.forceThalesIntoRemoteScript()\n"
132+
]
133+
},
134+
{
135+
"attachments": {},
136+
"cell_type": "markdown",
137+
"metadata": {},
138+
"source": [
139+
"# Perform the Measurements\n",
140+
"\n",
141+
"A for loop is used to iterate over the different current points. For each current a new seq-file is created with the function `fillTemplateFile()` from the template file.\n",
142+
"\n",
143+
"Then the sequence written to number 9 is performed and the EIS measurement is parameterized and done in the same way. For the DC measurement and the EIS, a file is saved, which has the current in mA in the name, since there must not be any \",\" or \".\" in the filename."
144+
]
145+
},
146+
{
147+
"cell_type": "code",
148+
"execution_count": 4,
149+
"metadata": {},
150+
"outputs": [
151+
{
152+
"name": "stdout",
153+
"output_type": "stream",
154+
"text": [
155+
"Step: 0\n",
156+
"Step: 0.5\n",
157+
"Step: 1\n",
158+
"Step: 1.5\n",
159+
"Step: 2\n"
160+
]
161+
}
162+
],
163+
"source": [
164+
" for current in currentSteps:\n",
165+
" print(f\"Step: {current}\")\n",
166+
" \"\"\"\n",
167+
" DC Sequence\n",
168+
" \"\"\"\n",
169+
" fillTemplateFile(\n",
170+
" templateFile=r\"ocp_constant_current_template.txt\",\n",
171+
" outputFile=r\"C:\\THALES\\script\\sequencer\\sequences\\sequence09.seq\",\n",
172+
" ocp_time=10,\n",
173+
" dc_time=20,\n",
174+
" dc_current=current,\n",
175+
" )\n",
176+
"\n",
177+
" filename = f\"{int(current*1000)}ma_current\"\n",
178+
"\n",
179+
" zahnerZennium.setSequenceNaming(FileNaming.INDIVIDUAL)\n",
180+
" zahnerZennium.setSequenceOutputPath(r\"C:\\THALES\\temp\")\n",
181+
" zahnerZennium.setSequenceOutputFileName(filename)\n",
182+
" zahnerZennium.selectSequence(9)\n",
183+
" zahnerZennium.runSequence()\n",
184+
"\n",
185+
" \"\"\"\n",
186+
" EIS\n",
187+
" \"\"\"\n",
188+
" zahnerZennium.setEISNaming(FileNaming.INDIVIDUAL)\n",
189+
" zahnerZennium.setEISOutputPath(r\"C:\\THALES\\temp\")\n",
190+
" zahnerZennium.setEISOutputFileName(filename)\n",
191+
" zahnerZennium.setPotentiostatMode(PotentiostatMode.POTMODE_GALVANOSTATIC)\n",
192+
" zahnerZennium.setAmplitude(amplitude)\n",
193+
" zahnerZennium.setCurrent(current)\n",
194+
" zahnerZennium.setLowerFrequencyLimit(10)\n",
195+
" zahnerZennium.setStartFrequency(1000)\n",
196+
" zahnerZennium.setUpperFrequencyLimit(10000)\n",
197+
" zahnerZennium.setLowerNumberOfPeriods(5)\n",
198+
" zahnerZennium.setLowerStepsPerDecade(2)\n",
199+
" zahnerZennium.setUpperNumberOfPeriods(20)\n",
200+
" zahnerZennium.setUpperStepsPerDecade(5)\n",
201+
" zahnerZennium.setScanDirection(ScanDirection.START_TO_MAX)\n",
202+
" zahnerZennium.setScanStrategy(ScanStrategy.SINGLE_SINE)\n",
203+
"\n",
204+
" zahnerZennium.measureEIS()\n",
205+
"\n",
206+
" zahnerZennium.setAmplitude(0)\n",
207+
"\n",
208+
" zahnerZennium.disablePotentiostat()\n",
209+
" zenniumConnection.disconnectFromTerm()\n",
210+
" "
211+
]
212+
}
213+
],
214+
"metadata": {
215+
"kernelspec": {
216+
"display_name": "Python 3",
217+
"language": "python",
218+
"name": "python3"
219+
},
220+
"language_info": {
221+
"codemirror_mode": {
222+
"name": "ipython",
223+
"version": 3
224+
},
225+
"file_extension": ".py",
226+
"mimetype": "text/x-python",
227+
"name": "python",
228+
"nbconvert_exporter": "python",
229+
"pygments_lexer": "ipython3",
230+
"version": "3.11.2"
231+
},
232+
"orig_nbformat": 4
233+
},
234+
"nbformat": 4,
235+
"nbformat_minor": 2
236+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import os
2+
import jinja2
3+
from thales_remote.connection import ThalesRemoteConnection
4+
from thales_remote.script_wrapper import (
5+
PotentiostatMode,
6+
ScanDirection,
7+
ThalesRemoteScriptWrapper,
8+
FileNaming,
9+
ScanStrategy,
10+
)
11+
12+
13+
def fillTemplateFile(templateFile: str, outputFile: str, **kwargs):
14+
"""
15+
Function to fill in template files.
16+
17+
For example, the following placeholders must be in the passed template:
18+
`\PYVAR{dc_time}`
19+
20+
Then the value for the template must be passed as an additional parameter as keyworded variable (kwargs):
21+
`dc_time=2.0`
22+
23+
:param templateFile: path of the file containing the templates.
24+
:param outputFile: path to the file containing the completed templates.
25+
:param **kwargs: template parameters which should be filled in as keyworded variable.
26+
"""
27+
latex_jinja_env = jinja2.Environment(
28+
variable_start_string="\PYVAR{",
29+
variable_end_string="}",
30+
trim_blocks=True,
31+
autoescape=False,
32+
loader=jinja2.FileSystemLoader(os.path.abspath(".")),
33+
)
34+
35+
template = latex_jinja_env.get_template(templateFile)
36+
37+
fileString = template.render(**kwargs)
38+
39+
fileString = bytearray(fileString, "utf-8")
40+
f = open(outputFile, "wb")
41+
f.write(fileString)
42+
f.close()
43+
44+
return
45+
46+
47+
if __name__ == "__main__":
48+
currentSteps = [0, 0.5, 1, 1.5, 2]
49+
amplitude = 0.05
50+
51+
zenniumConnection = ThalesRemoteConnection()
52+
zenniumConnection.connectToTerm("localhost")
53+
zahnerZennium = ThalesRemoteScriptWrapper(zenniumConnection)
54+
zahnerZennium.forceThalesIntoRemoteScript()
55+
56+
for current in currentSteps:
57+
print(f"Step: {current}")
58+
"""
59+
DC Sequence
60+
"""
61+
fillTemplateFile(
62+
templateFile=r"ocp_constant_current_template.txt",
63+
outputFile=r"C:\THALES\script\sequencer\sequences\sequence09.seq",
64+
ocp_time=10,
65+
dc_time=20,
66+
dc_current=current,
67+
)
68+
69+
filename = f"{int(current*1000)}ma_current"
70+
71+
zahnerZennium.setSequenceNaming(FileNaming.INDIVIDUAL)
72+
zahnerZennium.setSequenceOutputPath(r"C:\THALES\temp")
73+
zahnerZennium.setSequenceOutputFileName(filename)
74+
zahnerZennium.selectSequence(9)
75+
zahnerZennium.runSequence()
76+
77+
"""
78+
EIS
79+
"""
80+
zahnerZennium.setEISNaming(FileNaming.INDIVIDUAL)
81+
zahnerZennium.setEISOutputPath(r"C:\THALES\temp")
82+
zahnerZennium.setEISOutputFileName(filename)
83+
zahnerZennium.setPotentiostatMode(PotentiostatMode.POTMODE_GALVANOSTATIC)
84+
zahnerZennium.setAmplitude(amplitude)
85+
zahnerZennium.setCurrent(current)
86+
zahnerZennium.setLowerFrequencyLimit(10)
87+
zahnerZennium.setStartFrequency(1000)
88+
zahnerZennium.setUpperFrequencyLimit(10000)
89+
zahnerZennium.setLowerNumberOfPeriods(5)
90+
zahnerZennium.setLowerStepsPerDecade(2)
91+
zahnerZennium.setUpperNumberOfPeriods(20)
92+
zahnerZennium.setUpperStepsPerDecade(5)
93+
zahnerZennium.setScanDirection(ScanDirection.START_TO_MAX)
94+
zahnerZennium.setScanStrategy(ScanStrategy.SINGLE_SINE)
95+
96+
zahnerZennium.measureEIS()
97+
98+
zahnerZennium.setAmplitude(0)
99+
100+
zahnerZennium.disablePotentiostat()
101+
zenniumConnection.disconnectFromTerm()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
start_cycle
2+
samples(10)
3+
ocp(TIM2)
4+
hold_cur(CUR1,TIM1)
5+
end_cycle
6+
7+
start_variables
8+
TIM1=\PYVAR{dc_time}
9+
TIM2=\PYVAR{ocp_time}
10+
CUR1=\PYVAR{dc_current}
11+
end_variables
12+
13+
start_online
14+
cur_hi=3
15+
cur_lo=-3
16+
pot_hi=4
17+
pot_lo=-4
18+
pot_of=2
19+
cur_of=2
20+
end_on=1
21+
end_online

0 commit comments

Comments
 (0)