|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object android.support.v4.media.TransportController
public abstract class TransportController
Base interface to controlling a media transport. This is the interface for implementing things like on-screen controls: it allows them to request changes in playback, retrieve the current playback state, and monitor for changes to the playback state.
| Constructor Summary | |
|---|---|
TransportController()
|
| Method Summary | |
|---|---|
abstract int |
getBufferPercentage()
Retrieve amount, in percentage (0-100), that the media stream has been buffered on to the local device. |
abstract long |
getCurrentPosition()
Retrieve the current playback location in the media stream, in milliseconds. |
abstract long |
getDuration()
Retrieve the total duration of the media stream, in milliseconds. |
abstract int |
getTransportControlFlags()
Retrieve the flags for the media transport control buttons that this transport supports. |
abstract boolean |
isPlaying()
Return whether the player is currently playing its stream. |
abstract void |
pausePlaying()
Request that the player pause its playback and stay at its current position. |
abstract void |
registerStateListener(TransportStateListener listener)
Start listening to changes in playback state. |
abstract void |
seekTo(long pos)
Move to a new location in the media stream. |
abstract void |
startPlaying()
Request that the player start its playback at its current position. |
abstract void |
stopPlaying()
Request that the player stop its playback; it may clear its state in whatever way is appropriate. |
abstract void |
unregisterStateListener(TransportStateListener listener)
Stop listening to changes in playback state. |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Constructor Detail |
|---|
public TransportController()
| Method Detail |
|---|
public abstract void registerStateListener(TransportStateListener listener)
public abstract void unregisterStateListener(TransportStateListener listener)
public abstract void startPlaying()
public abstract void pausePlaying()
public abstract void stopPlaying()
public abstract long getDuration()
public abstract long getCurrentPosition()
public abstract void seekTo(long pos)
pos
- Position to move to, in milliseconds.public abstract boolean isPlaying()
public abstract int getBufferPercentage()
public abstract int getTransportControlFlags()
TransportMediator.FLAG_KEY_MEDIA_PREVIOUS
,
TransportMediator.FLAG_KEY_MEDIA_REWIND
,
TransportMediator.FLAG_KEY_MEDIA_PLAY
,
TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE
,
TransportMediator.FLAG_KEY_MEDIA_PAUSE
,
TransportMediator.FLAG_KEY_MEDIA_STOP
,
TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD
,
TransportMediator.FLAG_KEY_MEDIA_NEXT
|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


The Team, which consists of Sandra Gonzalez Maicas, Jaume Forner Escrig, Carlos Garcia Arbeloa, Fernando González González-Carrión, Jaume Francesc Roig Marmaneu and Aliénor Creismeas, presents you its Geometry Application :
Indeed, in this page, we can find the link to a main menu page which allow you to calculate the perimeter, the area, the surface or the volume of distinct geometrical figures.
Click here to see more!


