diff --git a/bin/test_property.py b/bin/test_property.py
index 18d148c245c1c6a356a83355cbbfb535943ba1c9..04f8fa03665acc44ad290a9bb12dacfb834941ca 100644
--- a/bin/test_property.py
+++ b/bin/test_property.py
@@ -1,36 +1,143 @@
-class Param(float):
-    def __new__(self,name,value):
-        return float.__new__(self,value)
-         
-    def __init__(self,name,value):
-        self.__name = name
+import abc
+import pykat.exceptions as pkex
+
+class puttable(object):
+    """
+    Objects that inherit this should be able to have something `put` to it.
+    Essentially this means you could write Finesse commands like
+    
+    put this parameter value
+    """
+    __metaclass__ = abc.ABCMeta
+    
+    def __init__(self, component_name, parameter_name):
+        self._parameter_name = parameter_name
+        self._component_name = component_name
+        self._putter = None
+    
+    def put(self, var):
+        if not isinstance(var, putter):
+            raise pkex.BasePyKatException("var was not something that can be `put` as a value")
+        
+        if self._putter != None:
+            self._putter.put_count -= 1
+        
+        self._putter = var
+        self._putter.put_count += 1
         
-    name = property(lambda self: self.__name)
+    def getPutFinesseText(self):
+        rtn = []
+        # if something is being put to this 
+        if self._putter != None:
+            rtn.append("put {comp} {param} ${value}".format(comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
+        
+        return rtn
+            
+class putter(object):
+    """
+    If an object can be put to something that is puttable it should inherit this
+    object.
+    """
+    __metaclass__ = abc.ABCMeta
     
+    def __init__(self, put_name):
+        self._put_name = put_name
+        self.put_count = 0
+        
+    def put_name(self): return self._put_name
     
-class Beer(object):
-    def __init__(self, temp):
-        self.__T = temp
+        
+class Param(puttable, putter):         
+    def __init__(self, name, owner, value):
+        self._name = name
+        self._owner = owner
+        self._value = value
+        
+        putter.__init__(self,"var_{0}_{1}".format(owner.name, name))
+        puttable.__init__(self, owner.name, name)
         
     @property
-    def temp(self):
-        return Param('Beer Temperature', self.__T)
+    def name(self): return self._name
     
-    @temp.setter
-    def temp(self,value):
-        self.__T = float(value) 
+    @property
+    def value(self): return self._value
+    @value.setter
+    def value(self, value):
+        self._value = value
+    
+    def __float__(self): return self.value
         
+    def getFinesseText(self):
+        rtn = []
+        rtn.extend(self.getPutFinesseText())
+        
+        # if this parameter is being put somewhere then we need to
+        # set it as a variable
+        if self.put_count > 0:
+            rtn.append("set {put_name} {comp} {param}".format(put_name=self.put_name(), comp=self._owner.name, param=self.name))
+        
+        return rtn
+        
+    def __mul__(self, a):
+        return float(self) * a
+    
+    def __imul__(self, a):
+        return self.value * float(a)
+        
+    __rmul__ = __mul__
+    
+    def __add__(self, a):
+        return self.value + flota(a)
+    
+    def __iadd__(self, a):
+        return self.value + float(a)
+        
+    __radd__ = __add__
+    
+    def __sub__(self, a):
+        return self.value - float(a)
+    
+    def __isub__(self, a):
+        return self.value - float(a)
+        
+    __rsub__ = __sub__
+    
+    def __div__(self, a):
+        return self.value / float(a)
+    
+    def __idiv__(self, a):
+        return self.value / complex(a)
+        
+    def __pow__(self, q):
+        return  self.value**q
 
-b = Beer(100)
-
-print b.temp.name, b.temp.__class__
-
-print b.temp * 4.5
-
-print b.temp.name, b.temp.__class__
+    def __neg__(self):
+        return -self.value
+        
+    def __eq__(self, q):
+        return float(q) == self.value
+        
+class Beer(object):
+    def __init__(self, temp, name):
+        
+        self._name = name
+        
+        self._T = Param('T', self, temp)
+    
+    @property
+    def name(self): return self._name
+        
+    @property
+    def T(self): return self._T
+    
+    @T.setter
+    def T(self,value): self._T.value = float(value) 
+        
 
-b.temp = 101
+b = Beer(1,"b")
+c = Beer(2,"c")
 
-print b.temp.name, b.temp.__class__
+c.T.put(b.T)
 
-print b.temp 
\ No newline at end of file
+print c.T.getFinesseText()
+print b.T.getFinesseText()
\ No newline at end of file
diff --git a/bin/test_put.py b/bin/test_put.py
new file mode 100644
index 0000000000000000000000000000000000000000..41155e42ee9d2c3d14016783c1c13e7ca3b68e42
--- /dev/null
+++ b/bin/test_put.py
@@ -0,0 +1,31 @@
+from pykat import finesse
+from pykat.detectors import *
+from pykat.components import *
+from pykat.commands import *
+from pykat.structs import *
+
+import numpy as np
+import pylab as pl
+
+code = """
+l l1 1 0 0 n1
+s s1 10 1 n1 n2
+mod eom 10 0.1 1 am 0 n2 n3
+"""
+
+kat = finesse.kat()
+
+kat.parseCommands(code)
+
+kat.add(photodiode('pd_ref','n3', num_demods=1, demods=[10,0]))
+
+kat.add(xaxis("lin", [0, 1000], "pd_ref", "f1", 100))
+
+out = kat.run(printout=0, printerr=0)
+
+pl.figure()
+pl.plot(out.x, out["pd_ref"])
+pl.xlabel(out.xlabel)
+pl.ylabel("Intensity [W]")
+pl.legend(out.ylabels)
+pl.show()
diff --git a/pykat/commands.py b/pykat/commands.py
index a0d63977d38d69d7ba3c86eab4f0ab7835bcb7b2..19fe6606425802bd21c89450a825b5c9e2b48602 100644
--- a/pykat/commands.py
+++ b/pykat/commands.py
@@ -9,6 +9,7 @@ from numpy import min,max
 import exceptions
 from components import *
 from structs import *
+from pykat.param import Param, putter
 
 class Command(object):
     def __init__(self):
@@ -46,40 +47,15 @@ class gauss(object):
         
         if not values[0].startswith("gauss"):
             raise exceptions.RuntimeError("'{0}' not a valid Finesse gauss command".format(text))
-        
-        
-        
-class attr():
-    @staticmethod
-    def parseFinesseText(text, kat):  
-        values = text.split(" ")
-        
-        if values[0] != "attr":
-            raise exceptions.RuntimeError("'{0}' not a valid Finesse attr command".format(text))
-
-        values.pop(0) # remove initial value
-        
-        if len(values) < 3:
-            raise exceptions.RuntimeError("attr Finesse code format incorrect '{0}'".format(text))
-        
-        comp = None
-        comp_name = values[0]
-        values.pop(0)
-        
-        for c in kat.getComponents():
-            if c.name == comp_name:
-                comp = c
-                break
-        
-        if comp == None:
-            raise 
-        # can list multiple attributes per command
        
 class xaxis(Command):
     
     def __init__(self, scale, limits, comp, param, steps, axis_type="xaxis"):
         self._axis_type = axis_type
         
+        self.x = putter("x1")
+        self.mx = putter("mx1")
+        
         if scale == "lin":
             scale = Scale.linear
         elif scale == "log":
@@ -146,6 +122,8 @@ class xaxis(Command):
 class x2axis(xaxis):
     def __init__(self, scale, limits, comp, param, steps):
         xaxis.__init__(self, scale, limits, comp, param, steps, axis_type="x2axis")        
+        self.x = putter("x2")
+        self.mx = putter("mx2")
 
     @staticmethod
     def parseFinesseText(text):
diff --git a/pykat/components.py b/pykat/components.py
index 25ab3134b9efce4b94a42a395c8b102bee55ed30..73948105755f4e25f8fd966e765d5f5d08fb62ed 100644
--- a/pykat/components.py
+++ b/pykat/components.py
@@ -15,6 +15,7 @@ import pykat.gui.resources
 import pykat.gui.graphics
 from pykat.gui.graphics import *
 from pykat.SIfloat import *
+from pykat.param import Param, AttrParam
 
 next_component_id = 1
 
@@ -58,6 +59,7 @@ class Component(object):
         self._requested_node_names = []
         self._kat = None
         self.tag = None
+        self._params = []
         
         # store a unique ID for this component
         global next_component_id
@@ -69,7 +71,10 @@ class Component(object):
         # all classes
         cls = type(self)
         self.__class__ = type(cls.__name__, (cls,), {})
-            
+    
+    def _register_param(self, param):
+        self._params.append(param)
+        
     def _on_kat_add(self, kat):
         """
         Called when this component has been added to a kat object.
@@ -145,87 +150,66 @@ class Component(object):
     
     def __str__(self): return self.name
     
-class Param(float):
-    def __new__(self,name,value):
-        return float.__new__(self,SIfloat(value))
-         
-    def __init__(self,name,value):
-        self.__name = name
-        
-    name = property(lambda self: self.__name)
-
 class AbstractMirrorComponent(Component):
     __metaclass__ = abc.ABCMeta
     
     def __init__(self, name, R=0, T=0, phi=0, Rcx=0, Rcy=0, xbeta=0, ybeta=0, mass=0, r_ap=0):
         super(AbstractMirrorComponent, self).__init__(name)
 
-        self.__R = SIfloat(R)
-        self.__T = SIfloat(T)
-        self.__phi = SIfloat(phi)
-        self.__Rcx = SIfloat(Rcx)
-        self.__Rcy = SIfloat(Rcy)
-        self.__xbeta = SIfloat(xbeta)
-        self.__ybeta = SIfloat(ybeta)
-        self.__mass = SIfloat(mass)
-        self.__r_ap = SIfloat(r_ap)
-
-    def getAttributeText(self):
-        rtn = []
-        
-        if self.Rcx != 0: rtn.append("attr {0} Rcx {1}".format(self.name,self.__Rcx))
-        if self.Rcy != 0: rtn.append("attr {0} Rcy {1}".format(self.name,self.__Rcy))
-        if self.xbeta != 0: rtn.append("attr {0} xbeta {1}".format(self.name,self.__xbeta))
-        if self.ybeta != 0: rtn.append("attr {0} ybeta {1}".format(self.name,self.__ybeta))
-        if self.mass != 0: rtn.append("attr {0} mass {1}".format(self.name,self.__mass))
-        if self.r_ap != 0: rtn.append("attr {0} r_ap {1}".format(self.name,self.__r_ap))
-        
-        return rtn
+        self.__R = Param("R", self, SIfloat(R))
+        self.__T = Param("T", self, SIfloat(T))
+        self.__phi = Param("phi", self, SIfloat(phi))
+        self.__Rcx = AttrParam("Rcx", self, SIfloat(Rcx))
+        self.__Rcy = AttrParam("Rcy", self, SIfloat(Rcy))
+        self.__xbeta = AttrParam("xbeta", self, SIfloat(xbeta))
+        self.__ybeta = AttrParam("ybeta", self, SIfloat(ybeta))
+        self.__mass = AttrParam("mass", self, SIfloat(mass))
+        self.__r_ap = AttrParam("r_ap", self, SIfloat(r_ap))
         
     @property
-    def r_ap(self): return Param('r_ap', self.__r_ap)
+    def r_ap(self): return self.__r_ap
     @r_ap.setter
-    def r_ap(self,value): self.__aperture = SIfloat(value)
+    def r_ap(self,value): self.__r_ap.value = SIfloat(value)
 
     @property
-    def mass(self): return Param('mass', self.__mass)
+    def mass(self): return self.__mass
     @mass.setter
-    def mass(self,value): self.__mass = SIfloat(value)
+    def mass(self,value): self.__mass.value = SIfloat(value)
     
     @property
-    def R(self): return Param('R', self.__R)
+    def R(self): return self.__R
     @R.setter
-    def R(self,value): self.__R = SIfloat(value)
+    def R(self,value): self.__R.value = SIfloat(value)
     
     @property
-    def T(self): return Param('T', self.__T)
+    def T(self): return self.__T
     @T.setter
-    def T(self,value): self.__T = SIfloat(value)
+    def T(self,value): self.__T.value = SIfloat(value)
         
     @property
-    def phi(self): return Param('phi', self.__phi)
+    def phi(self): return self.__phi
     @phi.setter
-    def phi(self,value): self.__phi = SIfloat(value)
+    def phi(self,value): self.__phi.value = SIfloat(value)
     
     @property
-    def Rcx(self): return Param('Rcx', self.__Rcx)
+    def Rcx(self): return self.__Rcx
     @Rcx.setter
-    def Rcx(self,value): self.__Rcx = SIfloat(value)
+    def Rcx(self,value): self.__Rcx.value = SIfloat(value)
     
     @property
-    def Rcy(self): return Param('Rcy', self.__Rcy)
+    def Rcy(self): return self.__Rcy
     @Rcy.setter
-    def Rcy(self,value): self.__Rcy = SIfloat(value)
+    def Rcy(self,value): self.__Rcy.value = SIfloat(value)
     
     @property
-    def xbeta(self): return Param('xbeta', self.__xbeta)
+    def xbeta(self): return self.__xbeta
     @xbeta.setter
-    def xbeta(self,value): self.__xbeta = SIfloat(value)
+    def xbeta(self,value): self.__xbeta.value = SIfloat(value)
     
     @property
-    def ybeta(self): return Param('ybeta', self.__ybeta)
+    def ybeta(self): return self.__ybeta
     @ybeta.setter
-    def ybeta(self,value): self.__ybeta = SIfloat(value)
+    def ybeta(self,value): self.__ybeta.value = SIfloat(value)
     
     @property
     def Rc(self):
@@ -236,8 +220,8 @@ class AbstractMirrorComponent(Component):
     
     @Rc.setter
     def Rc(self,value):
-        self.Rcx = SIfloat(value)
-        self.Rcy = SIfloat(value)
+        self.Rcx.value = SIfloat(value)
+        self.Rcy.value = SIfloat(value)
 
 class mirror(AbstractMirrorComponent):
     def __init__(self,name,node1,node2,R=0,T=0,phi=0,Rcx=0,Rcy=0,xbeta=0,ybeta=0,mass=0, r_ap=0):
@@ -271,11 +255,12 @@ class mirror(AbstractMirrorComponent):
         rtn = []
             
         rtn.append('m {0} {1} {2} {3} {4} {5}'.format(
-                self.name, self.R, self.T, self.phi,
+                self.name, self.R.value, self.T.value, self.phi.value,
                 self.nodes[0].name, self.nodes[1].name))
 
-        rtn.extend(super(mirror, self).getAttributeText())
-        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+                    
         return rtn
         
     def getQGraphicsItem(self):
@@ -293,12 +278,12 @@ class beamSplitter(AbstractMirrorComponent):
         self._requested_node_names.append(node3)
         self._requested_node_names.append(node4)
              
-        self.__alpha = SIfloat(alpha)
+        self.__alpha = AttrParam("alpha", self, SIfloat(alpha))
     
     @property
-    def alpha(self): return Param('alpha', self.__alpha)
+    def alpha(self): return self.__alpha
     @alpha.setter
-    def alpha(self,value): self.__alpha = SIfloat(value)
+    def alpha(self,value): self.__alpha.value = SIfloat(value)
     
     @staticmethod
     def parseFinesseText(text):
@@ -325,13 +310,14 @@ class beamSplitter(AbstractMirrorComponent):
         rtn = []
             
         rtn.append('bs {0} {1} {2} {3} {4} {5} {6} {7} {8}'.format(
-                self.name, self.R, self.T, self.phi,
-                self.alpha, self.nodes[0].name,
+                self.name, self.R.value, self.T.value, self.phi.value,
+                self.alpha.value, self.nodes[0].name,
                 self.nodes[1].name, self.nodes[2].name,
                 self.nodes[3].name))
 
-        rtn.extend(super(beamSplitter, self).getAttributeText())
-        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+            
         return rtn
         
     def getQGraphicsItem(self):
@@ -348,17 +334,17 @@ class space(Component):
         self._requested_node_names.append(node1)
         self._requested_node_names.append(node2)
         self._QItem = None
-        self.__L = SIfloat(L)
-        self.__n = SIfloat(n)
+        self.__L = Param("L", self, SIfloat(L))
+        self.__n = Param("n", self, SIfloat(n))
         
     @property
-    def L(self): return Param('L', self.__L)
+    def L(self): return self.__L
     @L.setter
-    def L(self,value): self.__L = SIfloat(value)
+    def L(self,value): self.__L,value = SIfloat(value)
     @property
-    def n(self): return Param('n', self.__n)
+    def n(self): return self.__n
     @n.setter
-    def n(self,value): self.__n = SIfloat(value)
+    def n(self,value): self.__n.value = SIfloat(value)
     
     @staticmethod
     def parseFinesseText(text):
@@ -377,11 +363,18 @@ class space(Component):
             raise exceptions.RuntimeError("Space Finesse code format incorrect '{0}'".format(text))
         
     def getFinesseText(self):
+        rtn = []
+        
         if self.__n == 1:
-            return 's {0} {1} {2} {3}'.format(self.name, self.__L, self.nodes[0].name, self.nodes[1].name)            
+            rtn.append('s {0} {1} {2} {3}'.format(self.name, self.__L.value, self.nodes[0].name, self.nodes[1].name))
         else:
-            return 's {0} {1} {2} {3} {4}'.format(self.name, self.__L, self.__n, self.nodes[0].name, self.nodes[1].name)            
+            rtn.append('s {0} {1} {2} {3} {4}'.format(self.name, self.__L.value, self.__n.value, self.nodes[0].name, self.nodes[1].name))
        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+            
+        return rtn
+        
     def getQGraphicsItem(self):
         if self._QItem == None:
             self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self)
@@ -411,13 +404,13 @@ class grating(Component):
             raise exceptions.RuntimeError("Grating must have between 2 and 4 ports")
         
         self.__n = n
-        self.__d = SIfloat(d)
-        self.__eta_0 = SIfloat(eta_0)
-        self.__eta_1 = SIfloat(eta_1)
-        self.__eta_2 = SIfloat(eta_2)
-        self.__eta_3 = SIfloat(eta_3)
-        self.__rho_0 = SIfloat(rho_0)
-        self.__alpha = SIfloat(alpha)
+        self.__d = Param("d", self, SIfloat(d))
+        self.__eta_0 = AttrParam("eta_0", self, SIfloat(eta_0))
+        self.__eta_1 = AttrParam("eta_1", self, SIfloat(eta_1))
+        self.__eta_2 = AttrParam("eta_2", self, SIfloat(eta_2))
+        self.__eta_3 = AttrParam("eta_3", self, SIfloat(eta_3))
+        self.__rho_0 = AttrParam("rho_0", self, SIfloat(rho_0))
+        self.__alpha = AttrParam("alpha", self, SIfloat(alpha))
     
     @property
     def n(self): return Param('n', self.__n)
@@ -429,39 +422,39 @@ class grating(Component):
             self.__n = value
     
     @property
-    def d(self): return Param('d', self.__d)
+    def d(self): return self.__d
     @d.setter
-    def d(self, value): self.__d = SIfloat(value)
+    def d(self, value): self.__d.value = SIfloat(value)
     
     @property
-    def eta_0(self): return Param('eta_0', self.__eta_0)
+    def eta_0(self): return self.__eta_0
     @eta_0.setter
-    def eta_0(self, value): self.__eta_0 = SIfloat(value)
+    def eta_0(self, value): self.__eta_0.value = SIfloat(value)
     
     @property
-    def eta_1(self): return Param('eta_1', self.__eta_1)
+    def eta_1(self): return self.__eta_1
     @eta_1.setter
-    def eta_1(self, value): self.__eta_1 = SIfloat(value)
+    def eta_1(self, value): self.__eta_1.value = SIfloat(value)
     
     @property
-    def eta_2(self): return Param('eta_2', self.__eta_2)
+    def eta_2(self): return self.__eta_2
     @eta_2.setter
-    def eta_2(self, value): self.__eta_2 = SIfloat(value)
+    def eta_2(self, value): self.__eta_2.value = SIfloat(value)
     
     @property
-    def eta_3(self): return Param('eta_3', self.__eta_3)
+    def eta_3(self): return self.__eta_3
     @eta_3.setter
-    def eta_3(self, value): self.__eta_3 = SIfloat(value)
+    def eta_3(self, value): self.__eta_3.value = SIfloat(value)
     
     @property
-    def rho_0(self): return Param('rho_0', self.__rho_0)
+    def rho_0(self): return self.__rho_0
     @rho_0.setter
-    def rho_0(self, value): self.__rho_0 = SIfloat(value)
+    def rho_0(self, value): self.__rho_0.value = SIfloat(value)
     
     @property
-    def alpha(self): return Param('alpha', self.__alpha)
+    def alpha(self): return self.__alpha
     @alpha.setter
-    def alpha(self, value): self.__alpha = SIfloat(value)
+    def alpha(self, value): self.__alpha.value = SIfloat(value)
     
     @staticmethod
     def parseFinesseText(text):
@@ -500,19 +493,14 @@ class grating(Component):
         rtn = []
         
         if self.__n == 2:
-            rtn.append('gr{0} {1} {2} {3} {4}'.format(self.__n, self.name, self.__d, self.nodes[0].name, self.nodes[1].name))
+            rtn.append('gr{0} {1} {2} {3} {4}'.format(self.__n, self.name, self.__d.value, self.nodes[0].name, self.nodes[1].name))
         elif self.__n == 3:
-            rtn.append('gr{0} {1} {2} {3} {4} {5}'.format(self.__n, self.name, self.__d, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name))
+            rtn.append('gr{0} {1} {2} {3} {4} {5}'.format(self.__n, self.name, self.__d.value, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name))
         else:
-            rtn.append('gr{0} {1} {2} {3} {4} {5} {6}'.format(self.__n, self.name, self.__d, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name, self.nodes[3].name))
+            rtn.append('gr{0} {1} {2} {3} {4} {5} {6}'.format(self.__n, self.name, self.__d.value, self.nodes[0].name, self.nodes[1].name, self.nodes[2].name, self.nodes[3].name))
         
-        if self.eta_0 != 0: rtn.append("attr {0} eta_0 {1}".format(self.name,self.__eta_0))
-        if self.eta_1 != 0: rtn.append("attr {0} eta_1 {1}".format(self.name,self.__eta_1))
-        if self.eta_2 != 0: rtn.append("attr {0} eta_2 {1}".format(self.name,self.__eta_2))
-        if self.eta_3 != 0: rtn.append("attr {0} eta_3 {1}".format(self.name,self.__eta_3))
-        if self.rho_0 != 0: rtn.append("attr {0} rho_0 {1}".format(self.name,self.__rho_0))
-        if self.alpha != 0: rtn.append("attr {0} alpha {1}".format(self.name,self.__alpha))
-        # TODO: implement Rcx, Rcy, Rc
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
         
         return rtn
        
@@ -529,12 +517,12 @@ class isolator(Component):
         self._requested_node_names.append(node1)
         self._requested_node_names.append(node2)
         
-        self.__S = SIfloat(S)
+        self.__S = Param("S",self,SIfloat(S))
         
     @property
-    def S(self): return Param('S', self.__S)
+    def S(self): return self.__S
     @S.setter
-    def S(self, value): self.__S = SIfloat(value)
+    def S(self, value): self.__S.value = SIfloat(value)
     
     @staticmethod
     def parseFinesseText(text):
@@ -551,7 +539,12 @@ class isolator(Component):
             raise exceptions.RuntimeError("Isolator Finesse code format incorrect '{0}'".format(text))
         
     def getFinesseText(self):
-        return 'isol {0} {1} {2} {3}'.format(self.name, self.S, self.nodes[0].name, self.nodes[1].name)            
+        rtn = ['isol {0} {1} {2} {3}'.format(self.name, self.S.value, self.nodes[0].name, self.nodes[1].name)]
+        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+            
+        return rtn
 
     def getQGraphicsItem(self):
         if self._QItem == None:
@@ -566,12 +559,12 @@ class lens(Component):
         self._requested_node_names.append(node1)
         self._requested_node_names.append(node2)
         
-        self.__f = SIfloat(f)
+        self.__f = Param("f", self, SIfloat(f))
         
     @property
-    def f(self): return Param('f', self.__f)
+    def f(self): return self.__f
     @f.setter
-    def f(self, value): self.__f = SIfloat(value)
+    def f(self, value): self.__f.value = SIfloat(value)
     
     @staticmethod
     def parseFinesseText(text):
@@ -588,38 +581,121 @@ class lens(Component):
             raise exceptions.RuntimeError("Lens Finesse code format incorrect '{0}'".format(text))
         
     def getFinesseText(self):
-        return 'lens {0} {1} {2} {3}'.format(self.name, self.f, self.nodes[0].name, self.nodes[1].name)            
-
+        rtn = ['lens {0} {1} {2} {3}'.format(self.name, self.f.value, self.nodes[0].name, self.nodes[1].name)]
+        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+            
+        return rtn
+        
     def getQGraphicsItem(self):
         if self._QItem == None:
             self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make lens graphic
         
         return self._QItem
+        
+class modulator(Component):
+    def __init__(self, name, f, midx, order, modulation_type, node1, node2, phase=0):
+        Component.__init__(self, name)
+        
+        self._requested_node_names.append(node1)
+        self._requested_node_names.append(node2)
+        
+        self.__f = Param("f", self, SIfloat(f))
+        self.__midx = Param("midx", self, SIfloat(midx))
+        self.__phase = Param("phase", self, SIfloat(phase))
+        self.__order = order
+        self.type = modulation_type
+        
+            
+    @property 
+    def f(self): return self.__f
+    @f.setter
+    def f(self, value): self.__f.value = SIfloat(value)
+    
+    @property 
+    def midx(self): return self.__midx
+    @midx.setter
+    def midx(self, value): self.__midx.value = SIfloat(value)
+    
+    @property 
+    def phase(self): return self.__phase
+    @phase.setter
+    def phase(self, value): self.__phase.value = SIfloat(value)
+    
+    @property 
+    def order(self): return self.__order
+    @order.setter
+    def order(self, value):
+        if order <= 1 and order > 6:
+            raise pkex.BasePyKatException("modulator order must be between 1 and 6")
+            
+        self.__order = int(value)
+    
+    @property 
+    def type(self): return self.__type
+    @type.setter
+    def type(self, value):
+        if value != "am" and value != "pm":
+            raise pkex.BasePyKatException("Modulator type must be am (amplitude modulation) or pm (phase modulation)")
+            
+        self.__type = str(value)
     
+    @staticmethod
+    def parseFinesseText(text):
+        v = text.split(" ")
+
+        if v[0] != "mod":
+            raise exceptions.RuntimeError("'{0}' not a valid Finesse modulator command".format(text))
+
+        v.pop(0) # remove initial value
+        
+        if len(v) == 7:
+            return modulator(v[0], v[1], v[2], v[3], v[4], v[5], v[6])
+        if len(v) == 8:
+            return modulator(v[0], v[1], v[2], v[3], v[4], v[6], v[7], phase=v[5])
+        else:
+            raise pkex.BasePyKatException("Modulator Finesse code format incorrect '{0}'".format(text))
+        
+    def getFinesseText(self):
+        rtn = ['mod {0} {1} {2} {3} {4} {5} {6} {7}'.format(self.name, self.f, self.midx, self.order, self.type, self.phase, self.nodes[0].name, self.nodes[1].name)]
+        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+            
+        return rtn
+        
+    def getQGraphicsItem(self):
+        if self._QItem == None:
+            self._QItem = pykat.gui.graphics.SpaceQGraphicsItem(self) # TODO: make lens graphic
+        
+        return self._QItem
+
 class laser(Component):
     def __init__(self,name,node,P=1,f_offset=0,phase=0):
         Component.__init__(self,name)
         
         self._requested_node_names.append(node)
         
-        self.__power = float(P)
-        self.__f_offset = float(f_offset)
-        self.__phase = float(phase)
+        self.__power = Param("P", self, SIfloat(P))
+        self.__f_offset = Param("f", self, SIfloat(f_offset))
+        self.__phase = Param("phase", self, SIfloat(phase))
+        self.__noise = AttrParam("noise", self, 0)
         
     @property
-    def power(self): return Param('P', self.__power)
+    def power(self): return self.__power
     @power.setter
-    def power(self,value): self.__power = float(value)
+    def power(self,value): self.__power.value = float(value)
     
     @property
-    def f_offset(self): return Param('f', self.__f_offset)
-    @f_offset.setter
-    def f_offset(self,value): self.__f_offset = float(value)
+    def f(self): return self.__f_offset
+    @f.setter
+    def f(self,value): self.__f_offset.value = float(value)
     
     @property
-    def phase(self): return Param('phase', self.__phase)
+    def phase(self): return self.__phase
     @phase.setter
-    def phase(self,value): self.__phase = float(value)
+    def phase(self,value): self.__phase.value = float(value)
     
     @staticmethod
     def parseFinesseText(text):
@@ -638,7 +714,12 @@ class laser(Component):
             raise exceptions.FinesseParse("Laser Finesse code format incorrect '{0}'".format(text))
     
     def getFinesseText(self):
-        return 'l {0} {1} {2} {3} {4}'.format(self.name, self.__power, self.__f_offset, self.__phase, self.nodes[0].name)            
+        rtn = ['l {0} {1} {2} {3} {4}'.format(self.name, self.__power.value, self.__f_offset.value, self.__phase.value, self.nodes[0].name)]
+        
+        for p in self._params:
+            rtn.extend(p.getFinesseText())
+        
+        return rtn
          
     def getQGraphicsItem(self):
         if self._svgItem == None:
diff --git a/pykat/detectors.py b/pykat/detectors.py
index 1f0384c2f343eb7b0700405494a61e4950ba9079..ffe3076be50915d0550ec0413fe1aea3d8618476 100644
--- a/pykat/detectors.py
+++ b/pykat/detectors.py
@@ -56,14 +56,6 @@ class photodiode(Detector):
             if values==None:
                 values = []
             list.__init__(self,[SIfloat(value) for value in values])
-
-        """    
-        def __setitem__(self, key, value):
-            list.__setitem__(self,key, SIfloat(value))
-
-        def append(self, value):
-            list.append(self,SIfloat(value))
-        """    
             
     class __Phi(list):
         def __convertValue(self, value):
@@ -82,20 +74,12 @@ class photodiode(Detector):
                 return list.__getitem__(self,key)
             else:
                 return float(list.__getitem__(self,key))
-        """    
-        def __setitem__(self,key,value):
-            list.__setitem__(self,key, self.__convertValue(value))
-
-        def append(self, value):
-            list.append(self,self.__convertValue(value))
-        """
             
     @property
     def f(self): return self.__f
 
     @property
     def phi(self): return self.__phi
-
         
     def __init__(self, name, node, senstype="", num_demods=0, demods=[]):        
         Detector.__init__(self, name, node)
@@ -109,10 +93,6 @@ class photodiode(Detector):
         
         # Every second element into phi (starting at 2)
         self.__phi = self.__Phi(demods[1::2])
-        """
-        for i in demods[1::2]:
-            self.__phi.append(i)        
-        """
         
     @staticmethod
     def parseFinesseText(text): 
diff --git a/pykat/exceptions.py b/pykat/exceptions.py
index a52c1c1fae7af6edf7d0d06b791ef8144c716099..2e3d0168e5687ba489f91316cb0124af6fee9e12 100644
--- a/pykat/exceptions.py
+++ b/pykat/exceptions.py
@@ -1,6 +1,5 @@
 import exceptions
 
-
 class BasePyKatException(Exception):
     def __init__(self, msg):
         self.__msg = msg
diff --git a/pykat/finesse.py b/pykat/finesse.py
index 1a2d53dbd40365fb4547c3ff3390990cf173f709..cd4fd21db2dcf3808fc40a132e167a565b1e4941 100644
--- a/pykat/finesse.py
+++ b/pykat/finesse.py
@@ -34,14 +34,14 @@ import pykat
 import warnings
 import re
 
-import pykat.exceptions as pkex
-
 from pykat.node_network import NodeNetwork
 from pykat.detectors import Detector
 from pykat.components import Component
 from pykat.commands import Command, xaxis
 from pykat.gui.gui import pyKatGUI
 
+import pykat.exceptions as pkex
+
 from PyQt4.QtCore import QCoreApplication
 from PyQt4.QtGui import QApplication
 
@@ -265,6 +265,8 @@ class kat(object):
                     obj = pykat.components.isolator.parseFinesseText(line)
                 elif(first[0:4] == "lens"):
                     obj = pykat.components.lens.parseFinesseText(line)
+                elif(first[0:3] == "mod"):
+                    obj = pykat.components.modulator.parseFinesseText(line)
                 elif(first[0:2] == "pd"):
                     obj = pykat.detectors.photodiode.parseFinesseText(line)
                 elif(first == "xaxis" or first == "xaxis*"):
@@ -310,12 +312,12 @@ class kat(object):
     def run(self, printout=0, printerr=0, save_output=False, save_kat=False,kat_name=None) :
         """ 
         Runs the current simulation setup that has been built thus far.
-        It returns a katRun object which is populated with the various
+        It returns a katRun or katRun2D object which is populated with the various
         data from the simulation run.
         """
         
         try:        
-            if not hasattr(self, "xaxis"):
+            if not hasattr(self, "xaxis") and self.noxaxis != None and self.noxaxis == False:
                 raise pkex.BasePyKatException("No xaxis was defined")
             
             if len(self.__katdir) == 0:
@@ -404,7 +406,7 @@ class kat(object):
             r.runDateTime = datetime.datetime.now()
             
             if p.returncode != 0:
-                raise FinesseRunError(err, katfile.name)
+                raise pkex.FinesseRunError(err, katfile.name)
             
             if printout == 1: print out
             if printerr == 1: print err
@@ -467,7 +469,7 @@ class kat(object):
             else:
                 return r
             
-        except FinesseRunError as fe:
+        except pkex.FinesseRunError as fe:
             print fe
         finally:
             print ""
@@ -505,7 +507,7 @@ class kat(object):
                 
             obj._on_kat_add(self)
             
-        except BasePyKatException as ex:
+        except pkex.BasePyKatException as ex:
             print ex
 
     def readOutFile(self, filename):
diff --git a/pykat/param.py b/pykat/param.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb9c7fbdfe417f0bfe7619fa5411a79ce1e805b1
--- /dev/null
+++ b/pykat/param.py
@@ -0,0 +1,167 @@
+from pykat.SIfloat import SIfloat
+import abc
+import pykat.exceptions as pkex
+
+class putable(object):
+    """
+    Objects that inherit this should be able to have something `put` to it.
+    Essentially this means you could write Finesse commands like
+    
+    put this parameter value
+    """
+    __metaclass__ = abc.ABCMeta
+    
+    def __init__(self, component_name, parameter_name, isPutable=True):
+        self._parameter_name = parameter_name
+        self._component_name = component_name
+        self._putter = None
+        self._isPutable  = isPutable
+    
+    @property
+    def isPutable(self): return self._isPutable
+    
+    def put(self, var):
+        print "put"
+        if not isinstance(var, putter):
+            raise pkex.BasePyKatException("var was not something that can be `put` as a value")
+        
+        if self._putter != None:
+            self._putter.put_count -= 1
+        
+        self._putter = var
+        self._putter.put_count += 1
+        
+    def _getPutFinesseText(self):
+        rtn = []
+        # if something is being put to this 
+        if self._putter != None:
+            rtn.append("put {comp} {param} ${value}".format(comp=self._component_name, param=self._parameter_name, value=self._putter.put_name()))
+        
+        return rtn
+            
+class putter(object):
+    """
+    If an object can be put to something that is putable it should inherit this
+    object.
+    """
+    
+    def __init__(self, put_name, isPutter=True):
+        self._put_name = put_name
+        self.put_count = 0
+        self._isPutter = isPutter
+    
+    @property
+    def isPutter(self): return self._isPutter
+    
+    def put_name(self): return self._put_name
+    
+        
+class Param(putable, putter):
+
+    def __init__(self, name, owner, value, isPutable=True, isPutter=True, isTunable=True, var_name=None):
+        self._name = name
+        self._owner = owner
+        self._value = value
+        self._isPutter = isPutter
+        self._isTunable = isTunable
+        self._owner._register_param(self)
+        
+        if isPutter:
+            if var_name == None:
+                var_name = "var_{0}_{1}".format(owner.name, name)
+                
+            putter.__init__(self, var_name, isPutter)
+            
+        if isPutable:
+            putable.__init__(self, owner.name, name, isPutable)
+        
+    @property
+    def name(self): return self._name
+    
+    @property
+    def isTuneable(self): return self._isTunable
+    
+    @property
+    def value(self): return self._value
+    @value.setter
+    def value(self, value):
+        self._value = value
+    
+    def __str__(self): return str(self.value)
+    def __float__(self): return self.value
+        
+    def getFinesseText(self):
+        rtn = []
+        
+        if self.isPutable: rtn.extend(self._getPutFinesseText())
+        
+        # if this parameter is being put somewhere then we need to
+        # set it as a variable
+        if self.isPutter and self.put_count > 0:
+            rtn.append("set {put_name} {comp} {param}".format(put_name=self.put_name(), comp=self._owner.name, param=self.name))
+        
+        return rtn
+        
+    def __mul__(self, a):
+        return float(self) * a
+    
+    def __imul__(self, a):
+        return self.value * float(a)
+        
+    __rmul__ = __mul__
+    
+    def __add__(self, a):
+        return self.value + flota(a)
+    
+    def __iadd__(self, a):
+        return self.value + float(a)
+        
+    __radd__ = __add__
+    
+    def __sub__(self, a):
+        return self.value - float(a)
+    
+    def __isub__(self, a):
+        return self.value - float(a)
+        
+    __rsub__ = __sub__
+    
+    def __div__(self, a):
+        return self.value / float(a)
+    
+    def __idiv__(self, a):
+        return self.value / complex(a)
+        
+    def __pow__(self, q):
+        return  self.value**q
+
+    def __neg__(self):
+        return -self.value
+        
+    def __eq__(self, q):
+        return float(q) == self.value
+    def __ne__(self, q):
+        return float(q) != self.value
+    def __lt__(self, q):
+        return float(q) > self.value
+    def __gt__(self, q):
+        return float(q) < self.value        
+        
+class AttrParam(Param):
+    """
+    Certain parameters of a component are set using the Finesse `attr` command.
+    
+    This inherits directly from a Param object so can be set whether this attribute
+    is putable or a putter.
+    
+    If the value pf the parameter is not 0 the attr command will be printed.
+    """
+    def getFinesseText(self):
+        rtn = []
+        
+        if self.value != 0:
+            rtn.append("attr {0} {1} {2}".format(self._owner.name, self.name, self.value))
+            
+        rtn.extend(super(AttrParam, self).getFinesseText())
+        
+        return rtn
\ No newline at end of file
diff --git a/pykat/utilities/optics/gaussian_beams.py b/pykat/utilities/optics/gaussian_beams.py
index 769bd75eebad6b4659bf4aae80835ad12d45f4d8..754135cfd694a9dd3165878d99f4434f229ff584 100644
--- a/pykat/utilities/optics/gaussian_beams.py
+++ b/pykat/utilities/optics/gaussian_beams.py
@@ -95,7 +95,7 @@ class gauss_param(object):
         return gauss_param(self.__lambda, self.__nr, self.__q * complex(a))
     
     def __imul__(self, a):
-        self.__q += complex(a)
+        self.__q *= complex(a)
         return self
         
     __rmul__ = __mul__
@@ -184,7 +184,8 @@ class HG_gauss_beam(object):
         self.__ypre_const *= math.sqrt(1j*self._qy.imag / self._qy)
         self.__ypre_const *= math.pow((1j*self._qy.imag * self._qy.conjugate)/(-1j*self._qy.imag * self._qy), self._m/2.0)
                 
-    def Unm(self, n, m, x, y):    
-        return self.__xpre_const * special
+    def Unm(self, n, m, x, y):  
+        # need to finish...
+        return self.__xpre_const
         
         
\ No newline at end of file