def xfer(dp, qa, qs):
Return the full-width, half-max of the transfer function in diameter space.
This implementation ignores diffusion broadening.
particle size in nm
aerosol flow rate in lpm
aerosol flow rate in lpm
Width of transfer function in nm.
beta = float(qa)/float(qs)
# Retrieve the center mobility
zc = aerosol.z(dp, self.air, 1)
# Upper bound of the mobility
zm = (1-beta/2)*zc
# Lower bound of the mobility
zp = (1+beta/2)*zc
return aerosol.z2d(zm, self.air, 1) - aerosol.z2d(zp, self.air, 1)
def __chargecorr__(diam, dn, gas, n=3, pos_neg=-1):
Correct the input concentrations for multiple charges.
When running in SMPS mode, we must keep in mind that each size of particles can carry multiple charges.
Particles with more charges will appear to be SMALLER than those with less. So, we will index through the
diameters backwards, get the number of the current selected size that would have charge n, and remove those
from the lower bins to the upper bins.
diam: array of float
array of diameters in nm
dn: array of integers
Array of particle concentrations corresponding to diameter 'diam'
gas: gas object
Gas object that defines the properties of the gas
n: int, optional
Number of charges to consider. Default is 3.
pos_neg: int, optional
Positive or negative one indicating whether to consider positive or negative charges.
Default is -1.
The charge correction loops from top to bottom in the size distribution.
This assumes that there are no particles beyond the probed distribution.
If there are, there will be noticeable steps in the charge corrected distribution.
Regarding the algorithm, we can solve for each bin by using the charging efficiency
ala Gunn or Wiedensohler. To solve, we use the following algorithm:
1. Assume that the current bin holds ONLY singly charged particles.
2. Calculate the fraction of particles that are expected to be singly charged
at the current diameter, :math:'f_1\left(D_p\right)'.
3. For each charge beyond 1:
a) Get the charging efficiency of the current particle size for :math:'i' charges
# Flip the incoming diamter array
rdiam = np.copy(diam[::-1])
# We are working backwards, so we need to have the length to get this all right...
l = len(dn)-1
# Inline function for finding the value closest to diameter d in the array diam
fmin = lambda nd: (np.abs(np.asarray(diam) - nd)).argmin()
for i, d in enumerate(rdiam):
# Get the fraction of particles that are singly charged
f1 = aerosol.ndistr(d, pos_neg, gas.t)
for j in reversed(range(2, n+1)): # Loop through charges 2 and higher backwards
ne = j*pos_neg
fi = aerosol.ndistr(d, ne, gas.t)
# Mobility of multiply charged particles
z_mult = abs(ne * aerosol.z(d, gas, pos_neg))
# Diameter bin which contains the multiply charged particles
d_mult = aerosol.z2d(z_mult, gas, 1)
# Continue while the diameter specified is larger than the minimum diameter
if d_mult >= diam:
# Find the index of the multiple charges
k = fmin(d_mult)
# Remove the particles in bin k that belong in the current bin, but don't remove more
# particles than there are in the bin
dn[k] -= min(dn[l-i]*fi/f1, dn[k])
# The total number of particlesi n the current bin is simply the number of singly charged
# particles divided by the singly charged charging efficiency.
dn[l-i] /= f1