Volume 1, Year 2014 - Pages 16-26
DOI: 10.11159/jbb.2014.003
Ash Analysis of Poultry Litter, Willow and Oats for Combustion in Boilers
Bimal Acharya, Animesh Dutta, Shohel Mahmud, Mohammad Tushar, Mathias Leon
School of Engineering, University of Guelph, 50 Stone Rd E, N1G 2W1, ON, Canada
Abstract - The large content of potassium and chlorine in lignocellulosic biomass greatly enhances the formation and accumulation of deposits and thus lead to corrosion in the different component of boilers compared to that of coal fired boiler. It is, thus, imperative to study the characteristics of the ash from lignocellulosic biomass and compare the results with the ash of non-lignocellulosic biomass. In this study, two lignocellulosic biomass ash samples from oat (agricultural biomass) and willow (forest wood biomass) were prepared and characterized and compared with a non-lignocellulosic biomass (poultry litter) ash samples. The detailed ash analysis and characterization of biomasses were performed by using elemental analysis, scanning electron microscopy (SEM) and X-ray diffraction (XRD). Ash samples from these biomasses are prepared at 800ᴼC, 900ᴼC and 1000ᴼC for SEM and XRD analysis. The poultry litter ash exhibits a higher alkali index, clorine and sulfur content, and a lower ash fusion temperature and silica in ash compared to that of willow and oats. Also, a very high ash content in poultry litter potentially requires high-volume ash-handling equipment and more attention to particulate removal, slagging, and fouling while used in a combustor/boiler. Therefore, care must be taken for using poultry litter as fuel for coal or lignocellulosic biomass combustion system.
Keywords: Ash, Lignocellulosic and non-lignocellulosic biomass, SEM, XRD, Alkali indices.
© Copyright 2015 Authors This is an Open Access article published under the Creative Commons Attribution License terms. Unrestricted use, distribution, and reproduction in any medium are permitted, provided the original work is properly cited.
Date Received: 2013-11-15
Date Accepted: 2014-05-13
Date Published: 2014-09-30
1.Introduction
Biomass can substitute the fossil fuels for generating power from boilers to reduce the Green House Gas (GHG) emission. The large alkali content of lignocellulosic biomass especially from the agricultural crop family causes more deposits and corrosion effect on the different components of boiler than the coal fired boiler [1-9]. This ultimately limits the operating temperature of the boiler shown in Table 1. Besides potassium and chlorine, large contents of calcium and silica in the lignocellulosic biomass cause deposit formation in the boiler. During agricultural biomass combustion, it is found that the bottom ash contains 34-84 % of potassium and calcium silicate components [10] whereas flue gas filter contains aerosols rich in KCl and K2SO4, which are formed when the flue gas is cooled down to 700-800C [11]. The fly ash contains mostly potassium and chlorine components in the range of 44 to 84% [11]. The rate of ash deposit formation on boiler heat transfer surfaces increases when the portion of the biomass ash is liquefied or melted. This phenomena may be caused due to a lower melting temperature of the ash because of the presence of the components shown in the Table 1. With the presence of components listed in the Table 1, the melting temperature could potentially start from 350°C, which is too low for a commercial combustion system to produce energy. During the agricultural straw combustion, boiler deposit contains large concentrations of K and Cl in addition to some silica, calcium and sulphur [12]. In the agriculture residue fired boiler, corrosion is a severe problem because of the reaction by KCl with the metal parts of boiler coils. Montgomery et al [13] observed the corrosion rates 0.8mm/Khrs, 0.3mm/Khrs and 0.02 mm/Khrs at steam temperatures of 570°C, 530°C and 440°C respectively. The corrosion mechanisms in the agricultural residue fired boiler is not yet completely understood [14, 15]. However, it is understood that sulfation of potassium chroride near the metal surface generates HCl gas or Cl2 gas that reacts with the boiler coils, and removing of Fe and Cror corrosion can be due to release of Cl2 gas after the reaction between KCL and Fe2O3 [16]. Therefore, for designing any types of biomass fired boiler, it is necessary to have an in depth knowledge on the deposition and corrosion formation and its effect on the every component of the boiler especially heating coils so that the steam temperature can be raised to make more efficient energy conversion system. Even though there are a number of study on ash analysis of other biomasses are performed [3, 5, 17], knowledge of the detailed analysis of different lignocellulosic and non-lignocellulosic biomass of Ontario has not yet been carried out. Hence, this study focuses to analyze ash samples of oats from agricultural family, willow from wood family, and poultry litter from non-lignocellulosic family by lab analysis, scanning electron microscopy (SEM) and X-ray diffraction (XRD) for their potential application as a fuel in combustion systems.
Table 1. Melting temperature of different components of biomass [3]
| Components | Minimum Melting Temperature °C |
| KCl | 774 |
| K2SO4 | 1059 |
| K2O +SiO2 | 750 |
| K2O.4SiO2 +CaO.SiO2 | 740 |
| KCl + K2SO4 | 694 |
| KCl + FeCl2 | 355 |
| KCl + K2SO4+Fe2O3 | 577 |
2. Materials and Methods
2.1 Sample Collection
Willow and oats samples were collected from the University of Guelph research center, and non-lignocellulosic sample of poultry litter was collected from a Poultry farm in Willington, Ontario. Willow and Oats were collected in the form of stem and pellets. Poultry litter was collected in the form of a mixture of manure (excreta), feathers, feed, dead birds, broken eggs, and bed material (wood shavings or straw). These samples were chopped in smaller pieces and grinded.
2.2 Sample preparation
Ash samples were prepared by a muffle furnace, and a custom designed Quartz Wool Matrix (QWM) reactor shown in Figure 1 at 800°C, 900°C and 1000°C. A detailed description of this reactor is available at (Acharya and Dutta 2013) (18). The reactor consists of a Stainless Steel (SS) tube heated by four electric heaters of 1.25KW capacity in close contact with the reactor wall and separately controlled by two PID controllers. The SS tube has an inner diameter of 75 mm and height of 600 mm. This reactor allows simulation of any gas-solid relative velocity; gas composition and gas temperature in a reactor while a precision electronic balance continuously measures the mass change of a reaction. Such reactor could thus accurately simulate conditions one would expect in a fixed, moving or entrained flow reactor. Before starting an experiment, the reactor was heated until an equilibrium temperature or steady state is attained. Temperatures were measured at two different locations one from upper mid portion of reactor and another from lower mid portion of the reactor by two separate thermocouples through the temperature controller (CNi16D, Temperature and Process Controller, Omega, USA). Then the sample of biomass of known mass and moisture content were placed into the reactor and air is supplied. The electronic balance (Model: MS204S, Mettler Toledo, Switzerland) continuously measured the mass of the biomass. When the weight of sample at a specific temperature reached a constant value, it is assumed that the combustion is completed. Thereafter, the sample is cooled down in desiccator and weighed. Its composition is analyzed by SEM and XRD techniques.
2.3 Methods of Analysis
Ultimate analysis of the raw biomass samples was carried out according to ASTM D 5373-08 method. All samples were dried at 105°C for 24 hours prior to the experiment for Ultimate analysis. During the experiment, the combustion was carried out at 925°C under Helium atmosphere while the reduction was carried out at 650°C. Ultimate analysis of biomass sample provides the elemental analysis of C, H, O, S and N. Methods and equipment used and results are listed in Table 2.
Table 2. Methods and Equipment used in characterizing raw biomass samples
*MC=Moisture Content; AC=Ash Content; VM=Volatile Matter; FC=Fixed Carbon; C=Carbon; H=Hydrogen; N=Nitrogen; S=Sulphur; O=Oxygen
| Proximate Analysis | Ultimate Analysis | Higher Heating Value(HHV) | ||||||
| Parameter | MC | AC | VM | FC | C, H, N | S | O | HHV |
| Method | ASTM E871 | ASTM E1755 | ASTM D3175 | ASTM E872 | ASTM D5375 | ASTM D4239 | ASTM E870 | ASTM E711 |
| Equipment Used | Muffle Furnace | Muffle Furnace | Muffle Furnace | Calculated Value | Leco CHN-1000 Elemental Analyzer | Leco SC-432 Elemental Analyzer | Calculated Value | C-200 Bomb Calorimeter |
Morphology of the biomass samples were analyzed using SEM at the lab facility of University of Guelph. Samples were coated with gold (20 nm) with a sputter coater (Model K550; Emitech, Ashford, Kent, England) prior to SEM analysis. SEM micrographs were taken by using a model S-570 (Hitachi High 115, Technologies Corp., Tokyo, Japan) at 10 kV accelerating voltage. Images were captured by extracting electrons from a sharp tungsten tip, and formed into a fine beam by a series of electromagnetic lenses. Resolutions of up to one nanometer was able to produce.
X-Ray diffraction test was carried out on the ash samples of the biomass at the lab facility of University of Guelph. The XRD test has given all the constituent elements, minerals and ores present in the ash. This technique is used to understand the crystal structure, chemical composition and physical properties of ash materials and thin films.. A comprehensive database of all known elements, minerals and ores were used to search for diffractogram patterns. Powder X-ray diffraction patterns (XRD) for various sample of ashes were collected in Bragg-Brentano geometry at room temperature on a STOE goniometer using the Cu Kα radiation (λ = 1.5406 Å) produced by an ENRAF-NONIUS
FR571 rotating anode generator. A Moxtek 2500 Silicon drift energy sensitive detector was used in order to minimize the background level. The patterns were measured in the 2θ interval from 5° to 70°, with a step size of 0.02° and 24 s counting time per step.
3. Results and Discussions
3.1 Chemical Analysis
Ultimate and proximate analyses of each sample were conducted as per the ASTM standard and is shown in Table 3. It is observed that lignocellulosic biomass contains more carbon and oxygen components 52.2% & 34.0% in oats and 50.7% & 24.1% in willow than poultry litter with 43.3% & 6.0%. But Poultry litter has significantly high Nitrogen and Ash content, and moderately high Sulfur content than willow and oats. This is likely to present some challenges when using poultry litter in a combustion device designed for lignocellulosic biomass. In addition, a lower volatile matter and a higher moisture contents in poultry litter compared to lignocellulosic biomass may cause problems in establishing flame in the combustor.
Table 3. Analysis of raw oats, poultry litter and willow (wt%, dry basis)
| Ultimate Analysis | |||
| Elements | Oats | Poultry Litter | Willow |
| Carbon, % | 52.2 | 43.3 | 50.7 |
| Hydrogen, % | 6.6 | 6.6 | 5.9 |
| Oxygen, % | 34.0 | 6.0 | 24.1 |
| Nitrogen, % | 0.6 | 5.7 | 0.5 |
| Sulgur, % | 0.3 | 1.2 | 0.4 |
| Ash Contents | 22.3 | 11.5 | 5.6 |
| Proximate Analysis | |||
| Moisture (%) | 7.7 | 20.1 | 5.2 |
| Volatile Matter (%) | 74.3 | 54.3 | 73.2 |
| Fixed Carbon (%) | 12.3 | 3.3 | 10.2 |
| HHV | 16.4 | 10.1 | 16.1 |
3.2 Chlorine and Ash Fusion Temperature
Samples were tested for Chlorine and ash fusion temperature by burning it as per the guideline of ASTM standard. The results of the analysis is shown in Table 4. Out of tested three samples, only poultry litter contains very small amount of sulfur. Lignocellulosic biomass samples of willow and oats have higher ash initial deformation temperature 1115°C and 1279°C than non-lignocellulosic biomass Poultry litter at 1048 °C and will be a better fuel than that of poultry litter. Also, the high ash content in poultry litter may require high-volume ash-handling equipment and more attention to particulate removal, slagging, and fouling while used in a combustor/boiler.
Table 4. Chlorine & ash fusion temperature of poultry litter, willow and oats
| Particular | Poultry Litter | Willow | Oats |
| Chlorine (%) | 0.1 | 0 | 0 |
| Ash Fusion Temperature (°C) | |||
| Initial Deformation (IT) (°C) | 1048 | 1115 | 1279 |
| Softening Temperature (ST) (°C) | 1074 | 1171 | 1303 |
| Hemispherical Temperature (HT) (°C) | 1207 | 1258 | 1338 |
| Fluid Temperature (FT) (°C) | 1240 | 1292 | 1354 |
3.3 Elemental Analysis of Ash
3.3.1 Calculations of Combustion Indices
To estimate the slagging, fouling and bed agglomeration potential of these three forms of biomass, alkali index (AI), the base-to-acid ratio (R b/a ), and the bed agglomeration index (BAI) are calculated using the procedure described by Vamvuka and Zografos [19, 20] as per Eqns. 1-3. When the AI values are within the range of 0.17 to 0.34 kg GJ -1 ([19], fouling or slagging may or may not occur, but it is certain to happen when the values are above this range. When the ratio of R b/a increases, the fouling tendency of a fuel ash increases. Also it is reported that bed agglomeration occurs when BAI values are lower than 0.15 [19]
Table 1. Elemental Analysis of Poultry Litter, Willow and Oats in % Ash basis
| Components | Poultry Litter | Willow Pellets | Oat Pellets |
| SiO2 | 2.69 | 67.77 | 60.68 |
| TiO2 | 0.02 | 0.44 | 0.61 |
| Al2O3 | 0.31 | 9.47 | 15.62 |
| Fe2O3 | 0.57 | 2.89 | 0.4 |
| MnO | 0.33 | 0.11 | 0.09 |
| CaO | 65.17 | 9.4 | 5.59 |
| K2O | 6.36 | 3.53 | 9.85 |
| Na2O | 2.48 | 2.44 | 0.47 |
| P2O5 | 17.46 | 1.74 | 4.54 |
| Cr2O3 | 0.03 | 0.03 | 0.07 |
| Alkali Index (AI) | 1.81 | 0.42 | 0.35 |
| Base to Acid Ratio (Rb/a) | 26.2 | 0.50 | 0.24 |
| Bed Agglomeration Index (BAI) | 0.06 | 0.48 | 0.04 |
As shown in Table 5, the elemental ash analysis of poultry litter contains 65.17% and 17.46% of CaO and P2O5, respectively. These values are 9.4% and 5.59% and 1.74% and 4.54% for willow and oats, respectively. Lignocellulosic biomass willow and oats contains more than 60% of SiO2. Willow contains 20.7% of MgO and 9.47% of Al2O3 whereas oats contains 15.62% of Al2O3 and 9.85% of K2O. The major compounds in poultry litter identified in the ash are CaO (65%), P2O5 (17.5%) and K2O (6.4%), which falls into the category of biomass ash rich in calcium, phosphorous, and potassium. As can be seen from combustion indices, Poultry litter is expected to have more corrosion and deposit formation compared to other two samples of lignocellulosic biomass. This is because the concentration of alkali metals (Na2O, and K2O) is higher in poultry litter than in willow and oats, indicating that poultry litter is a more challenging fuel than lignocellulosic biomass. High alkali content, especially in conjunction with high chloride levels, results in a high potential for slagging, fouling, particulate emissions, and corrosion during combustion [15-17, 21-22]. This is one of the reasons for having a lower ash fusion temperature for poultry litter than that of willow and oats.
Silica salts formed by K and Na show strong tendencies to become sticky and form slag on the hot surfaces of the combustion equipment and the boiler. Maintaining low combustion temperatures will also help in controlling alkali-related slagging and fouling problems. Fluidized bed combustors offers this advantage vis-à-vis conventional (fixed/moving bed) combustors as they typically operate in the range of only 800-900°[17].
3.4 SEM tests
The presence of potassium and chlorine in the fuel significantly increases the deposit formation and corrosion potential in combustion devices, compared to coal. It is known that the alkali species which cause the bed agglomeration come from the fuel ash [2, 3, 5, 12-17]. Hence, it is important to understand the behavior of alkali species in ash for the formation mechanisms of agglomerates and coating layers. In this study, ash samples are prepared at 800°C, 900°C and 1000°C and scanning electron microscopy imagery has been performed on the ash samples.
3.4.1 Poultry Litter
As shown in Figures 2 (a-c), the course mode particles has an irregular surface structure. The temperature during the process has not been high enough for complete coalescence of the ash into spherical particles. Some of the particles are long, fiber-like agglomerates still resembling the original wood fiber structure [12, 17]. The surfaces of the sample particles are generally formed by primary particles, which are less than few micrometers in size. These consequently joined together and form chain like structure. The primary particles are mainly found as mixture of round shaped and crystalline structures. The ash particle does not contain much unburned particles at higher temperature. At low temperature, the sample contains some wool like structures, which gradually disappears with the increase in combustion temperature. This wool like structures are not combustible at low temperature and can only be combusted at high temperature [16-17]. Also at high temperature, particles become more brittle as the minerals matters in the form of crystal increases. Hence the particles become smaller and many cracks start to show up as the combustion temperature increases. The increase in smooth surfaces in the samples with the increase in combustion temperature also supports the relative increase in mineral matters in the samples which is obtained in XRD analysis.
| (a) | (b) | (c) |
Skrifvars et al. (1998)[11] characterized the sintering tendency of ten biomass ash samples and classified the ash components into three groups: simple alkali salts, silicates and the rest non-melt. The fusible compounds melt and coat the surface of ash particles during combustion. The EDS spot analyses indicate that these melts, which are alkali silicates, are rich in K or Na. Based on the K2O־CaO־SiO2 phase diagram and the Na2O־SiO2 and K2O־SiO2 phase systems [21], the melting point of these alkali silicates are in the range of 800 - 1200°C. These alkali silicates formed during combustion can melt and form a sticky coating on the surface of ash particles, or on silicon dioxide grains, used as bed material in fluidized bed combustors at high temperature, leading to agglomeration.
Large and small sized ash particles may play different roles in bed agglomeration. When small-sized ash particles collide with the bed particles, the molten alkali species on them will be transferred to the surface of the bed particles. Large-sized ash particles may increase the amount of melts on local surface of bed particle and may act as the necks for the agglomerate formation. Bed agglomeration can be controlled by keeping the bed alkali contents low enough by regularly discharging the bed ash and feeding fresh sand into the bed [22].
3.4.2 Willow
Figure 3 (a), (b) and (c) show the images of the Willow' ash samples at 800, 900 and 1000°C respectively. As we have seen in poultry litter, at low temperature, the sample contains some wool like structures which gradually disappears with the increase in combustion temperature [2, 16]. The surface has irregular structure which signifies the process has not been enough for complete coalescence of the ash into spherical particles. Some of the particles were long, fiber like agglomerates still resembling the original wood fiber structure. The surfaces of the particles were usually formed in small sizes which had often sintered together forming chain-like agglomerate structures [2-3,17]. The primary particles were mainly cotton shaped but also cornered ones were seen like crystalline structure. This signifies, the ash particles does not contain significant amount of unburned samples. Also at high temperature, particles become more brittle as the minerals matters in the form of crystal increases. Hence the particles become smaller and many cracks start to show up as the combustion temperature increases. Because of the presence of high Silicon dioxide, Magnesium dioxide and other alkalis, the structure contains smooth surface which represents the presence of metallic components in the ash sample. The increase in smooth surfaces in the samples with the increase in combustion temperature also supports the relative increase in mineral matters in the samples which is obtained in XRD analysis.
| (a) | (b) | (c) |
3.4.3 Oats
Figure 4 (a), (b) and (c) show the images of the Oats ash samples at 800, 900 and 1000°C respectively. At low temperature, the sample contains some wool like structures which gradually disappears with the increase in combustion temperature. This broken wood like structures is not combustible at low temperature and can only be combusted at high temperature [16-17]. Similar to willow ash, some of the particles were long, fiber like agglomerates still resembling the original Oats fiber structure.  The primary particles were mainly cotton shaped but also cornered ones are seen like crystalline structure. This signifies, the ash particles does not contain significant amount of unburned samples. Also at high temperature, particles become more brittle as the minerals matters in the form of crystal. Hence the particles become smaller and many cracks start to show up as the combustion temperature increases. Because of the presence of high Silicon dioxide, Magnesium dioxide and other alkalis, the structure contains smooth surface which represents the presence of metallic components in the ash sample. The increase in smooth surfaces in the samples with the increase in combustion temperature also supports the relative increase in mineral matters in the samples which is also obtained from ash analysis.
| (a) | (b) | (c) |
3.5 XRD tests(Crystalline Phases Detected by Powder Diffraction)
The XRD tests provide all the constituent elements, minerals and ores present in the ash. The main purpose of the XRD tests was to determine the minerals present in the ash sample that could have potential effect on slagging, corrosion, fouling and agglomeration.
3.5.1 Poultry Litter
According to the researchers the major components for the poultry litter are struvite, sylvite, calcite, Weddellite and quartz [24-27]13-27]. Figure 5 shows the XRD patterns for poultry litter ash prepared at temperatures 800, 900 and 1000°C. The peaks at 17, 28, 33 2θ as can be seen from the Fig 5 represents the crystalline structure of struvite (NH4MgPO4·6H2O) [24-27], which with the increase in temperature, the height of the peak increases. This can be attributing to the increase in relative amount of crystalline structure in the sample with the increase in combustion temperature. Fig 5 also shows that there is a small peak of quartz (SiO2) at 26 2θ [26]. Sylvite (KCl) is identified in the samples at 28, 29, and 51 2θ [24, 27]. Calcite (CaCO3) and Weddellite (CaC2O4·2H2O) were also identified by the powder XRD at 31, 34 [27] and 43, 46 [26] 2θ respectively. Calcium, being an important diet for the poultry, can be expected to show as some kind of crystalline structure of calcium compound in the litter samples.
3.5.2 Willow and Oats
The XRD analysis (Figure 6) confirm that the basic forms in both willow and oats ash are SiO2, CaSO4 and K2Ca(CO3) 2, which determine the nature of the alkaline extracts in water and Willow ash. The ash fusion temperature of willow and oats are about 1100-1300°C, and 1250-1350°C respectively. This range of temperature limits the operating temperature of the combustor of a boiler system. The peaks of biomass are in the range of 20-40, 2θ which may be due to presence of arcanite, periclase, quartz, calcium silicate and potassium iron oxide in the molten biomass [28]. The XRD patterns of oat ash prepared at different experimental conditions showed hump for all three samples starting from 2θ=15 ־ 35° with some sharp peaks near 30°. These patterns demonstrate that oat ash is mainly amorphous in nature consists of majorly silica [29]. The sharp peak at 2θ=29° for the ash produced at 800°C is due to the presence of K2SO4. However, this peak diminishes with the increase in temperature and a new peak at 2θ=28° for KAlSiO4 becomes visible at 1000°C [30].
| (a) XRD of willow ash | (b) XRD of oats ash |
4. Conclusions
The poultry litter has very high ash content, and exhibits higher alkali index, lower ash fusion temperature, higher Cl and sulfur content, lower silica in ash compared to that of willow and oats. . Therefore, care must be taken for using poultry litter as fuel for combustion system. Also, the high ash content in poultry litter may require high-volume ash-handling equipment and more attention to particulate removal, slagging, and fouling while used in a combustor/boiler. The ashes from the samples studied contain a significant amount of Silica and Calcium and can be used for the cement production. Thick deposit of the ash prevents heat flow on the boiler so regular disposal of ash from the boiler is required in any biomass fired boilers. It is recommended to use regular soot blower and thus obtain better heat transfer.
References
[1] Acharya, B., Dutta, A., & Basu, P. (2012). Circulating-Fluidized-Bed-Based Calcium-Looping Gasifier: Experimental Studies on the Calcination-Carbonation Cycle. Industrial & Engineering Chemistry Research, 51(25), 8652-8660. View Article
[2] Baxter, L. L.; Miles, T. R.; Miles, T. R., Jr.; Jenkins, B. M.; Milne, T.; Dayton, D.; Bryers, R. W.; Oden, L. L. The Behavior of Inorganic Material in Biomass-Fired Power Boilers: Field and Laboratory Experiences. Fuel Process. Technol. 1998, 54, 47-7 View Article
[3] Jensen,P.A., Flemming J. Frandsen, Jørn Hansen, Kim Dam-Johansen,Niels Henriksen, and Steffen Horlyck, (2004) SEM Investigation of Superheater Deposits from Biomass-Fired Boilers, Energy & Fuel 2004, 18, 378-384. View Article
[4] Roy M.M, Dutta,A., Corscadden, K.,. (2013). An experimental study of combustion and emissions of biomass pellets in a prototype pellet furnace, Applied Energy, Vol 108, pp. 298-307 (I.F. 5.106). (NSERC) View Article
[5] Kludze,H., Deen,B., Dutta, A. (2013). Impact of agronomic treatments on fuel characteristics of herbaceous biomass for combustion, Fuel Processing Technology, Vol. 109, pp 96-102 (I.F. 2.945). (OMAFRA) View Article
[6] Roy M.M.,, Dutta,A., Corscadden,K., Havard P.,and DickieL. (2011). Review of Biosolids Management Options and Co-incineration of a Biosolid-derived Fuel, Waste Management, 31 (11), pp. 2228-2235 [N-Viro, NSDA] (I.F: 2.358) View Article
[7] Jarungthammachote S.and Dutta A. (2012). Experimental investigation of multi-stage air-blow and air-steam gasification. in print Int. J Energy Res. 36 (3), 335-345. (I.F: 1.86) View Article
[8] Thamavithya, M., Jarungthammachote,S., and Dutta,A., and Basu. P. (2012). Experimental study on sawdust gasification in a spout-fluid bed reactor. Int. J Energy Res. 36 (2), 204-217. (I.F: 1.86) View Article
[9] Dhungana, A., Dutta,A., Basu,.P., 2012. Torrefaction of non -lignocellulose biomass waste, Cdn. J. of Chem. Engineering, 90 (1) 186-195. [NSERC] (I.F: 0.707)
[10] Frandsen, F., Nielsen, H. P., Hansen, L. A., Hansen, P. F. B. Andersen, K. H., Sørensen, H. S. (1998) Ash Chemistry Aspects of Straw and Coal-Straw Co-firing in Utility Boilers. Paper presented at the 15th Annual International Pittsburgh Coal Conference. PA, USA, September, 1998. View Article
[11] Christensen, K. A.; Stenholm, M.; Livbjerg, H. (1998). The Formation of Submicron Aerosol Particles, HCl, and SO2 in Straw-Fired Boilers. J. Aerosol Sci. 1998, 29 (4), 421-444. View Article
[12] Michelsen, H. P.; Frandsen, F.; Dam-Johansen, K.; Larsen, O. H. (1998). Deposit and High-Temperature Corrosion in a 10 MW Straw-Fired Boiler. Fuel Process. Technol. 1998, 54, 95-108. View Article
[13] Montgomery M., Karlson, A., Larsen, O. H. (2002). Field test corrosion experiments in Denmark with biomass fuels. Part 1: Straw firing. Mater. Corros. 2002, 53, 121-131. View Article
[14] Montgomery M., Biede, O. & Larsen, O. H. Corrosion Investigation at Maribo Sakskrbing c, Part I. Technical University of Denmark, Department of Manufacturing Engineering, 2001.
[15] Nielsen H. P. Frandse, F. J., Dam-Johansen K. & Baxter L. L. (2000). The Implication of Chlorine-Associated Corrosion on the Operation of Biomass-Fired Boilers. Prog. Energy Combust. Sci. 2000, 26, 283-298 View Article
[16] Hansen L. A., Nielsen H. P., Frandsen F. J., Dam-Johansen, K,. Horlyck S. & Karlsson A.(2000). Influence of Deposit Formation on Corrosion at a Straw-Fired Boiler. Fuel Process. Technol. 2000, 64, 189-209. View Article
[17] Skrifvars, B.-J., Sþris, G., Backman, R., Widegren-Dafgasrd, K. and Hupa, M. (1997) Ash behavior in a CFB boiler during combustion of Salix. Energy Fuels 11, 843-848. View Article
[18] Acharya B and Dutta A. "Characterization of Torrefied Willow for Combustion Application; Journal of Biobased Materials and Bioenergy, Volume 7, Number 6, December 2013 , pp. 667-674(8) View Article
[19] Vamvuka, D., Zografos,D. (2004) Predicting the behaviour of ash from agricultural wastes during combustion. Fuel 83 (2004) 14-15. View Article
[20] amvuka,D., Topouzi,V., S. Sfakiotakis, Evaluation of production yield and thermal processing of switchgrass as a bio-energy crop for the Mediterranean region. Fuel Process Technol. 91 (2010) 988-996. View Article
[21] Acharya, B., Sule, I. & Dutta, A. "A review on advances of torrefaction technologies for biomass processing. Biomass Conversion and Biorefinery (2012). Available at: http://www.springerlink.com/index/10.1007/s13399-012-0058-y. View Article
[22] Thy, P., Jenkins, B. M., Grundvig, S., Shiraki, R., Lesher, C. E. 2006. High temperature elemental losses and mineralogical changes in common biomass ashes. Fuel, 85(5), 783-795. View Article
[23] Barišić, V., Åmand, L. E., & Coda Zabetta, E. (2008). The role of limestone in preventing agglomeration and slagging during CFB combustion of high phosphorus fuels. World Bioenergy, Jönköping (Sweden), May 27 - 29.
[24] Güngör, K., Jürgensen, A., & Karthikeyan, K. G. 2007. Determination of phosphorus speciation in dairy manure using XRD and XANES spectroscopy. Journal of environmental quality, 36(6), 1856-1863. View Article
[25] Sen, A. N., Miller, L., Basu, P., & Dutta, A. (2003). Revamping of 4 x 58 MWth Pulverized Coal-Fired Boilers With Circulating Fluidized Bed Firing. ASME.
[26] Hunger, S., Sims, J. T., Sparks, D. L. 2008. Evidence for struvite in poultry litter: effect of storage and drying. Journal of environmental quality, 37(4), 1617-1625. View Article
[27] Zhang, S. Q., Zhang, F. D., Liu, X. M., Wang, Y. J., Zou, S. W., & He, X. S. 2005. Determination and analysis on main harmful composition in excrement of scale livestock and poultry feedlots. Plant Nutr Fert Sci, 11(6), 822-829. View Article
[28] Naik, S., Goud, V. V., Rout, P. K., Jacobson, K., & Dalai, A. K. (2010). Characterization of Canadian biomass for alternative renewable biofuel. Renewable energy, 35(8), 1624-1631. View Article
[29] Cheah, C. B., & Ramli, M. (2014). The fluid transport properties of HCWA-DSF hybrid supplementary binder mortar. Composites Part B: Engineering, 56, 681-690. View Article
[30] Niu, Y., Tan, H., Wang, X., Liu, Z., Liu, H., Liu, Y., & Xu, T. (2010). Study on fusion characteristics of biomass ash. Bioresource technology, 101(23), 9373-9381 View Article


