sync to notebook

This commit is contained in:
Stefan Kögl 2012-11-23 14:03:40 +01:00
parent b494a9c05e
commit bfbddcc731
2 changed files with 165 additions and 80 deletions

View File

@ -3,6 +3,8 @@
import sys, os, random, copy, struct import sys, os, random, copy, struct
from datetime import datetime
from collections import deque from collections import deque
from operator import attrgetter from operator import attrgetter
@ -56,6 +58,11 @@ def set_colors(temp_levels):
def get_valid_neigbors(temp_level, temp_levels):
ix = temp_levels.index(temp_level)
return temp_levels[ix-1], temp_levels[ix+1]
def create_profile_header(x_list, y_list): def create_profile_header(x_list, y_list):
tpl = "#ifndef _H_SOLDER_PROFILE\n" \ tpl = "#ifndef _H_SOLDER_PROFILE\n" \
"#define _H_SOLDER_PROFILE\n" \ "#define _H_SOLDER_PROFILE\n" \
@ -99,11 +106,31 @@ def getTemperature():
class TempLevel(QtCore.QObject): class TempLevel(QtCore.QObject):
def __init__(self, name, temp, is_env=False): def __init__(self, name, temp, is_env=False):
super(TempLevel, self).__init__()
self.name = name self.name = name
self.temp = temp self.temp = temp
self.is_env = is_env self.is_env = is_env
self.color = None self.color = None
def __str__(self):
return "<TempLevel: name=%r, temp=%r>" % (self.name, self.temp)
def __lt__(self, other):
return self.temp < other.temp
def __le__(self, other):
return self.temp <= other.temp
def __eq__(self, other):
return self.temp == other.temp
def is_between(self, tl1, tl2):
tmp = [tl1, tl2, self]
tmp.sort()
return self == tmp[1]
__repr__ = __str__
class TempLevelModel(QtCore.QAbstractTableModel): class TempLevelModel(QtCore.QAbstractTableModel):
solder_changed = QtCore.pyqtSignal() solder_changed = QtCore.pyqtSignal()
@ -184,8 +211,11 @@ class TempLevelModel(QtCore.QAbstractTableModel):
self.reset() self.reset()
class TempLevelWidget(QtGui.QWidget): class TempLevelWidget(QtGui.QWidget):
temp_level_removed = QtCore.pyqtSignal(TempLevel) temp_level_removed = QtCore.pyqtSignal(TempLevel)
temp_levels_changed = QtCore.pyqtSignal()
solder_changed = QtCore.pyqtSignal() solder_changed = QtCore.pyqtSignal()
def __init__(self, parent, readonly=False): def __init__(self, parent, readonly=False):
@ -246,12 +276,14 @@ class TempLevelWidget(QtGui.QWidget):
def setData(self, solder): def setData(self, solder):
self.temp_level_model.setTempLevels(solder.temp_levels) self.temp_level_model.setTempLevels(solder.temp_levels)
self.temp_level_view.resizeColumnsToContents() self.temp_level_view.resizeColumnsToContents()
self.temp_level_view.setCurrentIndex(self.temp_level_model.index(0, 0))
def add_temp_level(self): def add_temp_level(self):
index = self.temp_level_view.currentIndex() index = self.temp_level_view.currentIndex()
self.temp_level_model.add_temp_level(index, TempLevel("new " + str(self.temp_level_model.rowCount(None)), 0)) self.temp_level_model.add_temp_level(index, TempLevel("new " + str(self.temp_level_model.rowCount(None)), 0))
self.temp_level_view.setCurrentIndex(self.temp_level_model.index(index.row() + 1, 0)) self.temp_level_view.setCurrentIndex(self.temp_level_model.index(index.row() + 1, 0))
self.temp_levels_changed.emit()
def remove_temp_level(self): def remove_temp_level(self):
@ -328,26 +360,32 @@ class Solder(QtCore.QObject):
def calc_rate(self, x1, y1, x2, y2): def calc_rate(self, x1, y1, x2, y2):
return (y2 - y1) / (x2 - x1) return (y2 - y1) / (x2 - x1)
def check_duration_constraints(self, temp_level, used): def check_duration_constraints(self, temp_level, used, ix):
x = list() x = list()
y = list() y = list()
temp_levels = None temp_levels = None
value = None value = None
dx = 0
for temp_levels, value in self.durations: for temp_levels, value in self.durations:
tl_len = len(temp_levels) tl_len = len(temp_levels)
if temp_levels and temp_levels[0] == temp_level and tl_len > 1: print "check dur", dx, temp_level, repr(temp_levels), self.ud
if temp_levels and temp_levels[0] == temp_level and tl_len > 1 and dx not in self.ud:
if temp_level not in used: if temp_level not in used:
used.add(temp_level) used.add(temp_level)
x.append(self.time) x.append(self.time)
y.append(temp_level.temp) y.append(temp_level.temp)
self.ud.add(dx)
print "using duration constraint", dx
if tl_len == 2: if tl_len == 2:
ix = self.temp_levels.index(temp_levels[1])
y.append(temp_levels[1].temp) y.append(temp_levels[1].temp)
used.add(temp_levels[1]) used.add(temp_levels[1])
self.time += value self.time += value
x.append(self.time) x.append(self.time)
elif tl_len >= 3: elif tl_len >= 3:
ix = self.temp_levels.index(temp_levels[-1])
part = value / (tl_len - 1) part = value / (tl_len - 1)
for tl in temp_levels[1:]: for tl in temp_levels[1:]:
used.add(tl) used.add(tl)
@ -357,30 +395,41 @@ class Solder(QtCore.QObject):
y.append(tl.temp) y.append(tl.temp)
self.log.append("* Duration connection: TempLevel %r connected to TempLevels %r" % (temp_level.name, [tl.name for tl in temp_levels[1:]])) self.log.append("* Duration connection: TempLevel %r connected to TempLevels %r" % (temp_level.name, [tl.name for tl in temp_levels[1:]]))
return x, y, ix
dx += 1
raise Exception()
return x, y def check_rate_constraints(self, temp_level, used, ix):
def check_rate_constraints(self, temp_level, used):
x = list() x = list()
y = list() y = list()
rx = 0
for temp_levels, value in self.rates: for temp_levels, value in self.rates:
tl_len = len(temp_levels) tl_len = len(temp_levels)
if temp_levels and temp_levels[0] == temp_level and tl_len > 1: print "check rate", rx, temp_level, repr(temp_levels), self.ur
if temp_levels and tl_len > 1 and rx not in self.ur and (temp_levels[0] == temp_level or temp_level.is_between(*temp_levels)):
if temp_level < temp_levels[1] and value < 0:
self.log.append("!RateError: negative rate for increasing temp levels is wrong")
elif temp_level > temp_levels[1] and value > 0:
self.log.append("!RateError: positive rate for decreasing temp levels is wrong")
if temp_level not in used: if temp_level not in used:
used.add(temp_level) used.add(temp_level)
x.append(self.time) x.append(self.time)
y.append(temp_level.temp) y.append(temp_level.temp)
self.ur.add(rx)
print "using rate constraint", rx
self.time += (temp_levels[1].temp - temp_level.temp) / value self.time += (temp_levels[1].temp - temp_level.temp) / value
used.add(temp_levels[1]) used.add(temp_levels[1])
x.append(self.time) x.append(self.time)
y.append(temp_levels[1].temp) y.append(temp_levels[1].temp)
ix = self.temp_levels.index(temp_levels[-1])
self.log.append("* Rate connection: TempLevel %r connected to TempLevels %r" % (temp_level.name, [tl.name for tl in temp_levels[1:]])) self.log.append("* Rate connection: TempLevel %r connected to TempLevels %r" % (temp_level.name, [tl.name for tl in temp_levels[1:]]))
return x, y, ix
return x, y rx += 1
raise Exception()
def calc_profile(self): def calc_profile(self):
print self.calc_profile
self.log = list() self.log = list()
x = list() x = list()
@ -390,18 +439,39 @@ class Solder(QtCore.QObject):
self.time = 0 self.time = 0
used = set() used = set()
unused = list() unused = list()
for temp_level in self.temp_levels: ix = 0
dur_x, dur_y = self.check_duration_constraints(temp_level, used) last = len(self.temp_levels)
rate_x, rate_y = self.check_rate_constraints(temp_level, used) self.ud = set()
self.ur = set()
count = len(self.durations) + len(self.rates)
print "max rounds", count
while 1:
print "while", ix, last, x, y, self.ud, self.ur
temp_level = self.temp_levels[ix]
count -= 1
if len(dur_x) > 0: try:
dur_x, dur_y, dur_new_ix = self.check_duration_constraints(temp_level, used, ix)
ix = dur_new_ix
print "dur_new_ix", dur_new_ix
x.extend(dur_x) x.extend(dur_x)
y.extend(dur_y) y.extend(dur_y)
elif len(rate_x) > 0: except Exception, e:
x.extend(rate_x) print e
y.extend(rate_y) try:
elif temp_level not in used: rate_x, rate_y, rate_new_ix = self.check_rate_constraints(temp_level, used, ix)
unused.append(temp_level) ix = rate_new_ix
print "rate_new_ix", rate_new_ix
x.extend(rate_x)
y.extend(rate_y)
except Exception, e:
print e
ix+=1
#if temp_level not in used:
#unused.append(temp_level)
if (y and y[-1] == y[0]) or count <= 0:
break
self.log.append("") self.log.append("")
map(self.log.append, ["* Missing Connection: %r" % tl.name for tl in unused]) map(self.log.append, ["* Missing Connection: %r" % tl.name for tl in unused])
@ -525,7 +595,7 @@ class SolderListModel(QtCore.QAbstractListModel):
return QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable) return QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable)
def create_solder(self): def create_solder(self):
solder = Solder(None, "new", "") solder = Solder(None, datetime.now().strftime("%Y-%M-%D %H:%m:%s"), "")
tl = solder.add_temp_level("environment temp", getTemperature(), True) tl = solder.add_temp_level("environment temp", getTemperature(), True)
tl.color = QtGui.QColor(0, 0, 0) tl.color = QtGui.QColor(0, 0, 0)
@ -536,6 +606,11 @@ class SolderListModel(QtCore.QAbstractListModel):
def dirname(): def dirname():
return os.path.join(os.path.dirname(__file__), "solder_types") return os.path.join(os.path.dirname(__file__), "solder_types")
def check_name(self, name):
for solder in self.listdata:
if name == solder.name:
return False
return True
class SolderWidget(QtGui.QWidget): class SolderWidget(QtGui.QWidget):
@ -746,8 +821,8 @@ class ConstraintWidget(QtGui.QWidget):
self.spinbox_block = False self.spinbox_block = False
self.constraint_model = ConstraintListModel(self) # constraint selection self.constraint_model = ConstraintListModel(self) # constraint selection
self.all_temp_levels = TempLevelModel(self) # temp_level selection pool self.temp_levels_model = TempLevelModel(self) # temp_level selection pool
self.selected_temp_levels = TempLevelModel(self) # selected temp_levels self.selected_temp_levels_model = TempLevelModel(self) # selected temp_levels
self.controls = AddRemoveValueWidget(self) self.controls = AddRemoveValueWidget(self)
self.constraint_controls = AddRemoveWidget(self, False) self.constraint_controls = AddRemoveWidget(self, False)
@ -761,16 +836,16 @@ class ConstraintWidget(QtGui.QWidget):
self.constraint_view = QtGui.QListView(self) self.constraint_view = QtGui.QListView(self)
self.constraint_view.setModel(self.constraint_model) self.constraint_view.setModel(self.constraint_model)
self.all_temp_levels_view = QtGui.QListView(self) self.temp_levels_view = QtGui.QListView(self)
self.all_temp_levels_view.setModel(self.all_temp_levels) self.temp_levels_view.setModel(self.temp_levels_model)
self.selected_temp_levels_view = QtGui.QListView(self) self.selected_temp_levels_view = QtGui.QListView(self)
self.selected_temp_levels_view.setModel(self.selected_temp_levels) self.selected_temp_levels_view.setModel(self.selected_temp_levels_model)
h = QtGui.QHBoxLayout() h = QtGui.QHBoxLayout()
h.addWidget(self.constraint_view, 1) h.addWidget(self.constraint_view, 1)
h.addWidget(self.constraint_controls, 1) h.addWidget(self.constraint_controls, 1)
h.addWidget(self.all_temp_levels_view, 3) h.addWidget(self.temp_levels_view, 3)
h.addWidget(self.controls, 1) h.addWidget(self.controls, 1)
h.addWidget(self.selected_temp_levels_view, 3) h.addWidget(self.selected_temp_levels_view, 3)
@ -825,9 +900,10 @@ class ConstraintWidget(QtGui.QWidget):
def setData(self, solder): def setData(self, solder):
self.solder = solder self.solder = solder
self.all_temp_levels.setTempLevels(solder.temp_levels) self.temp_levels_model.setTempLevels(solder.temp_levels)
self._set_data(solder) self._set_data(solder)
self.set_controls() self.set_controls()
self.temp_levels_view.setCurrentIndex(self.temp_levels_model.index(0,0))
self.controls.up_button.setEnabled(False) self.controls.up_button.setEnabled(False)
self.controls.down_button.setEnabled(False) self.controls.down_button.setEnabled(False)
@ -868,24 +944,24 @@ class ConstraintWidget(QtGui.QWidget):
raise NotImplementedError() raise NotImplementedError()
def add_temp_level_to_constraint(self): def add_temp_level_to_constraint(self):
src_row = self.all_temp_levels_view.currentIndex().row() src_row = self.temp_levels_view.currentIndex().row()
temp_level = self.all_temp_levels.temp_levels[src_row] temp_level = self.temp_levels_model.temp_levels[src_row]
self.selected_temp_levels.temp_levels.append(temp_level) self.selected_temp_levels_model.temp_levels.append(temp_level)
self.selected_temp_levels.reset() self.selected_temp_levels_model.reset()
self.selected_temp_levels_view.setCurrentIndex(self.selected_temp_levels.index(len(self.selected_temp_levels.temp_levels)-1,0)) self.selected_temp_levels_view.setCurrentIndex(self.selected_temp_levels_model.index(len(self.selected_temp_levels_model.temp_levels)-1,0))
self.solder_changed.emit() self.solder_changed.emit()
def remove_temp_level_from_constraint(self): def remove_temp_level_from_constraint(self):
del self.selected_temp_levels.temp_levels[self.selected_temp_levels_view.currentIndex().row()] del self.selected_temp_levels_model.temp_levels[self.selected_temp_levels_view.currentIndex().row()]
self.selected_temp_levels.reset() self.selected_temp_levels_model.reset()
self.selected_temp_levels_view.clearSelection() self.selected_temp_levels_view.clearSelection()
self.solder_changed.emit() self.solder_changed.emit()
def remove_constraint(self): def remove_constraint(self):
src_row = self.all_temp_levels_view.currentIndex().row() src_row = self.temp_levels_view.currentIndex().row()
del self.constraint_model.constraint_list[src_row] del self.constraint_model.constraint_list[src_row]
self.constraint_model.reset() self.constraint_model.reset()
self.selected_temp_levels.clear() self.selected_temp_levels_model.clear()
self.set_controls() self.set_controls()
self.solder_changed.emit() self.solder_changed.emit()
@ -897,6 +973,10 @@ class ConstraintWidget(QtGui.QWidget):
self.constraint_model.constraint_list[src_index][1] = value self.constraint_model.constraint_list[src_index][1] = value
self.solder_changed.emit() self.solder_changed.emit()
def temp_levels_changed(self):
print self.temp_levels_changed
self.temp_levels_model.reset()
def slot_temp_level_removed(self, temp_level): def slot_temp_level_removed(self, temp_level):
deletes = deque() deletes = deque()
ix = 0 ix = 0
@ -911,14 +991,14 @@ class ConstraintWidget(QtGui.QWidget):
def temp_level_up(self): def temp_level_up(self):
dst_row = self.selected_temp_levels_view.currentIndex().row() dst_row = self.selected_temp_levels_view.currentIndex().row()
self.selected_temp_levels.temp_levels[dst_row - 1], self.selected_temp_levels.temp_levels[dst_row] = self.selected_temp_levels.temp_levels[dst_row], self.selected_temp_levels.temp_levels[dst_row - 1] self.selected_temp_levels_model.temp_levels[dst_row - 1], self.selected_temp_levels_model.temp_levels[dst_row] = self.selected_temp_levels_model.temp_levels[dst_row], self.selected_temp_levels_model.temp_levels[dst_row - 1]
self.selected_temp_levels.reset() self.selected_temp_levels_model.reset()
self.solder_changed.emit() self.solder_changed.emit()
def temp_level_down(self): def temp_level_down(self):
dst_row = self.selected_temp_levels_view.currentIndex().row() dst_row = self.selected_temp_levels_view.currentIndex().row()
self.selected_temp_levels.temp_levels[dst_row], self.selected_temp_levels.temp_levels[dst_row + 1] = self.selected_temp_levels.temp_levels[dst_row + 1], self.selected_temp_levels.temp_levels[dst_row] self.selected_temp_levels_model.temp_levels[dst_row], self.selected_temp_levels_model.temp_levels[dst_row + 1] = self.selected_temp_levels_model.temp_levels[dst_row + 1], self.selected_temp_levels_model.temp_levels[dst_row]
self.selected_temp_levels.reset() self.selected_temp_levels_model.reset()
self.solder_changed.emit() self.solder_changed.emit()
@ -936,11 +1016,11 @@ class DurationConstraintWidget(ConstraintWidget):
if index.isValid(): if index.isValid():
self.spinbox_block = True self.spinbox_block = True
temp_levels, value = self.constraint_model.constraint_list[index.row()] temp_levels, value = self.constraint_model.constraint_list[index.row()]
self.selected_temp_levels.setTempLevels(temp_levels) self.selected_temp_levels_model.setTempLevels(temp_levels)
self.controls.value.setValue(value) self.controls.value.setValue(value)
else: else:
self.spinbox_block = True self.spinbox_block = True
self.selected_temp_levels.setTempLevels(list()) self.selected_temp_levels_model.setTempLevels(list())
self.controls.value.setValue(0) self.controls.value.setValue(0)
@ -959,11 +1039,11 @@ class RateConstraintWidget(ConstraintWidget):
if index.isValid(): if index.isValid():
self.spinbox_block = True self.spinbox_block = True
temp_levels, value = self.constraint_model.constraint_list[index.row()] temp_levels, value = self.constraint_model.constraint_list[index.row()]
self.selected_temp_levels.setTempLevels(temp_levels) self.selected_temp_levels_model.setTempLevels(temp_levels)
self.controls.value.setValue(value) self.controls.value.setValue(value)
else: else:
self.spinbox_block = True self.spinbox_block = True
self.selected_temp_levels.setTempLevels([]) self.selected_temp_levels_model.setTempLevels([])
self.controls.value.setValue(0) self.controls.value.setValue(0)
@ -1034,6 +1114,25 @@ class Report(QtGui.QWidget):
super(Report, self).__init__(parent) super(Report, self).__init__(parent)
self.operator = QtGui.QLineEdit(self)
self.date_begin = QtGui.QDateTimeEdit(self)
self.date_end = QtGui.QDateTimeEdit(self)
self.durations = list()
self.plot_file = ""
layout = QtGui.QGridLayout(self)
layout.addWidget(QtGui.QLabel("operator"), 0, 0)
layout.addWidget(QtGui.QLabel("date begin"), 1, 0)
layout.addWidget(QtGui.QLabel("date end"), 2, 0)
layout.addWidget(self.operator, 0, 1)
layout.addWidget(self.date_begin, 1, 1)
layout.addWidget(self.date_end, 2, 1)
def export_pdf(self):
pass
class ApplicationWindow(QtGui.QMainWindow): class ApplicationWindow(QtGui.QMainWindow):
def __init__(self): def __init__(self):
QtGui.QMainWindow.__init__(self) QtGui.QMainWindow.__init__(self)
@ -1053,6 +1152,8 @@ class ApplicationWindow(QtGui.QMainWindow):
QtCore.Qt.CTRL + QtCore.Qt.Key_D) QtCore.Qt.CTRL + QtCore.Qt.Key_D)
self.file_menu.addAction('S&ave plot', self.save_plot, self.file_menu.addAction('S&ave plot', self.save_plot,
QtCore.Qt.CTRL + QtCore.Qt.Key_A) QtCore.Qt.CTRL + QtCore.Qt.Key_A)
self.file_menu.addAction('&Quit', self.show_report,
QtCore.Qt.CTRL + QtCore.Qt.Key_T)
self.file_menu.addAction('&Quit', self.fileQuit, self.file_menu.addAction('&Quit', self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q) QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
@ -1074,6 +1175,10 @@ class ApplicationWindow(QtGui.QMainWindow):
self.profile_view_action.setCheckable(True) self.profile_view_action.setCheckable(True)
self.controls_view_action.setCheckable(True) self.controls_view_action.setCheckable(True)
self.report = Report(self)
self.report.hide()
#self.connect(self.profile_view_action, #self.connect(self.profile_view_action,
#QtCore.SIGNAL("triggered()"), #QtCore.SIGNAL("triggered()"),
#self.open_profile_view) #self.open_profile_view)
@ -1169,6 +1274,9 @@ class ApplicationWindow(QtGui.QMainWindow):
self.temp_level_widget.temp_level_removed.connect(self.duration_widget.slot_temp_level_removed) self.temp_level_widget.temp_level_removed.connect(self.duration_widget.slot_temp_level_removed)
self.temp_level_widget.temp_level_removed.connect(self.rate_widget.slot_temp_level_removed) self.temp_level_widget.temp_level_removed.connect(self.rate_widget.slot_temp_level_removed)
self.temp_level_widget.temp_levels_changed.connect(self.duration_widget.temp_levels_changed)
self.temp_level_widget.temp_levels_changed.connect(self.rate_widget.temp_levels_changed)
def getPlotter(self): def getPlotter(self):
return self.plotter return self.plotter
@ -1204,6 +1312,9 @@ class ApplicationWindow(QtGui.QMainWindow):
self.controls_widget.hide() self.controls_widget.hide()
self.settings_widget.show() self.settings_widget.show()
def show_report(self):
self.report.exec()
def save_plot(self): def save_plot(self):
file_choices = "PNG (*.png)|*.png" file_choices = "PNG (*.png)|*.png"
@ -1212,6 +1323,7 @@ class ApplicationWindow(QtGui.QMainWindow):
def save_solder(self): def save_solder(self):
self.plotter.solder.save() self.plotter.solder.save()
self.solder_widget.solder_model.listdata.sort(key=lambda x: x.name)
self.solder_widget.solder_model.reset() self.solder_widget.solder_model.reset()
new_index = self.solder_widget.solder_model.index(self.solder_widget.solder_model.listdata.index(self.plotter.solder)) new_index = self.solder_widget.solder_model.index(self.solder_widget.solder_model.listdata.index(self.plotter.solder))
self.solder_widget.solder_view.setCurrentIndex(new_index) self.solder_widget.solder_view.setCurrentIndex(new_index)
@ -1252,5 +1364,10 @@ def main():
sys.exit(qApp.exec_()) sys.exit(qApp.exec_())
if __name__ == '__main__': #if __name__ == '__main__':
main() #main()
tls = [TempLevel('peak', 260), TempLevel('environment temp', 20.0)]
a = TempLevel('tal', 200)
print a.is_between(*tls)

View File

@ -1,34 +1,2 @@
<xml> <?xml version='1.0' encoding='UTF-8'?>
<solder_type name="leadfree noclean" description=""> <xml><solder_type description="" name="leadfree noclean"><state name="environment temp" temperature="$ENV" /><state name="preheat start" temperature="130" /><state name="preheat end" temperature="185" /><state name="tal" temperature="220" /><state name="peak" temperature="250" /><duration value="100"><state name="preheat start" /><state name="preheat end" /></duration><duration value="100"><state name="tal" /><state name="peak" /><state name="tal" /></duration><rate value="1"><state name="environment temp" /><state name="preheat start" /></rate><rate value="1"><state name="preheat start" /><state name="preheat end" /></rate><rate value="1"><state name="preheat end" /><state name="tal" /></rate><rate value="-2"><state name="tal" /><state name="environment temp" /></rate></solder_type></xml>
<state name="environment temp" temperature="$ENV" />
<state name="preheat start" temperature="130" />
<state name="preheat end" temperature="185" />
<state name="tal" temperature="220" />
<state name="peak" temperature="250" />
<duration value="100" >
<state name="preheat start" />
<state name="preheat end" />
</duration>
<duration value="100">
<state name="tal" />
<state name="peak" />
<state name="tal" />
</duration>
<rate value="1">
<state name="environment temp" />
<state name="preheat start" />
</rate>
<rate value="1">
<state name="preheat start" />
<state name="preheat end" />
</rate>
<rate value="1">
<state name="preheat end" />
<state name="tal" />
</rate>
<rate value="-2">
<state name="peak" />
<state name="environment temp" />
</rate>
</solder_type>
</xml>