docs: def Z_device(self, filter_order=None, window_size=None, tol=0.05):
          '''
          Compute the impedance *(including resistive and capacitive load)* of
          the DMF device *(i.e., dielectric and droplet)*.
  
          See :func:`calibrate.compute_from_transfer_function`
          for details.
          '''
          ind = mlab.find(self.fb_resistor >= 0)
          Z1 = np.empty(self.fb_resistor.shape)
          Z1.fill(np.nan)
          # convert to masked array
          Z1 = np.ma.masked_invalid(Z1)
  
          R2 = self.calibration.R_fb[self.fb_resistor[ind]]
          C2 = self.calibration.C_fb[self.fb_resistor[ind]]
          Z1[ind] = compute_from_transfer_function(self.calibration.hw_version
                                                   .major, 'Z1',
                                                   V1=self.V_total()[ind],
                                                   V2=self.V_fb[ind], R2=R2,
                                                   C2=C2, f=self.frequency)
  
          Z1 = np.ma.masked_invalid(pd.Series(Z1, pd.to_datetime(self.time, unit='s')
              ).interpolate(method='time').values)
          Z1.fill_value = np.nan
          Z1.data[Z1.mask] = Z1.fill_value
  
          # if we're filtering and we don't have a window size specified,
          # automatically determine one
          if filter_order and window_size is None:
              window_size = self._get_window_size(tol)
  
          # if the filter_order or window size is None or if the window size is
          # smaller than filter_order + 2, don't filter
          if (filter_order is None or window_size is None or window_size < filter_order + 2):
              pass
          else:
              # if the window size is less than half the sample length
              if window_size and window_size < len(Z1) / 2:
                  # suppress polyfit warnings
                  with warnings.catch_warnings():
                      warnings.simplefilter("ignore")
                      Z1 = savgol_filter(Z1, window_size, filter_order)
              else: # fit a line
                  result = self.mean_velocity(tol=tol)
                  if result['dt'] and \
                      result['dt'] > 0.1 * self.time[-1] and result['p'][0] > 0:
                      if self.calibration._c_drop:
                          c_drop = self.calibration.c_drop(self.frequency)
                      else:
                          c_drop = self.capacitance()[-1] / self.area
                      if self.calibration._c_filler:
                          c_filler = self.calibration.c_filler(self.frequency)
                      else:
                          c_filler = 0
                      x = result['p'][0]*self.time + result['p'][1]
                      C = self.area * (x * (c_drop - c_filler) / \
                                       np.sqrt(self.area) + c_filler)
                      Z1 = 1.0 / (2.0 * math.pi * self.frequency * C)
                      Z1[mlab.find(self.time==result['t_end'])[0]+1:] = \
                          Z1[mlab.find(self.time==result['t_end'])[0]]
                  else:
                      Z1 = np.mean(Z1)*np.ones(Z1.shape)
          return Z1