From Laziness to Control: Reversing an IoT device using Frida
Have you ever had that irresistible urge to take apart a cheap IoT device you bought from a random store? You know, that feeling that says, “Let’s dive into the mystery and figure out how this thing actually works!” But then you stop and ask yourself, “Why am I even doing this?” and struggle to come up with a good reason. Well, let me tell you, if there was a Ph.D. for taking apart useless things, I’d probably have earned it!
Today, we’re going to explore the exciting world of reverse engineering, with a focus on understanding the device’s communication protocol. And here’s my little secret: this is my go-to trick when I’m feeling a bit lazy. Get ready for some tech magic, my friends!
Exploring the Target Device
Alright, let’s kick off our journey by addressing the question: What are we going to reverse engineer? Last week, I purchased an LED strip stand (as shown in the image), which came with a controller and a questionable phone app. From my experience, these types of apps usually communicate through Bluetooth. However, I’m not entirely certain about the controller itself. It could be using infrared, Bluetooth, or maybe even something entirely different (but probably not)?
Now, here’s the deal: I want to ditch the app because it’s been tickeling me crazy. To achieve this, I need to uncover the commands that are being sent from the app to the LED strip. Once I have a clear understanding of these commands, I can rewrite them in a programming language that I’m comfortable with. So, our goal is set: let’s crack the code.
Choosing the Right Approach
In order to achieve our goal of taking down the app and gaining control over our LED strip, we have several options available. Let’s explore each one:
-
Dump the LED strip’s firmware and reverse it: This approach involves extracting and analyzing the firmware of the LED strip itself. However, it requires extensive knowledge of hardware and may consume a significant amount of time and effort. Considering the complexity and potential challenges, this approach may not be the most convenient choice for a simple strip light.
-
Dump the controller’s firmware: This method involves extracting and examining the firmware of the controller. Similar to the previous approach, it requires hardware knowledge and can be time-consuming. While it provides valuable insights, it may not be the most suitable option for our scenario.
-
Use a magical device to sniff Bluetooth communication: This option involves employing a specialized device to intercept and analyze the Bluetooth communication between the app and the LED strip. Unfortunately, obtaining such a device might be difficult or costly, making it less reliable for our purposes.
-
Dissect the mobile app and reverse engineer it: This is the approach I have chosen, and let me tell you why. Tackling the mobile app allows us to dive into its inner workings, understand the commands it sends to the LED strip, and ultimately rewrite those commands according to our preferences. It’s a more accessible option, requiring reverse engineering skills but without the hardware-intensive aspects of the other methods.
Considering my inclination toward efficiency and laziness, focusing on dissecting and reverse engineering the mobile app appears to be the most favorable path forward. Let’s dive into the app’s code and unveil its secrets!
When we’re faced with a big challenge like reading lots of messy code written in Java or Kotlin, it can be really tiring to go through it all by hand. But don’t worry, I’ve got a solution that’s both efficient and effective. Our main goal is still clear: we want to figure out how the app communicates and extract the important commands, without getting too caught up in the app’s inner workings.
Here’s where dynamic analysis comes in. It’s a smart technique that lets us skip the hard work of reading all that code manually. Instead, we can focus on the most important parts. And to make things even easier, we’ll use Frida, a handy tool that can help us with our analysis.
By using dynamic analysis and Frida, we’ll be able to work smarter, not harder (I made up this excuse to cover up my laziness :d ). We’ll be able to find the key details of the communication protocol without getting lost in all the other stuff. Get ready to see how this combination of analysis and Frida can make our job much simpler and more efficient.
Environment Setup
Let’s set up the environment for our project. Here are the steps:
-
Rooted Android device: We’ll need a real Android device that has been rooted for this project. Emulators won’t work because they don’t support the Bluetooth stack. Some emulators might have a simulated Bluetooth connection, but we need to connect to a real device. Also, install the
HappyLighting
app. -
ADB (Android Debug Bridge): We’ll use ADB to communicate with the Android device. You can install ADB on Debian-based Linux distributions by running the following command:
sudo apt install adb
Note: Make sure you have enabled Developer Options
on your Android device.
- Frida: We also need to install Frida (You need Python) on both the computer and the Android device.
On your computer, run the following command to install the frida-tools
:
pip install frida-tools
On the Android device, first download the appropriate frida-server
binary for your device’s CPU architecture from here!. Then, push the frida-server
to the device by running these commands:
adb push /path/to/frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &
To verify that everything is working correctly and that you can communicate with the frida-server
, run the following command on your computer:
frida-ps -U
You should see a list of running processes on your Android device.
With these steps completed, we have our environment set up and ready to go.
Reversing the Communication Protocol
Finally, we’ve reached the exciting part where we dive into reversing and getting our hands dirty. But before we begin, let’s discuss our approach. If you’re already familiar with Frida and how it works, great! If not, take a quick look here! to get acquainted.
In simple terms, our goal is to find the specific function responsible for sending commands to the LED strip device, hook it using Frida, and log those commands. This way, we can reimplement a basic Bluetooth client and send the commands ourselves.
Now, you might be wondering how we can achieve this without delving into the complexities of reversing the Android application. Well, let’s take a step back and think outside the box for a moment. Do we really need to locate specific functions? In fact, what is the “right” function we want to hook?
To answer that, we need to consider a different perspective. We’re interested in the last function in the chain of the functions that handles and sends the commands to the device. Why the last one? Because we want to capture the raw payload being sent to the device, including any checksums, encodings, or padding applied. We need the raw payload as our starting point. We can capture that payload, send it to the device, and see if it works. If it does, great! If not, we can backtrack and analyze the chain further.
So, what is this last function responsible for sending the Bluetooth payload? Well, you guessed it! It’s the Java Bluetooth function from the Android SDK. Ultimately, Java and the Android SDK are responsible for delivering the payload to Android’s Bluetooth stack. Therefore, we can conveniently ignore all the code and simply hook the Java Bluetooth function. That’s all there is to it. We can reverse the communication protocol without actually having to reverse the entire application (if we’re fortunate enough that capturing and emulating the raw payload works for us).
With this approach, we’re ready to uncover the secrets of the communication protocol and create our own Bluetooth client. It’s time to embark on this reverse engineering journey and see where it takes us!
To implement hooking with Frida, we need to find the Bluetooth function’s signature. After some searching, we come across the android.bluetooth.BluetoothGattCharacteristic
class, which has a function called setValue
responsible for sending payloads through Bluetooth. The function signature is as follows:
public boolean setValue (String value)
Take your time and look at the examples provided by Frida docs here!. Now, let’s write a proper hook for the setValue
function using Frida:
Java.perform(function () {
var BluetoothGattCharacteristic = Java.use('android.bluetooth.BluetoothGattCharacteristic');
// setValue(String)
BluetoothGattCharacteristic.setValue.overload('java.lang.String').implementation = function (value) {
console.log('[BluetoothGattCharacteristic.setValue] Value (String): ' + value);
// Call the original method and return the result
var result = this.setValue(value);
return result;
};
});
This code sets up a hook on the android.bluetooth.BluetoothGattCharacteristic.setValue()
function. Whenever this function is called, it will log the inputs (hopefully the commands we’re looking for) to the console.
However, we notice that there are three more overloads
for this function, as mentioned in the Android Developer documentation here!.
In Java, method overloading is the ability to define more than one method with the same name in a class. The compiler is able to distinguish between the methods because of their method signatures1. This means that multiple methods can have the same name as long as the number and/or type of parameters are different. Method overloading is mainly used to increase the readability of the program; to make it look better. For example, instead of defining two methods that should do the same thing, it is better to overload one.
To ensure we don’t miss anything, let’s implement hooks for these overloads as well:
Java.perform(function () {
var BluetoothGattCharacteristic = Java.use('android.bluetooth.BluetoothGattCharacteristic');
// Overload 1: setValue(String)
BluetoothGattCharacteristic.setValue.overload('java.lang.String').implementation = function (value) {
console.log('[BluetoothGattCharacteristic.setValue] Value (String): ' + value);
// Call the original method and return the result
var result = this.setValue(value);
return result;
};
// Overload 2: setValue(byte[])
BluetoothGattCharacteristic.setValue.overload('[B').implementation = function (value) {
// Convert byte array to hex string
var hexValue = bytesToHex(value);
console.log('[BluetoothGattCharacteristic.setValue] Value (byte[]): ' + hexValue);
// Call the original method and return the result
var result = this.setValue(value);
return result;
};
// Overload 3: setValue(int, int, int)
BluetoothGattCharacteristic.setValue.overload('int', 'int', 'int').implementation = function (value1, value2, value3) {
console.log('[BluetoothGattCharacteristic.setValue] Values (int, int, int): ' + value1 + ', ' + value2 + ', ' + value3);
// Call the original method and return the result
var result = this.setValue(value1, value2, value3);
return result;
};
// Overload 4: setValue(int, int, int, int)
BluetoothGattCharacteristic.setValue.overload('int', 'int', 'int', 'int').implementation = function (value1, value2, value3, value4) {
console.log('[BluetoothGattCharacteristic.setValue] Values (int, int, int, int): ' + value1 + ', ' + value2 + ', ' + value3 + ', ' + value4);
// Call the original method and return the result
var result = this.setValue(value1, value2, value3, value4);
return result;
};
// Helper function to convert a byte array to a hex string
function bytesToHex(bytes) {
var hexArray = [];
for (var i = 0; i < bytes.length; ++i) {
var byteString = (bytes[i] & 0xff).toString(16);
hexArray.push(byteString.length === 1 ? '0' + byteString : byteString);
}
return hexArray.join('');
}
});
With this code, we have implemented hooks for all the overloads of the setValue
function. Each hook will log the inputs to the console, allowing us to capture the commands we’re interested in. This way, we can move forward with analyzing and emulating the captured commands.
To run Frida with the hooks and capture the output, execute the following command in the terminal:
frida -U -f com.xiaoyu.hlight -l bt_hooks.js
bt_hooks.js
is the filename of the JavaScript code containing the hooks and com.xiaoyu.hlight
is the package name of the HappyLighting
app.
Once the Frida script is running, you can test the functionality by turning the LED strip on and off using the app. The console output should display the captured commands.
In this case, we see that cc2333
is the command for turning on the LED strip, while cc2433
is the command for turning it off. The static parts cc
and 33
indicate some command indicator, and we can assume that 23
is for turning on the LED strip and 24
is for turning it off.
Hopefully, by sending these commands (cc2333
to turn on and cc2433
to turn off) to the LED strip ourselves, we can control its status accordingly.
To further explore the functionality and reverse-engineer the commands, let’s change the LED strip’s mode through the application and observe the corresponding commands. By switching between the “Rainbow pulsating” and “Red pulsating” modes multiple times, we can capture the commands associated with each mode.
After analyzing the captured commands, we can observe that bb260f44
corresponds to the “Rainbow pulsating” mode, while bb250f44
corresponds to the “Red pulsating” mode. From our previous understanding of the command structure, we can deduce that the bb
and 44
parts likely serve as command indicators.
However, we notice another part in the commands: 0f
. By further experimentation, specifically by adjusting the speed of the effect, we can observe that the 0f
portion changes accordingly. For example, 01
represents the maximum speed, while 1f
corresponds to the minimum speed.
Therefore, we can conclude that the 0f
portion of the command likely represents the speed parameter, with different values indicating various speed settings.
I believe we can wrap things up at this point since I think I have successfully demonstrated the concept I had in mind. Now, let’s proceed to the next section where we will develop a straightforward client application to control the LED strip.
Writing a Custom Client
To write a simple client, I opted for Python
as my preferred language since it’s the one I usually turn to when exploring new concepts. However, you are free to choose any programming language that you’re comfortable with.
Here’s the code:
import asyncio
from bleak import BleakClient
# Bluetooth device information
device_address = "92:3B:12:00:0D:B2" # MAC address of the device
characteristic_uuid = "0000ffd9-0000-1000-8000-00805f9b34fb" # UUID of the characteristic
# Payload in hex string format
payload = bytearray.fromhex("cc2333")
async def write_payload():
async with BleakClient(device_address) as client:
await client.is_connected()
# Write the payload to the characteristic
await client.write_gatt_char(characteristic_uuid, payload, response=False)
# Disconnect from the device
await client.disconnect()
# Run the write_payload coroutine
loop = asyncio.get_event_loop()
loop.run_until_complete(write_payload())
In the provided code snippet, the device_address
variable represents the MAC address of the Bluetooth device you want to connect to. It is a unique identifier assigned to each Bluetooth device. You should replace the device_address
value with the actual MAC address of your target device.
The characteristic_uuid
variable represents the UUID (Universally Unique Identifier) of the specific characteristic on the Bluetooth device that you want to interact with. Characteristics are attributes of a Bluetooth device that enable specific functionalities or data exchange. You should replace the characteristic_uuid
value with the actual UUID of the characteristic you intend to communicate with.
By knowing the MAC address and characteristic UUID, you can establish a connection with the Bluetooth device and utilize the corresponding characteristic to perform operations such as reading, writing, or subscribing to data.
There are multiple methods to obtain the MAC addresses and characteristics UUID of the target device. One approach is to write a simple code snippet using the bleak
library, while another option is to utilize Android applications such as Bluetooth Terminal
.
By following these steps, we have successfully achieved control over the LED strip using our custom client. While we could continue expanding the functionalities of our client, for the purpose of this blog post, it is sufficient to conclude our exploration here.
Conclusion
In conclusion, through our exploration, we have demonstrated the process of reverse engineering a communication protocol and controlling an LED strip. By utilizing the power of Frida, we were able to identify the relevant functions responsible for sending commands to the LED strip. By hooking these functions and capturing the command payloads, we gained insights into the communication protocol.
With this knowledge, we successfully developed a custom client that allows us to control the LED strip independently of the original mobile application. By sending the captured commands, we could turn the LED strip on and off, change its colors, and switch between different lighting modes.
It is important to acknowledge that achieving the desired outcome quickly is not always guaranteed in every reverse engineering scenario. The complexity of protocols and security measures can vary greatly, often necessitating more extensive analysis and reverse engineering efforts. However, in our case, the dynamic analysis approach we employed proved to be highly effective, significantly accelerating the process and saving us many hours of traditional reverse engineering work.
Overall, this post demonstrates the excitement and possibilities that arise from reverse engineering and taking control over IoT devices, opening up new avenues for customization and creativity.
I hope it was helpful. If you have any further questions, please feel free to reach out.


dgw - basegui - combobox - drawcanvas - hyperhelp - sbuttonbar - seditor - sfilebrowser - sfinddialog - sqlview - statusbar - tablelist - tlistbox - tvmixins - txmixins
dgw::combobox - snit widget derived from a ttk::combobox with added dropdown list and filtering
package require dgw::combobox
namespace import ::dgw::combobox
combobox pathName options
pathName configure -values list
pathName configure -hidenohits boolean
pathName configure -textvariable varname
dgw::combobox - is a snit widget derived from a ttk::combobox but with the added possibility to display the list of values available in the combobox as dropdown list. This dropdown list can further be filtered using the given options. If the user supplies the option -hidenohits false. He just gets the standard ttk::combobox
dgw::combobox pathName ?options?
Creates and configures the dgw::combobox widget using the Tk window id pathName and the given options.
As the dgw::combobox widget is derived from the standard ttk::combobox it interhits all options and methods from ttk::combobox. -hidenohits boolean
If hidenohits is set to true, non-matching list entries are not displayed in the dropdown listbox. Defaults to true.
As the dgw::combobox widget is dertived from the ttk::combobox, it has all methods available as a ttk::combobox, see the ttk::combobox manual from the description of the widget commands.
wm title . "DGApp"
pack [label .l0 -text "standard combobox"]
ttk::combobox .c0 -values [list done1 done2 dtwo dthree four five six seven]
pack .c0 -side top
pack [label .l1 -text "combobox with filtering"]
dgw::combobox .c1 -values [list done1 done2 dtwo dthree four five six seven] \
-hidenohits true
pack .c1 -side top
pack [label .l2 -text "combobox without filtering"]
dgw::combobox .c2 -values [list done1 done2 dtwo dthree four five six seven] \
-hidenohits false
pack .c2 -side top
Installation is easy you can install and use the dgw::combbox package if you have a working install of:
For installation of dgw::combobox just put the folder dgw in a folder belonging to your Tcl-library path
or put combobox.tcl as combobox-0.2.tm to a folder dgw which belongs to your Tcl-Module path.
The latter can be as well achieved using the -install option such as tclsh combobox.tcl --install
which will try to install dgw::combobox into your Tcl-module path.
Example code for this package can be executed by running this file using the following command line:
$ wish combobox.tcl --demo
The example code used for this demo can be seen in the terminal by using the following command line:
$ wish combobox.tcl --code
The script contains embedded the documentation in Markdown format. To extract the documentation you should use the following command line:
$ tclsh combobox.tcl --markdown
This will extract the embedded manual pages in standard Markdown format. You can as well use this markdown output directly to create html pages for the documentation by using the --html flag.
$ tclsh combobox.tcl --html
This will directly create a HTML page combobox.html
which contains the formatted documentation.
Github-Markdown can be extracted by using the --man switch:
$ tclsh combobox.tcl --man
The output of this command can be used to feed a markdown processor for conversion into a man page, a html or a pdf document. If you have pandoc installed for instance, you could execute the following commands:
# man page
tclsh combobox.tcl --man | pandoc -s -f markdown -t man - > combobox.n
# html page
tclsh ../combobox.tcl --man > combobox.md
pandoc -i combobox.md -s -o combobox.html
# pdf
pandoc -i combobox.md -s -o combobox.tex
pdflatex combobox.tex
The combobox widget was written by Detlef Groth, Schwielowsee, Germany.
Copyright (c) 2019 Dr. Detlef Groth, E-mail: detlef(at)dgroth(dot)de
Text search dialog widget dgw::combobox, version 0.2.
Copyright (c) 2019 Dr. Detlef Groth, E-mail: detlef(at)dgroth(dot)de
This library is free software; you can use, modify, and redistribute it for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions.
This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


{% extends "admin/layout.html" %} {% from "admin/_form_helpers.html" import render_actions %} {% block title %}{{ _('Write Result') if form.new else _('Edit Result') }}{% endblock %} {% block contents %}
{% trans %} Now that the war is over, please enter some details about it. {% endtrans %}


This permissions uses to check your current location for location reminder type. This application don't save or share Your location.
This permission used in call reminder types to make calls from application. Application don't call without Your acceptance.
This permission used in message reminder types for sending messages. Application can send message automatically but only if You enable it in settings.
This permission used for after call reminder, missed calls reminder and Quick SMS.
Used for getting birthdays from it or getting information for call or message reminder type.
This permission used for getting Your Google account to enable Google Drive and Google Task features.
This permission used for storing and getting events from system or Google calendar.
This permission used for making backup of application data.


The goal of coursedown is to create a template for course materials.
One folder (slides
) comprises of lecture slides written using xaringan
and is processed using RMarkdown into a mini-website, where the index.Rmd
would be a listing of lectures as well as any meta-data related to lectures.
One folder (notes
) comprises course notes (which may be derivative of the slides) built using bookdown
into a gitbook-formatted online book
One folder (assignments
) can hold homework assignments written in RMarkdown
The top folder creates the class website using RMarkdown, which can link to a Slack space for class collaboration, the GitHub repository for the course materials and various other pages (standard ones are provided for syllabus, instructor bio and other resources)
Building the web pages, presentations and course notes from R Markdown is monitored and controlled by drake.
The development version can be installed from GitHub with:
This is a basic example which shows you how to create a structured set of folders based on coursedown
:
library(coursedown)
create_course(slides = T, notes = T, hw = F)
add_slide('00-Introduction.Rmd')
slide2note('slides/00-Introduction.Rmd', outdir = 'notes')
# This creates basic notes from the corresponding slides. These can now be
# edited before processing
process()
This will create the website in the docs
folder. Opening docs/index.html
will give you access to the full website. You can also deploy this website using GitHub Pages
An example (in fact the first example) of this process can be seen for my BIOF 439 class being taught Spring 2019 at FAES Graduate School @ NIH. Follow the link


Ben Turok made sacrifices that helped SA attain freedom - Ramaphosa | IOL News
Johannesburg - President Cyril Ramaphosa and South African Communist Party (SACP) paid tributes to Prof Ben Turok following his passing on Monday.
Ramaphosa said he was deeply saddened by the passing of Struggle stalwart and former parliamentarian.
Professor Turok passed away at the age of 92.
Presidential spokesperson Khusela Diko said Ramaphosa offered his sincere condolences to Professor Turok’s spouse, Mary, and their children Ivan, Fred and Neil, Professor Turok’s friends, comrades and associates in South Africa and around the Continent and the international community.
“Professor Turok was the only surviving member of the original underground leadership of the South African Communist Party.


{% block head %}
EliteCircle
{% endblock %}
Forrex
App
calculate your risk
Home
risk calculation
purchease history
alerts
Support
About
{% block content %} {% endblock %}


groups=num_branches,
activation=(lambda: nn.PReLU(mid_channels)))
self.spp_dw = nn.ModuleList()
for i in range(num_branches):
dilation = dilations[i]
self.spp_dw.append(conv3x3(
in_channels=mid_channels,
self.branches = HierarchicalConcurrent()
for i in range(num_branches):
self.branches.add_module("branch{}".format(i + 1), conv3x3(
in_channels=mid_channels,
out_channels=mid_channels,
stride=stride,


layout: true class: inverse --- # .ps-title[Pythonic Interfaces] ### The secret to building maintainable, quality code! .invisible[-] .invisible[-] .invisible[-] .invisible[-] ## .ps-yellow[Praveen G Shirali] ### .ps-blue[PyCon India 2020] | .ps-orange[03rd October 2020] ### https://pshirali.github.io/pythonic-interfaces --- layout: false class: inverse # In this talk, we'll cover ### [1] .ps-blue[What is an interface?] ### [2] .ps-blue[Why is it important?] ### [3] .ps-blue[How to enforce interfaces?] ### [4] .ps-blue[Python3, 3rd-party libraries] ### [5] .ps-blue[How do I decide what to use?] --- layout: false class: inverse #.ps-title[[1/5] .ps-blue[What is an interface?]] --- layout: false class: inverse # An interface is defined as ... .invisible[-] ## a .ps-red[.underline[shared boundary]] across which ## .ps-yellow[.underline[two or more components]] .ps-green[.underline[share information]] .invisible[-] .invisible[-] .invisible[-] .invisible[-] #### Reference [1] --- layout: false class: inverse # A .ps-yellow[DataProcessor] class in an application ... .center[![](images/r0.png)] --- layout: false class: inverse # ... relies on another class to provide data .center[![](images/r1.png)] --- layout: false class: inverse # A .ps-yellow[FileIO] class reads & writes data to a file .center[![](images/r2.png)] --- layout: false class: inverse # The .ps-yellow[DataProcessor] calls the .ps-green[read] method .center[![](images/r3.png)] --- layout: false class: inverse # More IO classes need to be supported !! .center[![](images/r4.png)] --- layout: false class: inverse # .ps-yellow[MemIO] is similar to .ps-yellow[FileIO], but in-memory .center[![](images/r5.png)] --- layout: false class: inverse # .ps-yellow[DataProcessor] has clear requirements ... .center[![](images/r6.png)] --- layout: false class: inverse # Define a new interface class: .ps-yellow[ReadWriter] .center[![](images/r7.png)] --- layout: false class: inverse # .ps-yellow[FileIO] satisfies .ps-yellow[ReadWriter] interface .center[![](images/r8.png)] --- layout: false class: inverse # .ps-yellow[MemIO] satisfies .ps-yellow[ReadWriter] interface .center[![](images/r9.png)] --- layout: false class: inverse # Could any new .ps-yellow[IO] satisfy .ps-yellow[ReadWriter]? .center[![](images/r10.png)] --- layout: false class: inverse # A world without interface definition ... .center[![](images/r11.png)] --- layout: false class: inverse # Would you leave it to chance ? .center[![](images/r12.png)] --- layout: false class: inverse # Could .ps-yellow[ReadWriter] be enforced on all .ps-yellow[IOs]? .center[![](images/r13.png)] --- layout: false class: inverse # ... so that it errors on deviation? [1/5] .center[![](images/r14.png)] --- layout: false class: inverse # ... so that it errors on deviation? [2/5] .center[![](images/r15.png)] --- layout: false class: inverse # ... so that it errors on deviation? [3/5] .center[![](images/r16.png)] --- layout: false class: inverse # ... so that it errors on deviation? [4/5] .center[![](images/r17.png)] --- layout: false class: inverse # ... so that it errors on deviation? [5/5] .center[![](images/r18.png)] --- layout: false class: inverse # .ps-yellow[What does interface enforcement mean?] .invisible[-] ## Use code to verify that a .ps-blue[class adheres to an interface] ## If it doesn't, then the .ps-red[application raises errors] .invisible[-] ## Interface adherance is a .ps-green[requirement] for the application ## to either .ps-purple[start], or .ps-orange[run correctly]. --- layout: false class: inverse # .ps-yellow[What do we want to enforce?] ### [1] .ps-green[presence of required methods, correct names] ### [2] .ps-green[method signatures (arguments, order, type annotations etc)] ### [3] .ps-green[Descriptors/decorators (@staticmethod, @property etc)] ### [4] .ps-green[Special types: generator, coroutine functions (async) etc] ### [5] .ps-green[..may be more? (anything that improves quality)] --- layout: false class: inverse # In summary, the expectation is ... --- layout: false class: inverse .left-half[ # Interface ```python class DosaInterface: @classmethod def make(cls, masala=True):, pass @property def is_crispy(self) -> bool: pass def dip_in_chutney(self): pass def set_rating(self, r: int): pass async def repeat_order(self): pass ``` ] --- layout: false class: inverse .left-half[ # Interface ```python class DosaInterface: @classmethod def make(cls, masala=True):, pass @property def is_crispy(self) -> bool: pass def dip_in_chutney(self): pass def set_rating(self, r: int): pass async def repeat_order(self): pass ``` ] .right-half[ # Implementation 1 ```python class TiffinRoomDosa: @classmethod def make(cls, masala=True):, # implementation @property def is_crispy(self) -> bool: # implementation def dip_in_chutney(self): # implementation def set_rating(self, r: int): # implementation async def repeat_order(self): # implementation ``` ] --- layout: false class: inverse .left-half[ # Interface ```python class DosaInterface: @classmethod def make(cls, masala=True):, pass @property def is_crispy(self) -> bool: pass def dip_in_chutney(self): pass def set_rating(self, r: int): pass async def repeat_order(self): pass ``` ] .right-half[ # Implementation 2 ```python class StreetSideDosa: @classmethod def make(cls, masala=True):, # implementation @property def is_crispy(self) -> bool: # implementation def dip_in_chutney(self): # implementation def set_rating(self, r: int): # implementation async def repeat_order(self): # implementation ``` ] --- layout: false class: inverse .left-half[ # Interface ```python class DosaInterface: @classmethod def make(cls, masala=True):, pass @property def is_crispy(self) -> bool: pass def dip_in_chutney(self): pass def set_rating(self, r: int): pass async def repeat_order(self): pass ``` ] .right-half[ # Implementation 3 ```python class HighwayEateryDosa: @classmethod def make(cls, masala=True):, # implementation @property def is_crispy(self) -> bool: # implementation def dip_in_chutney(self): # implementation def set_rating(self, r: int): # implementation async def repeat_order(self): # implementation ``` ] --- layout: false class: inverse #.ps-title[[2/5] .ps-blue[Why is it important?]] --- layout: false class: inverse, middle # Example: An application's evolution ... .center[![](images/0.png)] --- layout: false class: inverse, middle # Components (/classes) interact ... .center[![](images/1.png)] --- layout: false class: inverse, middle # More get added, some get removed ... .center[![](images/2.png)] --- layout: false class: inverse, middle # Some components improve ... .center[![](images/3.png)] --- layout: false class: inverse, middle # The application gains maturity ... .center[![](images/4.png)] --- layout: false class: inverse, middle # Risk: some changes may break the app ... .center[![](images/5a_arrow.png)] --- layout: false class: inverse, middle # Ideal Scenario: plug & play w/o breaking .center[![](images/5b.png)] --- layout: false class: inverse # .ps-yellow[Benefits?] .invisible[-] ## With interfaces, applications have .ps-green[clear boundaries] ## They are .ps-blue[easier to maintain], and .ps-orange[less error prone] .invisible[-] ## With interface enforcement, some .ps-purple[errors can be prevented] ## as they are .ps-red[enforced] by the application, and .ps-yellow[detected early] --- layout: false class: inverse #.ps-title[[3/5] .ps-blue[Interface Enforcement]] --- layout: false class: inverse # Abstract Base Class ```python # ABCMeta is the enforcement mechanism # available as a **metaclass** # from abc import ABCMeta # decorate interface methods with `abstractmethod` decorator # from abc import abstractmethod ``` --- layout: false class: inverse # Abstract Base Class - Interface definition ```python from abc import ABCMeta, abstractmethod # ReadWriter is the interface definition # class ReadWriter(metaclass=ABCMeta): # <-- Class can have any name @abstractmethod def read(self, size: int = -1) -> str: pass @abstractmethod def write(self, data: str) -> int: pass ``` --- layout: false class: inverse # Abstract Base Class - Usage ```python # Concrete implementations derive from abstract base classes # class MemIO(ReadWriter): def read(self, size: int = -1) -> str: # actual implementation def write(self, data: str) -> int: # actual implementation if __name __ == "__main__": m = MemIO() # <--- Compliance is checked on instantiation ``` --- layout: false class: inverse # Abstract Base Class - Enforcement ```python class MemIO(ReadWriter): # missing `write` method implementation def read(self, size: int = -1) -> str: # actual implementation if __name __ == "__main__": m = MemIO() # <--- Compliance is checked on instantiation ``` ``` # ---- [output] ---- Traceback (most recent call last): File "{filename}", line {number}, in
m = MemIO() TypeError: Can't instantiate abstract class MemIO with abstract methods write ``` --- layout: false class: inverse # Abstract Base Class - Limitations ```python # ABCMeta does not enforce method signatures # class MemIO(ReadWriter): def read(self): # <--- incorrect signature # actual implementation def write(self): # <--- incorrect signature # actual implementation if __name __ == "__main__": m = MemIO() # <--- Does not raise errors ``` --- layout: false class: inverse # Abstract base classes can: ### [1] .ps-green[enforce presence of methods only by name] ### [2] .ps-green[enforce automatically on derived classes (via metaclass+inheritance)] # But! ### [1] .ps-blue[_abc_ is old. Python3 has evolved.] ### [2] .ps-blue[_abc_ design goals were/are different (ref(2): talk by Raymond Hettinger)] --- layout: false class: inverse #.ps-title[[4/5] .ps-blue[Python3 & libraries]] --- layout: false class: inverse # Python3 has: ### .ps-green[type annotation support, _async_] ### .ps-green[better typing, inspect library] .invisible[-] .invisible[-] .invisible[-] ### .ps-blue[Rich API definition capabilities] ### .ps-yellow[Methods can be defined in so many ways! .. Lets explore a few ...] --- layout: false class: inverse ## I pity the _foo_ ... ```python def foo(self): # name is the identifier def foo(self, a: int, b: float): # signature matters @property def foo(self): # not callable @foo.setter def foo(self, bar: bool): # assign. Don't call @staticmethod def foo(): # no 'self' @classmethod def foo(cls): # class as 1st argument def foo(self): yield # generator function async def foo(self): # coroutine function ``` --- layout: false class: inverse # What can we do with .ps-yellow[_inspect_] ? --- layout: false class: inverse # inspect.signature -- Usage ```python import inspect class MyIO: def read(self, size: int = -1) -> bytes: pass sig = inspect.signature(MyIO.read) # <------ `inspect.Signature` object ``` --- layout: false class: inverse # inspect.signature -- Comparison ```python def A(a:bytes, b:str, x: int = 10, y:int = 20) -> bool: pass def B(a:bytes, b:str, x: int = 10, y:int = 20) -> bool: pass >>> import inspect >>> inspect.signature(A) == inspect.signature(B) True ``` --- layout: false class: inverse # @property, data descriptors ... ```python class TestDD: # Data Descriptor Example Class @property # getter def my_prop(self): # same name pass @my_prop.setter def my_prop(self, x: int): # same name pass @my_prop.deleter def my_prop(self): # same name pass >>> inspect.signature(TestDD.my_prop) TypeError:
is not a callable object ``` --- layout: false class: inverse # @property, data descriptors ... ```python >>> import inspect >>> inspect.isdatadescriptor(TestDD.my_prop) True >>> prop_object = getattr(TestDD, "my_prop") ----------------------------------------------------------------------------- >>> getattr(prop_object, "fget") # getter >>> getattr(prop_object, "fset") # setter >>> getattr(prop_object, "fdel") # deleter ``` --- layout: false class: inverse # generator, coroutine functions ... ```python class GenCoro: def foo(self): yield async def bar(self): pass ----------------------------------------------------------------------------- >>> inspect.isgeneratorfunction(GenCoro.foo) True >>> inspect.iscoroutinefunction(GenCoro.foo) True ``` --- layout: false class: inverse # classmethod, staticmethod ... ```python # https://github.com/ksindi/implements/blob/master/implements.py # ::getobj_via_dict def getobj_via_dict(cls, name): for c in cls.__mro__: if name in c.__dict__: return c.__dict__[name] return None ----------------------------------------------------------------------------- >>> my_cls = getobj_via_dict(CSM, "my_cls") >>> isinstance(my_cls, (classmethod, types.ClassMethodDescriptorType)) True # just classmethod for PY < 3.7 >>> my_stat = getobj_via_dict(CSM, "my_stat") >>> isinstance(my_stat, (staticmethod, types.BuiltinMethodType)) True ``` --- layout: false class: inverse ## .ps-yellow[Revisit:] I pitied the _foo_ ... ```python ✓ def foo(self): # name is the identifier ✓ def foo(self, a: int, b: float): # signature matters @property ✓ def foo(self): # not callable @foo.setter ✓ def foo(self, bar: bool): # assign. Don't call @staticmethod ✓ def foo(): # no 'self' @classmethod ✓ def foo(cls): # class as 1st argument ✓ def foo(self): yield # generator function ✓ async def foo(self): # coroutine function ``` --- layout: false class: inverse # Some 3rd party libraries ... ### implements - simple, supports py3.6+ only, composition over inheritance - https://pypi.org/project/implements/ ### python-interfaces - supports py2 & py3, uses metaclasses - https://pypi.org/project/python-interface/ ### zope.interface - version 5 now, lots of features - https://pypi.org/project/zope.interface/ --- layout: false class: inverse #.ps-title[[5/5] .ps-blue[How to choose?]] --- layout: false class: inverse # Composition vs Inheritance .left-half[ Example: `implements` 1. clean wrapper 2. explicit ```python @implements(IFace) class MyClass: ... ``` ] .right-half[ Example: `python-interface`, `abc` 1. inheritance + metaclass driven 2. implicit ```python # abc: Interface inherits from abc.ABCMeta class MyClass(metaclass=IFace): ... # python-interface class MyClass(implements(IFace)): ... ``` ] --- layout: false class: inverse # Early vs Late enforcement .left-half[ ### Early (better) Example: `implements`, `python-interface` 1. Enforced on import/class-creation 2. Discover errors soon ```python @implements(IFace) # << checked! class MyClass: ... ``` ] .right-half[ ### Late Example: `abc` 1. Enforced on instantiation. 2. Code path dependent ```python # abc: Interface inherits from abc.ABCMeta class MyClass(metaclass=IFace): ... m = MyClass() # << checked here ``` ] --- layout: false class: inverse # Recap ### [1] .ps-green[Defining interfaces is good. Enforcing is even better!] ### [2] .ps-green[Py3: 3rd party libraries have better support than _abc_] ### [3] .ps-green[_inspect_ is powerful! Do more with it] ### [4] .ps-green[With enforcement, lean on finding errors early] --- layout: false class: inverse # References #### [1] Wikipedia: Interface: https://en.wikipedia.org/wiki/Interface_(computing) #### [2] R. Hettinger @ PyCon Russia 2019: https://www.youtube.com/watch?v=S_ipdVNSFlo # Further Reading #### [1] https://realpython.com/python-interface/ #### [2] https://realpython.com/inheritance-composition-python/ #### [3] https://www.youtube.com/watch?v=F4wUrj6pmSI -- Understanding Go Interfaces (by Francesc Campoy). Great talk to understanding interfaces conceptually (though it is explained in the context of Golang). --- layout: false class: inverse # Open for Q&A, Discussion & Feedback Let me know if you've faced hurdles with interfaces. How have you solved them? Has this talk been helpful? How can we improve this further? ## Praveen G Shirali - Email<EMAIL_ADDRESS>- `pshirali` on BangPypers Slack - https://linkedin.com/in/praveenshirali - https://github.com/pshirali - I'm .underline[not] on Twitter ## Link to this talk - https://pshirali.github.io/pythonic-interfaces


Updating Question and gear Release timing (just read)
Posted: Wed Dec 27, 2006 1:13 pm
Theres alot of concern about item rareity and values and so on....
This topic doesn't deal with that. It does however address the updating situation.
Are you going to release Mystic, Spirit, Ominex, Diabolic seperately? These gears obviously weren't added into the game at one time. They were spread out over the course of time. Mystic first, months later came spirit, maybe a year or two came Ominex. Will Pro. Volc. start Xenimus and the very end of the gear spectrum, starting with crap...and eventually after a while new gears will be added unannounced. This, of course, is how EJ did it. I encourage this method of updating.
Similarly, will the Xenimus landscape receive similar timing in it's updates? First continent, second....and so on. T1, t2, t3, t4.....yadda yadda. These towns are labeled such by when they were introduced into Xenimus. How are you going to address this?
Those of us from the beginning remember the mystery of the next batch of updated gear. Spirit was basically unheard of, I myself only learning of it from Wrath. We almost never saw these gears - only existing in the hands of two or three - and sometimes not at all. I know they kept some gear locked up and a mystery.
Anyways, enough memories. The key here is updating, mystery, unannounced batches of gears and towns and continents. What are your plans?
This topic doesn't deal with that. It does however address the updating situation.
Are you going to release Mystic, Spirit, Ominex, Diabolic seperately? These gears obviously weren't added into the game at one time. They were spread out over the course of time. Mystic first, months later came spirit, maybe a year or two came Ominex. Will Pro. Volc. start Xenimus and the very end of the gear spectrum, starting with crap...and eventually after a while new gears will be added unannounced. This, of course, is how EJ did it. I encourage this method of updating.
Similarly, will the Xenimus landscape receive similar timing in it's updates? First continent, second....and so on. T1, t2, t3, t4.....yadda yadda. These towns are labeled such by when they were introduced into Xenimus. How are you going to address this?
Those of us from the beginning remember the mystery of the next batch of updated gear. Spirit was basically unheard of, I myself only learning of it from Wrath. We almost never saw these gears - only existing in the hands of two or three - and sometimes not at all. I know they kept some gear locked up and a mystery.
Anyways, enough memories. The key here is updating, mystery, unannounced batches of gears and towns and continents. What are your plans?


--- layout: default title: Sponsors and Supporters ogtitle: mHACKeroni - Sponsors ogdescription: mHACKeroni is the result of 5 CTF Italian teams which have merged to sum their streghts and ultimately try to achieve DEFCON CTF Finals qualification. ---
We thank all the sponsors and supporters that made it possible for the mHACKeroni team to take part in the DEF CON 26 CTF finals in Las Vegas in August 2018, contributing to the success of our team!


Another way to create environment mapping is through equirectangular images. So, instead of using 6 images to compose a textured cube, only one image is required.
Image Credit: M. Cabral/ESO - Open project in a new tabIn short, an equirectangular image is a panoramic 360° image with ratio 2:1 like the one presented in Figure 1. An equirectangular image is a simple way of representing a spherical object as a flat 2D image. Equirectangular images are very common nowadays and there are several repositories to download from like this one .


Multiple models support.
|
|
__init__(self,
model_id=1,
**args)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature |
source code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__len__(self)
Returns the number of stored Chain objects. |
source code
|
|
|
|
__getitem__(self,
chain_idx)
Same as get_chain, but raises KeyError if the requested chain_id is
not found. |
source code
|
|
|
|
__iter__(self)
Iterates the Chain objects in the Model. |
source code
|
|
|
|
__contains__(self,
chain_idx)
Returns True if the argument Chain or chain_id is in the Model. |
source code
|
|
|
|
index(self,
chain)
Returns the numeric index of the Chain object in the Model. |
source code
|
|
|
|
sort(self)
Sorts all Chains in the Model by their chain_id. |
source code
|
|
|
|
add_chain(self,
chain,
delay_sort=False)
Adds a Chain to the Model. |
source code
|
|
|
|
remove_chain(self,
chain)
Removes the Chain from the Model. |
source code
|
|
|
|
get_chain(self,
chain_id)
Returns the Chain object matching the chain_id character. |
source code
|
|
|
|
iter_chains(self)
Iterates over all Chain objects in alphabetical order according to
their chain_id. |
source code
|
|
|
|
count_chains(self)
Counts all Chain objects. |
source code
|
|
|
|
add_fragment(self,
fragment,
delay_sort=False)
Adds a Fragment instance |
source code
|
|
|
|
remove_fragment(self,
fragment)
Removes a Fragment object. |
source code
|
|
|
|
count_fragments(self)
Counts all Fragment objects. |
source code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remove_atom(self,
atom)
Removes an Atom object. |
source code
|
|
|
|
iter_atoms(self)
Iterates over all Atom objects according to the Structure defaults. |
source code
|
|
|
|
count_atoms(self)
Counts all Atom objects in according to the Structure defaults. |
source code
|
|
|
|
iter_all_atoms(self)
Iterates over all Atom objects including all atoms in multiple
conformations. |
source code
|
|
|
|
count_all_atoms(self)
Counts all Atom objects including all atoms in multiple
conformations. |
source code
|
|
|
|
get_equivalent_atom(self,
atom)
Returns the atom with the same fragment_id and name as the argument
atom, or None if it is not found. |
source code
|
|
|
|
add_alpha_helix(self,
alpha_helix)
Adds an AlphaHelix object to the Model. |
source code
|
|
|
|
remove_alpha_helix(self,
alpha_helix)
Removes an AlphaHelix object from the Model. |
source code
|
|
|
|
iter_alpha_helicies(self)
Iterates over all AlphaHelix objects in the Model. |
source code
|
|
|
|
add_beta_sheet(self,
beta_sheet)
Adds a BetaSheet object to the Model. |
source code
|
|
|
|
remove_beta_sheet(self,
beta_sheet)
Removes a BetaSheet object from the Model. |
source code
|
|
|
|
iter_beta_sheets(self)
Iterate over all child BetaSheet objects in the Model. |
source code
|
|
|
|
add_site(self,
site)
Adds a Site (of interest) object to the Model. |
source code
|
|
|
|
remove_site(self,
site)
Removes a Site (of interest) object from the Model. |
source code
|
|
|
|
iter_sites(self)
Iterate over all active/important sites defined in the Structure. |
source code
|
|
|
|
get_structure(self)
Returns the parent Structure. |
source code
|
|
|
|
|
|
|
|
|
|
set_model_id(self,
model_id)
Sets the model_id of all contained objects. |
source code
|
|
|
Inherited from object :
__delattr__ ,
__format__ ,
__getattribute__ ,
__hash__ ,
__new__ ,
__reduce__ ,
__reduce_ex__ ,
__repr__ ,
__setattr__ ,
__sizeof__ ,
__subclasshook__
|


Residual Generation for a MAVLink UAV¶
This demo showcases the usage of fault-diagnosis to perform FDI in MAVLink-enabled fixed-wing UAVs.
We shall present step-by-step the procedure which involves:
- Generation of the Structural Model
- Extraction of PSOs for maximum fault isolation
- Finding valid matchings for each subgraph
- Implementation of every residual generator
- Calculation of the residuals using a stored log
Generation of the Structural Model¶
The MAVLink protocol is a standardized message format for use in unmanned vehicles. It is mostly intented for aerial vehicles, but is not limited to them. Its robust description allows for a fixed interface between such a vehcile and a generic FDI module.
Let us construct a structural graph which reflects a MAVLink-enabled fixed-wing UAV.
The corresponding model in the GraphPool
folder is g033
.

Each MAVLink message ID is stated. However, messages which convey state information (e.g. ID=0:Heartbeat) cannot be handled by our Parity-Space-based approach and are ommited. The same holds for event-triggered messages (e.g. any mission-related message).
The rest of the measurements are assigned a fault each and their analytical expressions are provided. Additionally, each measurement equation is assigned to a subsystem, for later classification.
If only the information conveyed through MAVLink was used, then only hardware redundancy cross-checking would be possible. Instead, we add a set of equations which hold for all fixed-wing UAVs and act as the “glue” among the measurements.
These equations can act as:
- First-principles models
- Limit-checking
- Implicit equalities
Naturally, since these equations are meant to be portable from UAV to UAV, they shouldn’t need any airframe-specific parameters.
% First-principles equations
kin = [...
{'climb v_d expr -climb-v_d'};...
{'v_ground ni v_n ni v_e expr -v_ground+sqrt(v_n^2+v_e^2)'};...
{'dot_p_n v_n expr equal'};...
{'dot_p_e v_e expr equal'};...
{'dot_p_d v_d expr equal'};...
{'v_w_n ni dir_wind ni v_wind_hor expr -v_w_n+v_wind_hor*cos(dir_wind)'};...
{'v_w_e ni dir_wind ni v_wind_hor expr -v_w_e+v_wind_hor*sin(dir_wind)'};...
{'ni cog ni v_e ni v_n expr -tan(cog)+v_e/v_n'};...
{'v_air press_diff par rho expr -press_diff+0.5*rho*v_air*v_air'};...
{'v_air ni v_ground ni v_wind_hor ni cog ni dir_wind expr -v_air+sqrt(v_ground^2+v_wind_hor^2-2*v_ground*v_wind_hor*cos(dir_wind-cog))'};...

];
Extraction of PSOs for maximum fault isolation¶
The structural_analysis()
routine bears the majority of the Structural Analysis work. After instantiating the initial structural graph object, it finds its overconstrained part, to limit the scope of the ensuing analysis.
The next important step is to break down the structural graph into its Weakly Connected Components (WCCs). If such a partitioning exists, it can greatly accelerate the analysis. Indicatively, the initial MAVLink model is of large size and also has a large structural redundancy degree of 59. It potentially could contain up to 9.4x10e21 residual generators, a number which is intractable.
Instead, the initial model can be broken down to 34 subgraphs, which can yield up to 7952 residual generators, a much more amenable number.
graphs_conn = getDisconnected(graphRemaining); % Get the Weakly Connected Components
A typical structural subgraph looks like
The MTES [1] algorithm is used to extract all the minimum structurally overdetermined sets of equations.
sg.buildMTESs(); % Use the LiUSM algorithm to find the MTESs
ResGenSets = sg.getMTESs(); % Get the equations sets corresponding to the MTESs
Then, a new structural graph is generated for each MTES, in order to be examined separately.
SOSubgraphs(i) = sg.buildSubgraph(ResGenSets{i}, 'pruneKnown', true, 'postfix', postfix);
One of the PSOs extracted from the previous subgraph is
Known input variables are ommited without loss of generality.
Finding valid matchings for each subgraph¶
Next, a matching procedure is applied to each Proper Structurally Overconstrained subgraph (PSO). The goal is to take advantage of the graph-based encoding of each PSO and employ graph-based methods to discover a matching which represents a valid sequence of calculations leading to the evaluation of a residual generator.
Older matching algorithms, such as the Ranking Matching [2] and the efficient Hungarian algorithm and its derivatives [3], are not a suitable option for this task. They have multiple deficiencies, such as the inability to cope with calculation loops or ensuring the realisability [4] of the resulting matching.
For the above reasons, we employ our own Branch and Bound Integer Linear Programming (BBILP) matching algorithm.
[...]
disp('Examining another SO graph')
tempGI = SOSubgraphs(index);
matchers(i) = Matcher(tempGI); % Instantiate the matcher for this SO
[...]
matching = matchers(i).match('BBILP','branchMethod',branchMethod);
If there exists one, the valid matching is used to fully direct the PSO, embedding the residual calculation order.
The matched and directed PSO from the previous section is presented below:
The white rectangle to the right represents an unmatched equation which will serve as a residual generator.
We can perform Isolability Analysis in this stage. We gather all the structural residuals, note which faults are introduced in which residuals and generate the Fault Signature Matrix.
As we can see, its structure is mostly diagonal, meaning that all faults are (structurally) isolable, with a single-fault assumption. The non-singular diagnoal elements represent blocks of faults which are not distinguishable from each other, due to lack of surplus information.
Only 6 faults are non-detectable.
Implementation of every residual generator¶
We can now proceed with implementing each structural residual generator and obtain a numerical function, able to process measured data.
The analytical expression of each equation was passed during the construction of the model and stored alongside the equation. Now, the Symbolic Toolbox of MATLAB is employed to solve each equation for the specified variable (according to the matching) and use the rest of the equations as arguments.
The function get_res_gens
is responsible for this task:
RG_results = get_res_gens(SA_results, RG_settings);
The edges of the matching are converted to a fully-ordered evaluation list, through knowledge propagation from inputs to the residual generator equation.
%% Propagate knowledge from inputs to outputs
knownVarIds = [];
unusedIndices = 1:length(SCCsEquIds); % Indices to the equations SCCs cell array
% Build an active list of equations which are ready to be solved
activeList = []; % This contains indices to SCCsEquIds
for i=unusedIndices
unknownVariables = setdiff(SCCsVarIds{i},knownVarIds);
if isequal(sort(unknownVariables),sort(SCCsMatchedVarIds{i}))
activeList(end+1) = i;
end
end
solutionOrder = {};
while ~isempty(activeList)
unusedIndices = setdiff(unusedIndices, activeList); % Do not look in equations already in the list
% Pop an item
currentIndex = activeList(1);
solutionOrder(end+1) = SCCsEquIds(currentIndex);
activeList(1) = [];
% Update the known variables list
knownVarIds = [knownVarIds SCCsMatchedVarIds{currentIndex}];
% Search for new solvable equations to populate the list
for i=unusedIndices
unknownVariables = setdiff(SCCsVarIds{i},knownVarIds);
if isempty(unknownVariables) % This SCC can be solved
activeList(end+1) = i;
end
if isequal(sort(unknownVariables),sort(SCCsMatchedVarIds{i})) % This SCC has unknown variables but it will match all of them
activeList(end+1) = i;
end
end
end
NOTE: Any Strongly Connected Components (SCCs) existing in the matched subgraph will break the propagation process. Thus, during propagation they are compacted into single equation-variable pairs to allow the process to continue. Later, they each will be treated as a unified equation system during the implementation process, anyway.
Each equation is turned into an Evaluator
object
obj.evaluators_list = create_evaluators(graphInitial, matched_graph, SCCs, values, obj.dt);
[...]
new_evaluator = Evaluator(gi, sub_digraph, scc, dictionary);
which may be inherited by
new_evaluator = Differentiator(gi, sub_digraph, scc, dictionary, dt);
new_evaluator = DAESolver(gi, sub_digraph, scc, dictionary, dt);
depending on the nature of each equation; whether it is a single equation, an explicit integration/differentiation or an SCC representing a Differential-Algebraic Equation set (DAE).
The equation is solved symbolically once during setup and a numerical function is created. In this manner each subsequent evaluation (e.g. during log parsing) will be as fast as possible.
obj.expressions_solved = vpasolve(obj.expressions, obj.sym_var_matched_array); % Store the pre-solved expressions
[...]
obj.expressions_solved_handle = matlabFunction(obj.expressions_solved, 'Vars', obj.sym_var_input_array, 'Outputs', obj.gi.getAliasById(obj.var_matched_ids));
108 residual generator functions were created in this fashion.
Calculation of the residuals using a stored log¶
We have reached a point where we are able to pass a MAVLink log to our algorithm to perform fault diagnosis in real measured data. Our example log file was taken during a mapping mission, performed by a 2m UAV. The UAV experienced sudden loss of control and fell into the ground.
The log is initially converted to an .m
file with the mavtomfile.py
Python script, provided by pymavlink.
Then, the log file is resampled at a constant rate, which is user selectable. Most MAVLink messages are emitted regularly at 1, 2 and 4Hz. We select 1Hz for our analysis. We can also restrict the examination interval to the last few seconds of the flight.
data_resampled = resampleData('afrika.mat', SA_results); % Read the dataset and resample it to have uniform data
Now the data is in a form that can be fed into each residual generator and obtain residual signals. Thresholding is also performed against a constant value (different for each residual).
RE_results = evaluateResiduals(SA_results, RG_results, data_resampled); % Evaluate the residual generator bank
[...]
interval_of_interest = [317:333]; % Select the sample interval you wish to investigate
triggering_threshold = 0.97; % Specify a static threshold
% Threshold the residual signals
triggered_residuals = thresholdResiduals(RE_results, interval_of_interest, triggering_threshold);
The result is a binary residual trigger signal, at the resolution of 1 second. One such signal is generated for each residual generator.
We do not make the single-fault assumption, because in tightly-coupled systems, such as a UAV, one fault can easily cause inconsistencies to other neighbouring subsystems. Still, the known fault signatures can be used to exclude which faults are certain to not have happened (using the exoneration assumption).
This information lets us construct the Fault Occurrence Grid. This visualization pattern is a powerful investigation tool, which can help the human investigator have a better picture of the manifested faults and make time correlations.
Loss of control occurred at t = 322 seconds. Even before the failure time, we notice a few faults triggering certain residuals. Faults corresponding to 24/lon, 30/yawspeed, 33/lon, 116/zgyro, 182/lat and 182/lng are probably caused by inconsistencies between the direct measurements of the sensors related to the navigation system and the 3 different navigation algorithms which ArduPilot runs simultaneously.
More concerning is the departure from the airspeed envelope and the airspeed error, occurring at time t = 321 seconds - 325 seconds, as witnessed by the faults 62/airspeed_error and 74/airspeed. Plotting the actual airspeed data series we see a significant drop in airspeed at that interval.
At the same interval we see residuals related to 3 state control faults trigger. These faults refer to altitude, pitch and roll regulation. In fact, these faults affect only one residual each and are hence isolable. Indeed, plotting the roll, pitch and altitude time series, we clearly see that the aircraft has by now entered a downward spiral, leading to the crash. Even though the airspeed recovered a few seconds after the initial stall, the autopilot was not able (nor programmed) to perform the maneuver required to exit the spiral.
It is interesting to note that a lot of residuals related to faults of the sensor and navigation subsystems triggered during the downward spiral. This can be attributed to the separate state estimation filters underperforming because of the rapid rotation and producing diverging estimates.
Regarding the root cause of the accident, we can safely rule out airspeed estimation, since the related residuals did not trigger. Instead, the first severe failure was the inability of the autopilot to maintain the airspeed error within a +-3m/s bound. This allowed the airspeed to drop below its prescribed envelope, resulting in a tip-stall. Past that point, the autopilot was no longer able to control the state of the aircraft.
The inability of the autopilot to regulate airspeed should probably not be attributed to an external fault. Instead, it is much more likely that the kinetic energy control loop was badly tuned, especially taking into account the high Mean-Sea-Level altitude the aircraft was flying at. However, further investigation would require analysis of the internal structural of the controller architecture and implementation, and such information is not conveyed by the MAVLink stream.
References
| [1] |
|
| [2] |
|
| [3] |
|
| [4] |
|


Assure that all controls are flush at the top and bottom. Pay special attention to the Submit button.