Login| Sign Up| Help| Contact|

Patent Searching and Data


Title:
METAL DETECTING SYSTEM
Document Type and Number:
WIPO Patent Application WO/1991/003746
Kind Code:
A1
Abstract:
A metal detection station capable of detecting tiny metal pieces unlawfully concealed on persons moving through the station is disclosed. The station comprises a transmitting coil, receiving coils, field shaping coils, field shielding coils, shielding plates, receiver balancing coils, and a computer based console employing software to digitize, analyze, display, and store the detected signals.

Inventors:
GHENT HUGH W (CA)
Application Number:
PCT/CA1990/000286
Publication Date:
March 21, 1991
Filing Date:
September 07, 1990
Export Citation:
Click for automatic bibliography generation   Help
Assignee:
CA ATOMIC ENERGY LTD (CA)
International Classes:
G01V3/10; G01V3/11; (IPC1-7): G01V3/10
Foreign References:
US4821023A1989-04-11
DE2837265A11980-03-06
EP0300974A11989-01-25
EP0308073B11994-07-13
Download PDF:
Claims:
THE EMBODIMENTS OF THE INVENTION IN WHICH AN EXCLUSIVE PROPERTY OF PRIVILEGE IS CLAIM
1. ED ARE DEFINED AS FOLLOWS: A method of detecting concealed metals comprising the steps of: generating a fluctuating electromagnetic field about a passageway; passing a person or object through said passageway; obtaining an electrical signal representative of said electromagnetic field as said person or object passes through said passageway; comparing the values of predetermined characteristics of said electrical signal against the corresponding values of said characteristics of a base electrical signal for said person or object previously obtained when said person or object was known not to contain concealed metals; and generating an alarm signal when the differences between at least one of said characteristics signals exceeds a predetermined threshold.
2. A method as defined in claim 1, said producing step including processing said electrical signal to determine quantitative values for each of said characteristics of said signal and said comparing step including comparing said quantitative values against corresponding base values of said characteristics for said person or object previously obtained when said person or object was known not to contain concealed metals.
3. A method as defined • in claim 2, said processing step including demodulating said electrical signal to produce a first signal representative of the resistive component of said electromagnetic field and a second signal representative of the reactive component of said electromagnetic field.
4. A method as defined in claim 3, said processing step including the steps of: determining the magnitude of each said first and second signals at predetermined increments of time; determining the maximum amplitude of each of said first and second signals; deteπnining an overall differential phase angle between said first and second signals; determining an intermediate differential phase angle between said first and second signals; and determining a differential phase angle for each of a plurality of different positions of said person or object in said passageway.
5. An apparatus for detecting concealed metals on a person or object, comprising: means for generating an electromagnetic field about a passageway; means for producing an electrical signal representative of said electromagnetic field as said person or object passes through said passageway; and means for comparing the values of predetermined characteristics of said signal against corresponding values representative of an electrical calibration signal obtained when said person or object was known not to contain concealed metals; and means for generating an alarm signal when the differences between the values of at least one of said characteristics of said signals exceeds a predetermined threshold.
6. An apparatus as defined in claim 5, said producing means including means for demodulating said electrical signal to produce a first signal representative of the resistive component of said electromagnetic field and a second signal representative of the reactive component of said electromagnetic field.
7. An apparatus as defined in claim 6, said producing means being operable to determine the magnitude of each said first and second signals at predetermined increments of time, the maximum amplitude of each of said first and second signals, an overall differential phase angle between said first and second signals, an intermediate differential phase angle between said first and second signals, and a differential phase angle for each of a plurality of different positions of said person or object in said passageway.
8. An apparatus as defined in claim 5, said means for generating an electromagnetic field about a passageway including a transmit coil extending about said passageway with an axis extending longitudinally through said passageway and means for producing an alternating current at a predetermined frequency within said coil so as to form said magnetic field about said coil.
9. An apparatus as defined in claim 8, said means for producing an electrical signal including a pair of receive coils about said passageway and coaxiaUy spaced apart on opposite sides of said transmit coil, said receive coils having a common terminal and output terminals and being responsive to a changing magnetic field within said passageway to produce alternating voltages across said receive coils.
10. An apparatus as defined in claim 9, further including an amplifier having input terminals connected to said output terminals of said receive coils and an output terminal for producing said electrical signal.
11. An apparatus as defined in claim 10, further including means for producing and matching a reference signal to said electrical signal from said receive coils and means for obtaining a difference signal which is the difference between the amplified receive coil output signal and said reference signal.
12. An apparatus as defined in claim 11, further including a demodulator for receiving said differential signal and producing first and second output signals representative of the resistive and reactive components of said differential signal.
13. An apparatus as defined in claim 12, further including converter means for converting first and second output signals to first and second digital output signals, respectively.
14. An apparatus as defined in claim 13, further including computation means for processing said first and second digital output signals to determine the values of predetermined characteristics of thereof and compare said values against predetermined calibration values of said characteristics representative of said person or object.
15. An apparatus as defined in claim 14, said computation means being operable to determine the magnitude of each said first and second signals at predetermined increments of time, the maximum amplitude of each of said first and second signals, an overall differential phase angle between said first and second signals, an intermediate differential phase angle between said first and second signals, and a differential phase angle and signal magnitudes for each of a plurality of different positions of said person or object in said passageway.
16. An apparatus as defined in claim 10, further including means for reducing the effect of objects moving in said passageway in close proximity to said receive coils.
17. An apparatus as defined in claim 16, said reducing means including field shaping coil means associated with said receive coil means and responding to the magnetic field in the vicinity thereof by inducing an additional magnetic field in said station whereby voltages induced in the receive coil means are substantially influenced by currents flowing in the associated field shaping coil means.
18. An apparatus as defined in claim 17, wherein further including means for maintaining said additional magnetic field in an selected outofphase relationship with respect to the magnetic field generated by said transmit coil means.
19. An apparatus as defined in claim 5, further including a portal unit defining said passageway through which the person moves with said coil means being coaxially located with respect to each other in planes generally perpendicular to the axis of the passageway along which the person moves.
20. An apparatus as defined in claim 18, said field shaping coil means comprising a pair of field shaping coils, each located adjacent to a respective one of said receive coils.
21. An apparatus as defined in claim 10, further including capacitor means connected to said common terminal to produce a resonant condition between said receive coils during operation such that as the voltage in one receive coil increases the voltage in the other decreases so the net voltage across both receive coils is substantially zero when there said passageway is empty.
22. An apparatus as defined in claim 10, further including means to zero or null any induced unbalanced voltages across the receive coils arising from coil winding inaccuracies and the like.
23. An apparatus as defined in any of the preceding claims, further including ferromagnetic shielding means located and arranged to reduce or eliminate eddy currents and resulting magnetic field disturbances arising in materials exterior to the detecting station.
24. An apparatus as defined in any of the preceding claims, further including field shielding coil means spaced outwardly from the receive coil and field shaping coil means and arranged such that currents induced in the field shielding coils by the fluctuating magnetic fields in the station create still further magnetic fields which act to reduce the strength of magnetic fields extending outwardly away from the detecting station.
25. For use in a metal detecting system wherein a person capable of carrying concealed metal pieces is caused to pass through a detecting station within which a rapidly fluctuating magnetic field exists and means are provided to sense changes in the magnetic field resulting from passage of the person's body and any metals carried thereon, the calibration method substantially as described with reference to Figure 6.
26. For use in a metal detecting system wherein a person capable of carrying concealed metal pieces is caused to pass through a detecting station within which a rapidly fluctuating magnetic field exists and means are provided to sense changes in the magnetic field resulting from passage of the person's body and any metals carried thereon, the detection method substantially as described with reference to Figure 7.
Description:
- .-

METAL DETECTING SYSTEM

REFERENCE TO APPENDIX

A computer program used in accordance with the present invention is shown in the Appendix.

BACKGROUND OF THE INVENTION

The present invention relates, in general, to a metal detection system and, more specifically, to a method and an apparatus capable of detecting tiny metal pieces which may be unlawfully concealed on a person's body.

Industries involved with precious metals including precious metal refineries, mints, jewellery manufacturers and the like require a detecting apparatus which is capable of quickly and efficiently detecting small quantities of precious metals which may be unlawfully concealed on the person of an individual.

Many devices have been developed for detecting metals in the ground and elsewhere. However, such devices are intended to locate relatively massive concentrations of metal in static environments and, frequently, they are designed to exclude signals produced by small amounts of metal. For these and other reasons, metal detectors of this type are not suitable for screening individuals for concealed precious metals.

There also exists a number of metal detecting stations for detecting concealed firearms at airports, public offices, embassies, jails, and even hospitals. They are typically characterized by a portal unit which defines a passageway through which a person is required to pass. Electrical coils extend vertically in parallel relation around the portal unit with one coil, a transmitting coil, being energized by an alternating current to cause it to generate a magnetic field which in turn causes an electrical signal to be induced in the other coils, the receiving coils. Relatively massive metal objects, such as a gun, passed through the unit disturb the magnetic and hence the signals induced in the receive coils. Thus, the output of the coils are monitored to detect such disturbances. Heytow United States Patent No. 4,012,690 granted on March 15, 1977 and Mallick et al United States Patent No. 3,686,564 granted on August 22, 1972 describe devices of this type.

All the metal detecting stations, including those disclosed in the referenced patents, currently known to the inventor use electromagnetic principles. Generally, as indicated above, a transmitting coil connected to an electrical current driving unit is used to generate a time changing magnetic field and receiver coils are used to detect changes in the magnetic field. The changes in the magnetic field occur when either eddy currents are generated in conducting materials brought into the vicinity of the station or when ferromagnetic materials are brought near the station. Most ferrous material exhibit both effects - the eddy current and ferromagnetic effects. The extent to which the magnetic field is changed depends upon many factors including electrical conductivity, magnetic permeability, shape, size, structural properties, density, orientation and location relative to the transmitting coil. The human body is known to be a poor electrical conductor and has slight ferromagnetic properties. Due to the relatively large size of the human body a small but significant change occurs in the magnetic field of these stations when a person passes through. It has been found that, because the signal strength associated with a person is so much stronger than the signal strength associated with a small quantity of a precious metal, such stations are not inherently designed to detect the small quantities of metal as required in industries involved with precious metals including precious metal refineries, mints, jewellery manufacturers and the like.

Kerr United States Patent No. 4,719,421 granted on January 12, 1988 discloses a metal detector for detecting impurities in bakery products and comprises a transmit coil positioned between a pair of receive coils, as in the above referenced prior art, and circuitry which responds to deviation form a standard signal by generating a faulty product signal. The system can be set to distinguish between different types of loaves of bread. This arrangement suffers from the same difficulty mentioned earlier, that being that the size of the human body is so much larger than the small quantity of material it is difficult to distinguish signals associated with the small quantity of material from those associated with the individual carrying the material. Further, characteristics such as the size, shape, density and so forth of human body vary greatly from person to person and, accordingly, it is not possible to categorize humans in the manner

in which loaves of bread can be categorized, and to provide preset values as proposed by Kerr against which the output of the receive coils can be compared.

In summary, known metal detection devices do not specifically address the special problems associated with detecting concealed precious metal on humans or objects and to provide a permanent record of a violation when such is detected.

SUMMARY OF THE INVENTION

The principal object of this invention is to provide a means for detecting the smallest quantity of metal possible being transported, typically unlawfully and usually concealed, by persons passing through a detection station. It is a further object of the present invention to provide a detection system and process whereby the signal is obtained and can be displayed in a graphical form in order to demonstrate, in a court of law if necessary, the signal obtained from an individual passing through the metal detector. The metal detector described hereafter has the capability of detecting significantly smaller quantities of metal carried by persons than any other currently known and available metal detector. It has the further advantage of displaying a recording of the actual signals obtained. It therefore is especially useful in industries dealing with precious metals including refineries, mints, jewellery manufacturers, etc. although use in a wide variety of other areas is also possible.

Accordingly in one aspect of the present invention there is provided a method of detecting concealed metals comprising the steps of generating a fluctuating electromagnetic field about a passageway, passing a person or object through the passageway, obtaining an electrical signal representative of the change of the electromagnetic field as the person or object passes through the passageway, comparing the values of predetermined characteristics of the electrical signal against the corresponding values of the characteristics of a base electrical signal for the person or object previously obtained when the person or object was known not to contain concealed metals, and generating an alarm signal when the differences between at least one of the characteristics signals exceeds a predetermined threshold.

In accordance with a further aspect of the present invention there is provided an apparatus for detecting concealed metals on a person or object, comprising means for generating an electromagnetic field about a passageway, means for producing an electrical signal representative of the change in the electromagnetic field as the person or object passes through the passageway, means for comparing the values of predetermined characteristics of the signal against corresponding values representative of an electrical calibration signal obtained when the person or object was known not to contain concealed metals, and means for generating an alarm signal when the differences between the values of at least one of the characteristics of the signals exceeds a predetermined threshold.

BRIEF DESCRIPTION OF THE DRAWINGS

These and other features of the invention will become more apparent from the following description in which reference is made to the appended drawings wherein: FIGURE 1 is a perspective view of a typical metal detecting station in accordance with a preferred embodiment of the present invention; FIGURE 2 is a perspective view of the coil and winding configuration and associated circuitry for the detecting station;

FIGURE 3 is a diagrammatic electrical schematic of a circuit in accordance with- a preferred embodiment of the present invention; MGURES 4a-4f illustrate the voltage signal changes in a receive coil as a typical metal-free human body passes through a detecting station with and without in the current generated by field-shaping coils;

FIGURES 5a-5c illustrate typical signal changes in the receive coil as various objects are brought close to the receive coil and then withdrawn; FIGURE 6 is a logic flow chart illustrating the manner in which a person's calibration values are determined; FIGURE 7 is a logic flow diagram illustrating the normal operation of the detection system.

DESCRIPΗON OF PREFERRED EMBODIMENT

With reference now to the drawings, FIGURE 1 shows a typical metal detection station comprising the open-ended enclosure or portal unit 10 with a person 12 walking through the portal unit on a shallow platform 14, an entry display 16 and an exit display 18, both mounted on the portal unit, a computer console 20 and a card reader 22 connected to the computer system. An electrical transmit coil, discussed later with reference to FIGURES 2 and 3, is disposed about the portal unit and generates a magnetic field at a predetermined alternating frequency. Similarly, electrical receive coils are disposed about the portal unit in a manner described later and produce alternating electrical signals in response the magnetic field in their vicinity. The signals are further processed and then digitized and transmitted to the computer system. The receive coils produce a characteristic signal when the portal is empty. Similarly, a person walking through the portal will influence the magnetic field in a distinctive manner and it has been found that it is possible to detect these distinctive characteristics from the output of the receive coils. Thus, in accordance with one aspect of the present invention, each person with pass privileges is required to walk through the portal without metal objects for the purpose of producing a base or calibration signal which is processed to quantify the characteristics. These characteristics are stored in computer memory so that whenever the individual passes through the portal unit, the computer will compute and compare the characteristics of the receive coil with the calibration characteristics to determine whether the individual is carrying concealed metals. It will be understood that the present invention is not limited to humans and that it is equally applicable to animals and inanimate objects. Thus, unless otherwise indicated, the reference to "person" is to be taken to apply to animals and inanimate objects.

Under normal operation, a person inserts an identification card into card reader 22 and waits for permission to walk through the portal unit. The card reader reads the card in known manner and transmits signals representative of the identity of the person to the computer system. If the person's status in the computer system is such that it is permissible for the person to pass through the portal unit, the display on the entry sign 16 will so indicate. The system is able

to recognize when the person has entered and exited the portal unit by comparing the output of the receive coils against the signal characteristics of an empty portal. When the system recognizes that the person has exited the portal, it processes the signals which were produced while the person was in the portal and compares them to the base or calibration values discussed earlier for that individual. Based upon this comparison, the exit display 18 will indicate either a "clean" or an "alarm" condition. The envelope of the signal generated (similar to that shown in FIGURES 4 and 5) when the person passed through the portal can be displayed graphically on the computer monitor for visual observation by the operator. This display and other relevant data may be printed on paper to serve as a permanent record if desired.

FIGURE 2 illustrates an arrangement of coils in accordance to the preferred embodiment of the present invention. A transmit coil 30 is disposed substantially midway along the length of the portal and is operable to produce an alternating magnetic field within the portal. A pair of receive coils 32 are coaxially disposed on opposite sides and equidistantly from the transmit coil and operate to produce an electrical signal in response to changes to magnetic fields within their respective fields of influence. A field-shaping coil 34 is coaxially disposed proximate each receive coil and on the side thereof remote from the transmit coil. The field-shaping coils serve to reduce the effect of objects, such as a person's feet, placed in close proximity to the receive coils. Finally, at least one pair of field-shielding coils 36 are coaxially disposed on the axially outer sides of the field-shaping coils. These coils serve to reduce the magnetic field extending axially from the portal unit. While the field-shaping and field-shielding coils enhance system performance, they are not essential to successful operation of the system. All of the coils are located in planes which are perpendicular to the axis of the passageway through portal unit 10 and are fixedly mounted in or on the walls of the portal unit to avoid vibrations which would disturb the magnetic fields by suitable insulated mountings (not shown). The portal unit also incorporates magnetic field shielding comprising thin narrow strips of ferromagnetic material in at least its top and side walls as described in more detail later.

With reference to FIGURE 3, a driver 40 delivers a high frequency current to transmit coil 30 at a frequency, typically 25 kHz, determined by oscillator 42. This rapidly changing current generates a magnetic field about the axis of transmit coil. A capacitor 44 is connected across the input leads to the transmit coil and is chosen to cause a resonant condition in the transmit coil and serves to significantly amplify the current in the transmit coil and the magnetic field strength about the coil.

The receive coils are responsive, by producing a current therein, to all magnetic fields and changing currents in their respective vicinities including the alternating magnetic field produced by the transmit coil, the field-shaping coils, field-shielding coils and ferromagnetic material and ferrous material in which eddy currents are produced. If the coils are wound with precision, such that the spacings between respective windings are accurately controlled and substantially identical on each side of the transmit coil, then the currents and voltages induced in each receive coil will be substantially identical.

As best shown in FIGURE 3, the receive coils 32 are connected together in series such that as the voltage in one coil increases, the voltage in the other decreases. In this way, the resultant voltage across both coils is substantially zero. A capacitor 46 across the output leads of the receive coils is chosen such that it will cause a resonant condition between the two receive coils. Any small voltage differences between the two windings will then be greatly increased due to this resonant condition.

In practice, it is virtually impossible to wind the transmit and receive coils with exact precision. These differences, along with general wiring connections and other external influences, will- cause significant non-symmetrical influences on the magnetic fields inside the portal unit. Therefore, the induced voltages in each receive coil are not in general identical - albeit they are very close. Hence, it is necessary, in order to achieve a balanced condition, to provide a means to adjust or trim the voltage induced in each receive coil. A quadrature adjusting means is provided to balance the "in-phase" and the "out-of-phase" components of the signals. There are in general many conceivable ways to accomplish this adjustment. In the illustrated embodiment, a wire loop 47 having its axis normal

to the axis of the coils, and miscellaneous adjustments of the transmit leads are used to zero the induced voltage across the combined receive coils.

The field-shaping coils are used to generate an additional magnetic field in such a way as to enhance the detection of metal. It will be noticed that the field-shaping coils 34 are in close proximity to the receive coils 32. It should also be noted that, typically, the only part of the human body that comes in close proximity to the receive coils are the feet (typically, a few centimetres spacing). Due to physical constraints, it is impractical to design units in which this is not the case. The design of the units can be such that greater clearances for arms, hands and heads are achieved. The voltage change in the receive coils due to a particular object increases as the distance from the object to the receive coil decreases. Therefore, the receive coils are inherently more sensitive to the feet of an individual walking through the unit. Furthermore, significantly greater variation in the signal received by the receive coil will occur depending on the foot position relative to the receive coils. This type of variation will not be as significant for other parts of the body. In order to reduce the detrimental effects of the variation in the voltage induced in the receive coils due to the position of the feet, an additional current can be generated in the field-shaping coils. The advantages of having this additional current will become apparent later. In the present configuration, a separate phase shifter 48 and driver 49 are used to control the phase and amplitude of the current in the field shaping coils. An alternate means of achieving similar currents in the field-shaping coils could be achieved by carefully designing the coil and selecting appropriate passive components (resistors, capacitors and inductors) and not require the use of the phase shifter 48 and driver 49.

The primary function of the field shielding coils 36 is to effectively reduce the magnetic field extending axially from the portal unit. The induced current in these coils creates a magnetic field which opposes (or reduces) the magnetic field which generates it. In this way, the magnetic field extending from the portal unit is also decreased. Therefore, ferromagnetic materials, which tend to focus the magnetic field through these materials when brought into close proximity to the front or rear of the unit, will have a greatly reduced influence on the

non-symmetrical magnetic field distribution generated inside the portal unit. In the present configuration, the field shielding coils are shown to be located or spaced a distance axially outwardly from the respective transmit and receive coils. This is necessary in order to minimize the effect the field-shielding coils would have on the magnetic field in the vicinity of the receive coil.

The previously noted narrow ferromagnetic shielding strips (not shown) extend over the exterior surface of the portal unit on at least the sides and top. The purpose of these strips is to constrain, as much as possible, the magnetic fields generated by the transmit and field-shaping coils so they remain substantially within the portal unit. If no significant magnetic fields are able to leave the unit, then no significant eddy currents can be induced in electrically conducting materials exterior to the unit, and, if no eddy currents are generated, then no additional magnetic fields can be generated which would normally have been sensed by the receive windings. Similarly, ferromagnetic components close to the exterior of the unit would have a minimal influence on the magnetic fields inside the unit. This unit therefore provides a degree of electromagnetic shielding to the front and sides.

The output of the receive coils are connected to detection electronics commonly found in commercially-available, eddy current non-destructive testing instrumentation. One type of eddy current instrument which has been used successfully in laboratory tests is known as the "Defectomat F", by Institut. Dr. Forster of West Germany. Less expensive eddy current instruments are available from a number of suppliers. Other instruments are available from the following companies: Eddy Current Technology, Elotest, Hocking, Nortec; Reluxtrol, Tecrad and Zetec, certain of which can supply separate digitizing cards. This electronics, in general, has the capability of effectively balancing the small residual voltage remaining on the receive coil after the walk-through unit has been installed, and detecting the change in magnitude and direction (phase) of the voltage change in the receive coils. As explained below, the output of the detection electronics is comprised of two voltages which can be resolved into a resistive voltage change and a reactive voltage change. During system operation,

these voltages are being constantly digitized by separate digital circuitry, and the values are received by the computers.

FIGURE 3 illustrates the basic components and operation of the detection electronics. The output terminals of the receive coils are each connected to an input of an amplifier 50 whose output 52 is connected to one input terminal 54 of a summer or adder 56. The output of oscillator 42 is passed through an attenuator 58 and a phase shifter 60 and applied to the other input terminal 62 of the summer. The output of the summer is a signal which is the difference of the two input signals. Thus, when the portal is empty, the output of the receiver coils will be the same as the input to the transmit coil and, accordingly, the difference in the magnitude of the two signals will be zero. However, if a person or object is passing through the portal, the magnitude and phase of the output of the receiver coils will be different, resulting in a non-zero summer output. The summer output is delivered to a demodulator 66 which produces two DC level signals, one being representative of the resistive component of the signal and the other being representative of the reactive component of the signal. These two signals are then delivered to an analog-to-digital converter which digitizes the signals and feeds the digitized signals to the computer 70.

Before describing the digital signal processing scheme of the present invention, it would be useful to briefly review the types of signals sensed by the receive coils. An understanding of these signals is required in order to appreciate the value of field shaping coils 34 and to understand how the signal analysis is able to discriminate differences in the processed receive coil voltages.

As indicated above, the induced signal in the receive coils can be resolved into two components, namely, a resistive component and a reactive component. These components can be plotted on a graph in which the reactive component is plotted along the ordinate (y-axis) and the resistive component is plotted along the abscissa (x-axis). When a ferromagnetic material is brought into the vicinity of the receive coil, the magnetic field inside the coil increases due to the higher magnetic permeability of the ferromagnetic material. The increase in magnetic field strength causes a voltage increase in the receive winding (FIGURE 4). The voltage increase is 90° out-of-phase with the voltage induced in the receive coil

due to the magnetic field generated by the current in the transmit coil, and is therefore identified as a voltage increase having a direction along the positive reactive axis (see Signal No. 1 in FIGURE 4). Now consider the effects on the detection system of two loops of copper wire, each about 5 cm in diameter. One loop will be made of a wire having a very small cross-sectional area (for example #43 AWG) and the other of a larger cross-sectional area (for example #14 AWG). When the thin wire loop is brought close to one of the receive coils, a voltage will be induced in it due to the magnetic field generated from the current in the transmit coil. Because the resistance of the thin loop is high relative to the loop's reactance, the current in the loop will be substantially in phase with the induced voltage. As a result the magnetic field due to the current in the thin loop will increase, and hence the voltage induced in the receive coil will increase with an "in-phase" orientation (see Signal No. 2 as shown in FIGURE 4). When the thicker wire loop is brought close to the receive coil, a similar voltage is induced in it from the magnetic field generated by the currents in the transmit coil. However, the reactive impedance is far greater than the resistive impedance of this loop, and, as a result, the current generated in the loop generates a magnetic field which opposes the magnetic field which induced the voltage. As a result, the voltage induced in the receive coil will decrease, and this decrease is 90° out-of-phase with the initial voltage induced in the receive coil from the transmit coil (see Signal No. 3 in FIGURE 4).

Therefore, it can be understood from the above examples that, depending upon an object's magnetic and conductive properties, shape, size, structural properties, density, orientation and location relative to the various coils in the metal detector, a range of signals having orientations of up to 180° is possible. Typically, most precious metals have a high conductivity and so the voltage change tends to be in the negative reactive direction. However, very thin materials (for example platinum gauze) will exhibit properties like that of the thin wire.

It will be seen that while a person or object passes through the portal unit the magnetic field about each receive coil will fluctuate. If the receive coil output is sampled at equal increments of time, resolved into its resistive and reactive components and plotted on a graph as described above, a curve similar to that

illustrated in FIGURES 4 and 5 will result. The curve is characterized by two loops 80 and 82 in which loop 80 indicates the response of the receive coil proximate the entrance of the portal unit and loop 82 indicates the response of the receive coil proximate the exit of the portal unit. Each loop has an approach section 84 in which the strength of the signal increases in magnitude and a departure section 86 in which the strength of the signal decreases in magnitude. As stated earlier, the human body is known to be a poor conductor and has slight ferromagnetic properties. Due to the size of the body, the signal change detected by the receive coils due to the presence of the body can be significantly greater than the signal of interest, typical of the small metal object being carried by the person. A typical signal, sensed by the receive coils from the human body as it passes through the metal detector being described, is shown in FIGURE 5a. This signal shows the response of each receive coil, and hence we see the positive and negative components of the signal. It is clear from this signal that the body has a much higher conductive component than it has a ferromagnetic component. FIGURE 5b shows the much smaller response for a tiny metal object alone as it is passed through the portal unit and FIGURE 5c shows the signal when the tiny metal object is being passed through the detector on the human body. It follows from the foregoing that the output of the receive coils will vary with the manner in which an individual walks through the unit, i.e., side to side and front to back motion, swinging arms, etc. These variations cause the normal signal to vary somewhat and potentially inhibit the ability to detect small quantities of metal. To increase the detectability of small objects, it is therefore advisable to require employees to walk through the unit in a reasonable consistent and predetermined way.

The effect of the field shaping coils can now be appreciated. In order to demonstrate the effect of a person's foot as he walks through the portal, signals from a plastic container containing a salt water solution were obtained. This container was moved through the portal in a manner similar to that of a person's foot, and the signals are shown in FIGURES 4a and 4b. It will be noted that the signal without the field shaping current is approximately 50% greater than the signal with the field shaping current. FIGURES 4c and 4e show the signal from

a person walking through the portal without (FIGURE 4c) and with (FIGURE 4e) the field shaping current. The signal without the field shaping current is only about 20% greater than that with the field shaping current. This is expected since the predominant effect of the field shaping current will occur on things closest to it (i.e. the feet) and to a lesser extent on things more removed (i.e. the legs, torso and head). FIGURE 4d and 4f show the signals of a person walking through the portal with a coin in the front pocket without (FIGURE 4d) and with (FIGURE 4f) the field shaping current. The change in the middle angle is significantly greater for the case with the field shaping current (about 13°) than without the field shaping current (about 9°). Therefore, by utilizing field shaping currents, a significant increase in the detectability of small metal objects being carried by individuals is obtained.

Each person who walks through the portal unit must have first been calibrated. The calibration process is illustrated in the flow chart of FIGURE 6. The calibration process consists of the individual walking through the unit a number of times - for example 8 times. During each pass through the unit, the computer system receives the digitized voltage values. Based on these values, it determines when the signal starts and ends, and computes various characteristics of the signal for each pass. These characteristics can include, for example, the maximum positive and negative reactive components, the maximum positive and negative resistive components, the sum of the absolute values of the positive and negative reactive components of the signal, the sum of the absolute values of the positive and negative resistive components of the signal, the angle defined by these two sums called the differential angle, the angle of the middle portion, (e.g. the middle three-fifths) of each of the approach and departure sections of the two loops, and a middle angle defined by the terminal portion of the departure section of the first loop and the initial portion of the approach section of the second loop. These angles may be computed by any suitable technique, such as linear regression techniques, well known to those skilled in the art. The mean and standard deviation of each of these characteristics are then computed, and can be checked against the individual's weight, height and other significant features (e.g., implants, dental bridges etc.) to ensure the values are consistent with those

expected. If the values are satisfactory, they are stored in computer memory in association with other particulars, such as name, identification code and the like, for the individual. These values are considered the individual's calibration values and are used during normal operation. An advantage of this approach is that it considerably reduces the amount of computer memory required for each individual. It is possible, of course, to store the raw data, samples taken at small increments of time as the person passes through the portal unit. However, such an approach would consume a considerable amount of computer memory and would introduce considerable complexity into the signal analysis algorithm. During normal operation, as illustrated by the logic flow chart of

FIGURE 7, after the individual has been identified by the computer system and instructed to walk through the unit, the computer system receives the processed receive coil voltage changes in digitized form, determines the characteristic values of the signal and then compares these values to the calibration values previously described. Based on this comparison, a decision is made as to whether an alarm or non-alarm condition is present. The results of this decision are then displayed on exit display 18 so that an attending security guard can take appropriate action.

APPENDIX β 1990 ATOMIC ENERGY OF CANADA LIMITED

This Appendix contains material which is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of this Appendix as it appears in the Patent and Trademark Office file or records, but otherwise reserves all copyright rights whatsoever.

' Program PHD i» designed to operate a precious metal detector.

1 The prograπ requires a relay card to operate controls used to indicate

1 the outcome of a pass through the detector, and a separate card used to

' set signal levels from the detector and to digitive the signals.

DECLARE FUNCTION TCGAINSET* CDECL (BYVA GAIN*)

DECLARE FUNCTION TCFREQSET* CDECL (BYVAL FREQi, BYVAL PHASE*)

DECLARE SUB TCACQUISITION CDECL

DECLARE FUNCTION TCCOHPENSλTIONt CDECL

DECLARE SUB TCINITIALIZATION CDECL

DECLARE SUB MAIN.MENU.DISPLAY ()

DECLARE SUB GETFEATURES (condition*)

DECLARE SUB GETSIGNATURE (}

DECLARE SUB GETINKEY ()

DECLARE SUB UPDATE.EMPLOYEE.DATABASE () .

DECLARE SUB DISPLA .DATABASE ()

DECLARE SUB PMDCONS (At)

DECLARE SUB PMDHEΛD ()

DECLARE SUB GET.DATA ()

DECLARE SUB COMPENSATE ()

DECLARE SUB OPERATE ()

DECLARE SUB BLANXLINE (LINE. O.B ANK*)

DECLARE SUB ADDNEHCHAR ()

DECLARE SUB READ.KEYBOARD (}

DECLARE SUB CHECK.ID ()

DECLARE SUB DELETE.EMPLOYEE.FROH.DATABASE ()

DECLARE SUB GET.DAYS.FROM.1990 ()

DECLARE SUB SWAP.EMPLOYEE (HIGH.INDEX.NUMt, ARRAY.ENTRY.POINT*)

DECLARE SUB COPY.EMPLOYEE.DATA (OLD*, NEW*)

COMMON A$, EXIT$, FINISHS, IPRM*, IPRMKAX*, COLUMN*, ASPACECHRS

COMMON TIHELOOPt, Rt, Ct

COMMON XAVGt, YAVG*, XREF*, YREFt, X.AT.COMP*, Y.AT.COMP*

COHHON COMPCHECKt, COMP#()

COHHON NUH.UPDATE.HEAD*, UPDATEHEADRt() , UPDATEHEADC*() , UPDATEHEADT$()

COMMON NUM. PDATE.ADD.HEAD*, UPDATEADDHEADR*() , UPDATEADDHEADCt() ,

UPDATEADDHEADTS()

COMMON NUM.UPDATE.PARM*, UPDATERO *() , UPDATECOL*() , UPDATESPCS*()

COMMON DATΛRtO, DATAC*(), SPCS*()

COMMON NUMBER.Or.EMPLOYEES*, DATA.CHANGE?

COMMON DMEANO, DSTDEV(), NUM. EATURES*

COMMON DACTLASTS() , DACTFIRSTS() , DACTINITS() , DCARDLASTS() , DCARDNO&() ,

DEMFNOtO

COMMON DSEXO AS STRING * 1, DHEIGHT() , DWEIGHTf)

COMMON DBRIDGEO AS STRING * 1, DIMPLANT() AS STRING * 1, DPACE() AS STRING *

1, DOTHER50

COMMON IN.SECURE.AREA*(), AMTIPASS1*, ANTIPASS2*, READER.OPERATIONALS

COMMON PERSON.CALIBRATEDS, ALARMS, OPERATE.ALERT*()

COMMON PERSON.IN.DATABASES, RUN.HODE$

COMMON EMPNO*, INDEX. UM*

COMMON INTERRUPT.RATB, RISETIME, DIFFERENTIAL.TIME, MAX.WALK.TIME*

COMMON MAX.SAMPLES.FOR.EVENT*, SAMPLES.IN.RISETIME*

C0MM0N M$(), REFLINE, PI, RADTODEG, LOOPSPERSEC, BLINKTIME

COMMON PDISO*, PDISO.WAIT*, PDISO.GO*, PDISO.ALARM*, PDISO.CLEAN*

COMMON CLEAN.TIME*. ALARM.TIME*, PERCENT.ALARM*

COMMON MAX.PASSNUHt, NUM.OPERATE.ALERTS*

COMMON OP.NSTDEVO, CAL.NSTDEV() , LIM.STDEV()

COMMON RECOMP.CHECK*, FREQS, PHASE*, GAIN*, DRANGE*

COMMON FILE.CONSTANTSS, LAST.DATES, LAST.TIMES

COMMON X.DEL.CHK.S*, Y.DEL.CHK.S*, X.DEL.CHK.Et, Y.DEL.CHK.E*

COMMON CALIBRATE.MAX.DELAY. IME*, OPERATE.MA .DELAY.TIME*

COMMON VIEW. ENGTH, LBND*, UBND*

COMMON CONPARMSO, CALQUEST$()

COMMON NUM.CAL.HEAD*, CALHEADR*() , CALHEADC*() , CALHEADTS()

COMMON NUM.CON.HEAD*, CONHEADR*(), CONHEADC*(), CONHEADTSO

COMMON NUM.CAL. ARMt, CALROWt(), CALCOL*(), CALSPCSt()

COMMON NUM.CON. ARM*, CONROW*(), CONCOL*(), CONSPCS*()

COMMON E*, NEWFREQS, NEWGAIN*, NALARM*, ALARMNUM*() -

COMMON FEATUREO, X*0. V*(), NSAMP*

COMMON COUNT*, IRT*, IHTt, XAR*(), YAR*(), A*()

COMMON NAME.FILES, ERRNUM*, REASONS

COMMON YESS, NO$, OKS, NOTOKS

COMMON PERSON. AITINGS, NEED. O.BLANKS

COMMON F1HITS, LASTKEYS, PASSNUM*

COMMON MAX.SAMPLES.BEFORE.EVENT*, PASS.ALERT*, END.EVENT*

COMMON DM*(), DAYS. ROM.1990*

CLEAR , , 2000

DIM A*(0 TO 4), COMP«(3)

DIM OPERATE.ALERT*(10), ALARMNUM*(10)

DIM FEATURE(10)

DIM HEADR*(25), HEADC*(25), HEADT$(25), SPCS*(25)

DIM 0ATAR*(25), DATAC*(25), DATASPCS*(25)

DIM CALHEADR*(25), CALHEADC*(25) , CALHEADTS(25)

DIM CALROW*(25) , CALCOL*(25), CALSPCS*(2S) , CALPARM$(25)

DIM CONHEADR*(25), CONHEADCt(25) , CONHEADT$(25)

DIM CONROWt(25), CONCOL*(25), CONSPCS*(25) , CONPARM$(25)

DIM UPDATEHEADR*(25), UPDATEHEADCt(25) , UPDATEHEADT$(25)

DIM UPDATEADDHEADR*(25), UPOATEADDHEADC*(25) , UPDATEADDHEADTS(25)

DIM UPDATEROW*(25), UPDATECOL*(25) , UPDATESPCS*(25) , UPDATEPARMS(25)

DIM CALQUESTS(25) , M$(12), DM*(12)

NMAX* - 50

DIM DEMPNOt(NMAXt), DACTLAST$(NMAX*)

DIM DACTFIRSTS(NMAX*) , DACTINIT$(NMAX*)

DIM DSEX(NMAXt) AS STRING * 1, DHEIGHT(NMAX*) , DWEIGHT(NMAXt)

DIM DBRIDGE(NMAXt) AS STRING * 1, DIMPI_ANT(NMAX*) AS STRING * 1

DIM DPACE(NMAXt) AS STRING * 1, DOTHERS(NMAX*)

DIM DMEAN(NMAX*, 10), DSTDEV(NMAXt, 10)

DIM OP.NSTDEV(IO) , CAL.NSTDEV(IO) , LIM.STDEV(IO)

CALL PHDCONS(O)

DIM XAR*(MAX.SAMPLES.FOR.EVENT*), YAR*(MAX.SAMPLES.FOR.EVENT*) DIM X*(MAX.SAMPLES.FOR.EVENT*), Yt(MAX.SAMPLES.FOR.EVENT*)

DΣM XCALDAT*(β, MAX.SAMPLES.FOR.EVENT*) , YCALDAT*(8, MA .SAMPLES.FOR.EVENT*) DIM NCAI_DAT*(8)

TIME.TEST* - 0: JEND* - 1: IEND* - 20000 WHILE TIME.TEST* - 0

JEND* - 2 * JEND*

STTIHE - TIHER

FOR J* - 1 TO JEND*: FOR I* » 1 TO IEND*: NEXT It: NEXT J*

ENDTIHE - TIMER

IF ENDTIME - STTIHE > 1.5 THEN TIME.TEST* - 1 WEND

LOOPSPERSEC - JEND* / (ENDTIME - STTIHE) * IEND* BLINKTIKE - .05 TIHELOOP* - BLINKTIME * LOOPSPERSEC

YESS ■ "YES": HOS - "NO": OKS - "OK": NOTOKS - "NOT OK" STAT.BASEt - 40' - the number used for determining the mean and st. dev. SB* - STAT.BASEt: SBMt - STAT.BASE* - 1 ESCKEYS - CHSS(27) ADAYt - VAL(MIDS(DATES, 4, 2)) MONTHS - MS(VA (LEFTS(DATES, 2))) RANDOMIZE TIMER

X.DEL.CHK.INV.St - 2 * X.DEL.CHK.S* Y.DEL.CHK.INV.St - 2 * Y.DEL.CHK.S* SCREEN 0, , 1, l: CLS GOSUB EMPLOYEE.DATABASE

ASPACECHRS - " »: SPACECHRS - STRINGS(80, ASPACECHRS) DRIVE.ERRORS -~NOS CALL PMDHEAD GOSUB SET.BOARD CALL MAIN.MENU.DISPLAY

RESPONSER* - CSRLIN: RESPONSEC* » POS(O) Note that the initial value for RESPONSES- H 0" so that the OPERATE mode •tarts right away. RESPONSES - "O" WHILE RESPONSES <> "-Q" SELECT CASE RESPONSES CASE "C«

GOSUB CALIBRATE

CALL MAIN.MENU.DISPLAY

RESPONSES - »" CASE IS - "O"

RUN.MODES - "OPERATE"

IF DATA.CHANGES - YESS THEN GOSUB SAVE.DATABASE

GOSUB OPERATE

CALL MAIN.MENU.DISPLAY

RESPONSES - **" CASE "U"

CALL UPDATE.EMPLOYEE.DATABASE

CALL MAIN.MENU.DISPLAY

RESPONSES - "" CASE "D"

-19-

CALL DISPLAY.DATABASE CALL MAIN.MENU.DISPLAY RESPONSES - "" CASE IS - "Q"

LOCATE 23, 1: PRINT "STOP" CASE ELSE

LOCATE RESPONSERt + 2, 1 SOUND 500, 2: SOUND 300, 2 PRINT "Invalid entry - try again"; END SELECT SOUND 100, 3: SOUND 50, 2 LOCATE RESPONSER*, RESPONSEC* CALL GETINKEY RESPONSES - UCASES(AS) PRINT AS; WEND END

CALIBRATE: ' - routine to calibrate the individual RUN.MODES ■ "CALIBRATE": OKAY.TO.CALIBRATES - YESS SCREEN 10, , 0, 0: CLS : ESCHITS - NOS

MAX.SAMPLES.BEFORE.EVENT* - CALIBRATE.MAX.DELAY.TIME* * INTERRUPT. ATE COLOR 3, 0:

LOCATE 1, 1: PRINT CHRS(201) + STRING$(78, 205) + CHRS(187); : LOCATE 2, 1 PRINT CHR$(186) + SPACE$(31) + "CALIBRATION MODE" + SPACE$(31) + CHRS(186) LOCATE 3, 1: PRINT CHRS(200) + STRINGS(78, 205) + CHR$(188); COLOR 1, 0

' - need to get the employee*■ last name and their employee number. GET.NAMES - YESS WHILE GET.NAMES - YESS AND ESCHITS - NO$

CALL BLλNKLINE(β): PRINT "Enter the employee's last name " :

GOSUB GET.INPUT: IASTNAMES - ASTRS

IF LEN(IASTNAMES) > 0 THEN LASTNAMES - LTRIM$(RTRIMS(UCASES(IASTNAMES) ) )

CALL BLANKLINE(9) : PRINT "Enter the employee's number ";

GOSUB GET.INPUT: EHPSTRS • ASTRS: EMPNO* » VA (ASTRS) : CALEMPNO* - EMPNOt ( -ALL CHECK.ID: ' - returns PERSON.IN.DATABASES, PERSON.CALIBRATED?, and ' INDEX.NUMt

CAL.INDEX.NUMt - INDEX.NUM* IF PERSON.IN.DATABASES - NOS THEN

CALL BLANKLINE(13): CALL BLANKLINE(12) : -CALL BLANKLINE(ll)

PRINT " The employee number "; EMPSTRS; " is not in the database."

PRINT " Do you wish to re-enter the name and number (Y/N) ? ";

SROWQ* - CSRLIN: SCOLQ* - POS(O)

GOSUB CHECK.INKEY: PRINT λ$; : A$ - UCASES(AS)

WHILE AS <> "Y" AND A$ <> "N"

CALL BLANKLINE(14): PRINT "Invalid entry - try again " LOCATE SROWQ*, SCOLQ*: GOSUB CHECK.INKEY: PRINT AS: AS - UCASES(AS) WEND

IF AS - "N" THEN GET.NAMES - NOS: OKAY.TO.CALIBRATES - NOS ELSE ' - now to sake sure the last names match

NAME.MATCHS - YESS

IF DλCTI_AST$(CAL.INDEX.NUM*) <> IASTNAMES THEN NAME.MATCHS - NO$ It - CAL.INDEX.NUMt

CALL BLANKLINE(13): CALL BLANKLINE(12) : CALL BLANKLINE(ll) PRINT " EBployβe "; DACTFIRSTS(It) ; " "; DACTINIT d*) ; " " 1 PRINT DACTLASTS(It); " has employee number "; EMPNO* PRINT " The last names are not the same." PRINT " Do you wish to re-enter the name and number (Y/N) ? "; SROWQ* - CSRLIN: SCOLQ* - POS(O) GOSUB CHECK.INKEY: PRINT AS; : AS - UCASE$(A$) WHILE AS <> "Y" AND AS <> "N"

CALL BLANKLINE(15): PRINT "Invalid entry - try again " LOCATE SROWQ*, SCOLQ*: GOSUB CHECK.INKEY: PRINT AS: AS - UCASES(AS) WEND »

IF AS - "N" THEN GET.NAMES - NO$: OKAY.TO.CALIBRATES * NOS END IF

IF NAME.MATCHS - YESS THEN GET. AMES - NOS IF PERSON.CALIBRATEDS - YESS THEN

CALTYPES - "R" ELSE

CALTYPES - "N" END IF END IF END IF WEND

IF OKAY. O.CALIBRATES - YESS AND ESCHITS - NOS THEN GOSUB GET.CAL.DATA GOSUB CALIBRATE.OLD.HEAD.DISPLAY IF CALTYPES - "N" THEN

GOSUB CALIBRATE.DISPLAY.CHANGE ELSE

CALL BLANKLINE(18)

PRINT "Do you wish to change any values - enter Y(yes) N(no) "; ACALS - ""

WHILE ACALS <> "Y» AND ACALS <> "N" AND ACALS <> CHRS(27) SOUND 500, 2: SOUND 300, 2: LOCATE 18, 61 GOSUB CHECK.INKEY: PRINT AS; : ACALS - UCASES(AS) SELECT CASE ACALS CASE "Y"

CALL BLANKLINE(18) : CALL BLANKLINE(20) GOSUB CALIBRATE.DISPLAY.CHANGE CASE "N"

GOSUB CALIBRATION.SETUP. AME CASE CHRS(27)

OKAY.TO.CALIBRATES - NO$ CASE ELSE

LOCATE 20, 5: PRINT "Invalid response - try again."; LOCATE 18, 61: PRINT " "; END SELECT WEND

END IF END IF ' - Note that in routine CALIBRATE.DISPLAY.CHANGE the parameter ' OKAY.TO.CALIBRATES - NOS if the escape key is pressed. IF OKAY.TO.CALIBRATES - YESS AND ESCHITS - NOS THEN

PASSNUM* - l: PASS.ALERT* - 0: PASS1CHECKS - "NOT OK" VIEW PRINT 13 TO 24 CLS 2

PRINT "PASS DELX DELY DIF.AN MID.AN ANGL1 ANGL2 ANGR1 ANGR2 DELYL DELYR"

WHILE PASSNUM* <- MAX. ASSNUM* AND PASS.ALERT* - 0 AND ESCHITS - NOS PASS.ALERT* - 0 CALL COMPENSATE

CALL BLANKLINE(25): SOUND 500, 2: SOUND 300, 2 PRINT "Ok to walk through - elbows against sides,"; PRINT " hands on middle - PASS "; PASSNUM*; IF ESCHITS - NOS THEN

IF RELAY.CONTROLS? - YESS THEN OUT PDISO*, PDISO.GO* GOSUB PLOT.CAL.BORDER CALL GETSIGNATURE FOR It - 1 TO NSAMPt

XCALDAT*(PASSNUM*, I*) - X*(It) YCALDAT*(PASSNUM*, It) - Yt(It) NEXT It

NCALDAT*(PASSNUM*) - NSλMP* IF END.EVENT* > O THEN CALL GETFEATURES(O) LOCATE 13 + PASSNUM*, 1

PRINT USING "###"; PASSNUM*; : PRINT " "; FOR It - 1 TO NUM.FEATURES*

CALFEATURE( ASSNUM*, I*) - FEATURE(It) PRINT USING "###...#"; FEATURE(It) ; NEXT It: PRINT END IF

EVENT* - 0: COUNT* - -1: TOTAL.COUNT* - -1: OLDTIME - TIMER IRTt - COUNTt - SAMPLES.IN. ISETIMEt IHTt - COUNTt - SAMPLES.IN.RISETIME* / 2 PASSNUM* - PASSNUM* + 1 END IF WEND 1 - now I need to perait additional passes in order to satisfy the • CHECK.STATS conditions.

IF PASS.ALERT* - 0 AND ESCHITS - NOS THEN REDO.PASS* - -1

WHILE REDO.PASS* <> 0 AND PASS.ALERT* » 0 GOSUB GET.STATS: GOSUB PRINT.STATS STATS.OKS - YESS: GOSUB CHECK.STATS IF REDO.PASS* <> 0 THEN

PASSNUMt * REDO.PASS*: PASS.ALERT* « 0

CALL BLANKLINE(25): SOUND 500, 2: SOUND 200, 2

CALL COMPENSATE

PRINT "Ok to walk through - elbows against sides,";

PRINT " hands on βiddlβ - RE-PASS "; PASSNUM*; OUT PDISO*, PDISO.GO* GOSUB PLOT.CAL.BORDER CALL GETSIGNATURE FOR I* - 1 TO NSAMP*

XCALDAT*(PASSNUM*, It) - Xt(It) YCALDAT*(PASSNUM*, I*) - Y*(I*) NEXT It

NCALDAT*(PASSNUM*) - NSAMP* IF END.EVENT* > 0 THEN CALL GETFEATURES(O) LOCATE 13 + PASSNUM*, 1

PRINT USING "###"; PASSNUM*; : PRINT " "; FOR It • 1 TO NUM.FEATURES*

CALFEATURE(PASSNUM*, I*) « FEATURE(I*) PRINT USING "#####.#"; FEATURE(I*) ; NEXT It: PRINT END IF

EVENT* - 0: COUNTt « -1: TOTAL.COUNT* - -l: OLDTIME » TIMER IRT* - COUNTt - SAMPLES.IN. ISETIMEt .IHTt « COUNTt - SAMPLES.IN.RISETIME* / 2 END IF WEND

IF STATS.OKS - YESS THEN ' - okay to update employees info It - CAL.INDEX.NUMt

DSEX(It) - CALEMPSEXS: DHEIGHT(It) - CALEMPHEIGHT DWEIGHT(It) - CALEMPWEIGHT: DBRIDGE(I*) « CALEMPBRIDGES DIMPLANT(I*) - CALEHPIMPLANTS: DPACE(I») » CΛLEMPPACES DOTHERS(It) - CALEMPOTHERS - now I need to deteraine which pass is the most representative and to save the data on the hard drive.

SUMMIN - 1000000: PASS.SAVE* - 1 FOR J* - 1 TO MAX.PASSNUMt SUM - 0

FOR Kt - 1 TO NUM.FEATURESt

SUM - SUM + ABS(CALFEATURE(Jt, K*) - DMEAN(I*, Kt) ) / DSTDEV(I*, Kt) NEXT K*

IF SUM < SUMMIN THEN SUMMIN - SUM: PASS.SAVE* - J* NEXT J*

AFNS - "E" + LTRIM$(RTRIMS(STRS(DEMPNO*(I*)))) DRIVE.B.ERRORS - YESS ON ERROR GOTO DISCB.CHECK CAL. ILE.NAMES - "B:" + AFNS WHILE DRIVE.B.ERRORS - YESS DRIVE.B.ERRORS - N0$ OPEN CAL.FILE.NAMES FOR OUTPUT AS fl WEND

GOSUB SAVE.CAL.DATA ON ERROR GOTO 0

CAL.FILE.NAMES » "C:\PMD\CALDAT\" + AFNS OPEN CAL.FILE. AMES FOR OUTPUT AS #1 GOSUB SAVE.CAL. ATA

CALL BLANKLINE(25) : CALL BLANKLINE(24) : BEEP

PRINT "Calibration was successful - ";

PRINT "Press return to continue. ";

GOSUB CHECK.INKEY

DATA.CHANGES - YESS ELSE

FOR It - 1 TO NUM.FEATURES*

DMEλN(INDEX.NUMt, It) - 0: DSTDEV(INDEX.NUMt, It) - 0

NEXT It

CALL BLANKLINE(25) : CALL BLANKLINE(24) : BEEP

PRINT "Calibration values are not consistent -";

PRINT "press return to continue. ";

GOSUB CHECK.INKEY END IF ELSE

CALL BLANKLINE(25): CALL BLANKLINE(2 ) : BEEP

PRINT "Problem encountered while collecting data - ";

PRINT "press return to continue. ";

CALL GETINKEY END IF END IF ALARMS - NOS RETURN

SAVE.CAL.DATA: ' - routine to save the calibration data It - CAL.INDEX.NUMt

WRITE fl, DATES, TIMES, PASS.SAVEt ΛlS - DACTLASTS(It)

A2S - DACTFIRST$(I*) I A3$ - DACTINITS(It) : A4* - DEMPNOtd*) A5S - DSEX(It)

A6 - DHEIGHT(It): A7 - DWEIGHT(It) : A8$ - DBRIDGEd*) A9$ - DIHPLANT(It): AλS - DPACE(It) : ABS - DOTHERS(It) WRITE fl, A1S, A2S, A3$, A4t, A5S, A6, A7, A8$, A9$, λλ$, ABS Bl - DMEAN(It, 1) I B2 - DMEAN(It, 2): B3 - DMEAN(I*, 3) B4 - DMEANd*, 4): B5 - DMEAN(It, 5): B6 » DMEAN(I*, 6) B7 - DMEANd*, 7) : B8 - DMEAN(I*, 8): B9 - DMEAN(It, 9) BA - DMEANdt, 10)

WRITE fl, Bl, B2, B3, B4, B5, B6, B7, B8, B9, BA Bl - DSTDEVflt, 1): B2 - DSTDEV(It, 2): B3 - DSTDEV(It, 3) B4 - DSTDEV(I*, 4)s B5 - DSTDEVflt, 5): B6 » DSTDEV(It, 6) B7 - DSTDEV(It, 7): B8 - DSTDEV(It, 8): B9 - DSTDEV(It, 9) BA - DSTDEV(It, 10)

WRITE fl, Bl, B2, B3, B4, B5, B6, B7, B8, B9, BA FOR Jt - I TO NUM.FEATURES*

Al - CALFEATUREU, Jt) : A2 - CALFEATURE(2, Jt) : A3 - CALFEATURE(3, Jt)

A4 - CALFEATURE(4, Jt) : A5 - CALFEATURE(5, Jt) : A6 ■ CALFEATURE(6, J*)

A7 - CALFEATURE(7, Jt) 8 λβ - CALFEATURE(8, Jt)

WRITE fl, Al, A2, A3, A4, A5, A6, A7, Aβ NEXT Jt

WRITE fl, NCALDAT*(PASS.SAVE*) FOR Jt - 1 TO NCALDAT*(PASS.SAVE*)

WRITE fl, XCALDATt(PASS.SAVEt, Jt) , YCALOATt(PASS.SAVEt, Jt)

NEXT Jt CLOSE fl RETURN

DISCB.CHECK: ' - routine to check that drive B is okay to use

PRINT "Please insure a formatted disc (which isn't full) is in drive B." PRINT "Press return to continue "; GOSUB CHECK.INKEY DRIVE.B.ERRORS - YESS RESUME NEXT

GET.EMP.NAME: ' - routine to get an employee name and employee number GET.NAMES - YESS WHILE GET.NAMES - YES$ >

CALL BLANKLINE(8): PRINT "Enter the employee's last name "; GOSUB GET.INPUT: IASTNAMES - ASTRS

IF LEN(IASTNAMES) > 0 THEN IASTNAMES - LTRIMS(RTRIMS(UCASES(IASTNAMES) ) ) CALL BLANKLINE(9) : PRINT "Enter the employee's number "; GOSUB GET.INPUT: EMPSTRS - ASTRS: EMPNO* - VAL(LEFT$(ASTRS, 4)) CALEMPNOt - EMPNO* OLD.MODES - RUN.MODES RUN.MODES - "CALIBRATE"

CALL CHECK.ID: • - returns PERSON.IN.DATABASES, PERSON.CALIBRATEDS, and ' INDEX.NUM*

RUN.MODES - OLD.MODES CAL.INDEX.NUM* - INDEX.NUM* IF PERSON.IN.DATABASES - NOS THEN

CALL BLANKLINE(13): CALL BLANKLINE(12) : CALL BLANKLINE(11)

PRINT " The employee number "; EMPSTRS; " is not in the database."

PRINT " Do you wish to re-enter the name and number (Y/N) ? ";

RPOSt - CΞRLIN: CPOSt - POS(O)

GOSUB CHECK.INKEY: PRINT λ$; : AS - UCASES(AS)

WHILE AS <> "Y" AND AS <> "N"

CALL BLANKLINE(14) : PRINT "Invalid entry - try again " LOCATE RPOSt, CPOSt: GOSUB CHECK.INKEY: PRINT AS: AS - UCASES(AS) WEND

IF AS » "N" THEN GET.NAMES - NOS: OKAY.TO.CALIBRATES - NOS ELSE ' - now to sake sure the last names match NAME.MATCHS - YESS

IF DACTLASTS(INDEX.NUMt) <> IASTNAMES THEN NAME.MATCHS - NOS It - INDEX.NUMt

CALL BLANKLINE(13): CALL BLANKLINE(12) : CALL BLANKLINE(11) PRINT " Employee "; DACTFIRSTS(It) ; " "; DACTINITS(It) ; " "; PRINT DACTLASTS(It); " has employee number "; EMPNO* PRINT " The last names are not the same." PRINT " Do you wish to re-enter the name and number (Y/N) ? "; GOSUB CHECK.INKEY: PRINT AS : λ$ - UCASES(AS) WHILE AS <> "Y" AND A$ <> "N"

CALL BLANKLINE(15): PRINT "Invalid entry - try again " LOCATE 13, 70: GOSUB CHECK.INKEY: PRINT AS: AS - UCASES(A$)

-25-

WEND

IF AS - "N" THEN GET.NAMES - NOS: OKA .TO.CALIBRATES - NOS END IF

IF NAME.MATCHS - YES? THEN GET.NAMES - NOS IF PERSON.CALIBRATED! - YESS THEN

CALTYPES - "R" ELSE

CALTYPES - "N" END IF END IF END IF WEND RETURN

CALIBRATE.OLD.HEAD.DISPLAY: ' - routine to display the CALIBRATE screen CLS (0) COLOR 3, 0 FOR I* - 1 TO NUM.CAL.HEAD*

LOCATE CALHEADR*(It) , CALHEADC*(I*)

PRINT CALHEADTS(I*); NEXT It COLOR 1, 0 FOR It - 1 TO NUM.CAL.PARMt

LOCATE CALROW*(It), CALCOLt(It) : PRINT LEFTS(SPACECHRS, CALSPCS*(I*)) ;

LOCATE CALROWt(It), CALCOLt(It) : PRINT CALPARMS(I*) ,* NEXT It RETURN

CALIBRATE.DISPLAY.CHANGE: * - routine to change the entries on the calibration display.

IPRMSTAKTt - 5: ZFRMMAX* - NUM.CAL.FARM*: IPRM* - IPRMSTART* FOR It - 1 TO IPRMMAXt

DATARt(It) - CALROWtd*): DATAC*(I*) - CALCOH(It): SPCS*(It) - CALSPCStflt) NEXT It

ALLDATAS - "NOT OK" WHILE ALLDATAS - "NOT OK" FΣNISHS - NOS WHILE FINISHS - NOS

IF IPRM* > IPRMMAXt THEN IPRMt - IPRMSTAKTt

IF IPRMt - 1 THEN IPRMt - IPRMSTARTt

IF IPRMt < IPRMSTARTt THEN IPRMt - IPRMMAXt

CALL BLANKLINE(25): PRINT CALQUESTS(IPRM ) ; : SOUND 100, 3: SOUND 50, 2

ROWt - DATARt(IPRMt): COLUMNt - DATACt(IPRMt)

LOCATE ROWt, COLUMNt

GOSUB ADDNEWCHAR.WITH.CHECK

IF EXITS - YESS THEN

OKAY.TO.CALIBRATES - NOS RETURN END IF

CALL BLANKLINE(15) WEND

GOSUB CALIBRATION.SETUP.NAME

GOSUB CALIBRATION.SETUP.CHECK WEND RETURN

ADDNEWCHAR. ITH.CHECK: • routine to add a character ' as well as excessive signals in the PMD.

AS - "" EXITS - HOS WHILE AS <> CHR$(13) GOSUB CHECK.INKEY SELECT CASE ASC(λS)

CASE 13: ' - to advance to the next field IPRMt - IPRMt + 1

IF IPRMt > IPRMMAXt THEN IPRMt •. 1 CASE 32 TO 217: ' - standard characters PRINT AS; : AS - "": C* - POS(0)

IF (C* - COLUMN*) >- SPCS*(IPRM*) OR C* < COLUMN* THEN IPRM* » IPRM* + 1: AS » CHRS(13) IF IPRM* > IPRMMAX* THEN IPRMt * 1 END IF CASE' 8: ' - backspace and overwrite LOCATE Rt, Ct: PRINT ASPACECHRS LOCATE Rt, Ct - l: AS - "": Ct - POS(0) IF Ct < COLUMNt THEN LOCATE Rt, COLUMNt CASE 9: ' - tab to the next field IPRMt - IPRMt + 1

IF IPRMt > IPRMMAXt THEN IPRMt - 1 AS - CHRS(13) CASE 27: ' - escape key - used to exit data entry - no checking AS - CHRS(13) EXITS - YESS CASE 0: * - look at keys having 2 byte responses SELECT CASE ASC(RIGHTS(AS, 1))

CASE 15: • - shift tab - go back a field IPRMt - IPRMt - 1

IF IPRMt <- 0 THEN IPRM* « IPRMMAX* AS - CHRS{13) CASE 75: ' - shift left 1 character LOCATE Rt, Ct - 1 AS - "": Ct - POS(0)

IF Ct < COLUMNt THEN LOCATE Rt, COLUMN* CASE 77: ' - shift right 1 character CPt - Ct + 1

IF CPt <■ 80 THEN LOCATE Rt, CP*: AS " "": C* - POS(O) IF (Ct - COLUMNt) >» SPCSt(IPRMt) OR C* « 80 THEN IPRM* - IPRMt + 1: AS - CHR$(13) IF IPRMt > IPRMMAX* THEN IPRMt - 1 END IF CASE 68: ' - F10 - exit menu FINISHS - YES$ AS - CHR$(13)

CASE ELSE AS - "" END SELECT CASE ELSE END SELECT WEND RETURN

CALIBRATION.SETUP.NAME: ' - subroutine to name the PAGE parameters FOR It - 1 TO NUM.CAL.PARMt BS - " " FOR Jt - 1 TO CALSPCSt(It)

AS - CHRS(SCREEN(CALROWt(I*), CALCOLt(It) + J* - 1)) IF AS - ASPACECHRS THEN J* - -CALSPCS*(I*) + 1 ELSE

BS - BS + AS END IF NEXT Jt CALPABMS(It) "• RTRIMS(LTRIHS(BS)) NEXT It CALLASTNAMES - CALPARMS(l) CALFIRSTNAMES - CALPARMS(2) CALINITIALS - CALPARMS(3) CALEMPNUMBERi - VAL(CALPARMS(4) ) CALEMPSEXS - CALPARMS(5) CALEMPHEIGHT - VAL(CALPARM$(6)) CALEMPWEIGHT - VAL(CALPARM$(7)) CALEMPBRIDGES - CALPARM$(8) CALEMPIMPLANTS - CALPARM$(9) CALEMPPACES - CALPARMS(IO) CALEMPOTHERS - CALPARMS(ll) RETURN

CALIBRATION.SETUP.CHECK: ' - subroutine to check the data entered is okay ALLDATAS - "OK"

FOR It - IPRMSTARTt TO NUM.CAL.PARMt IF LEN(CALPARM$(It)) < 1 THEN ALLDATAS - "NOT OK"

CALL BLANKLINE(15) : PRINT "A value must be entered here." SOUND 500, 2: SOUND 300, 2 IPRMt - It

It - NUM.CAL.PARMt -I- 1 END IF NEXT It IF ALLDATAS ■ "OK" AND (CALEMPHEIGHT < 100 OR CALEMPHEIGHT > 220) THEN ALLDATAS - "NOT OK": IPRMt - 6

CALL BLANKLINE(15): PRINT "Correct the person's height value" SOUND 500, 2: SOUND 300, 2 END IF IF ALLDATAS - "OK" AND (CALEMPWEIGHT < 30 OR CALEMPWEIGHT > 200) THEN ALLDATAS - "NOT OK": IPRMt - 7

CALL BLANKLINE(15): PRINT "Correct the person's weight value " SOUND 500, 2: SOUND 300, 2 END IF

AS - CALEMPSEXS IF ALLDATAS - "OK" AND AS <> "M" AND AS <> "m" AND AS <> "F" AND AS <> "f" THEN

ALLDATAS - "NOT OK": IPRMt - 5

CALL BLANKLINE(15) : PRINT "NOTE : a 'M' or 'F' must be entered here." SOUND 500, 2: SOUND 300, 2 END IF IF ALLDATAS - "OK" THEN FOR It - 8 TO 10 AS - CALPARMS t)

IF AS <> "N" AND AS <> "n" AND AS <> "Y" AND AS <> "y" THEN ALLDATAS - "NOT OK"

CALL BLANKLINE(15): PRINT "NOTE : a 'N' or ' _ ' must be entered here." SOUND 500, 2: SOUND 300, 2 IPRMt - It

It - NUM.CAL.PARMt + 1 END IF NEXT It END IF RETURN

CHECK.INKEY: ' - This subroutine gets a character from the keyboard using the 1 INKEY command, and also checks the PMD for an invalid entry. AS - "" WHILE AS - "

Rt » CSRLIN: Ct - POS(O): ACHAR - SCREEN(R*, C*) : PRINT " ";

IF ACHAR <- 32 THEN ACHAR - ASC(ASPACECHRS)

LOCATE Rt, Ct

FOR It - 1 TO TIMELOOPt: NEXT It: PRINT CHRS(ACHAR);

FOR It 1 TO TIMELOOPt: NEXT It: LOCATE Rt, C*

AS - INKEYS

IF AS - ESCKEYS THEN ESCHITS - YESS

GOSUB CHECK.INVALID.ENTRY: ' - need to check for excessive signal level. WEND RETURN

GET.INPUT: ' - This subprogram gets an input from the keyboard using the ' GETINXEY subprograa, and also checks the PMD for an invalid entry.

ASTRS - "": AS - "": CREFt » POS(O): RREFt - CSRLIN: C* - CREFt: R* » RREF* PERSON.WAITINGS - NOS

WHILE AS <> CHRS(13) AND PERSON. AITINGS « NOS AND AS <> CHRS(27) GOSUB CHECK.INKEY SELECT CASE ASC(AS) CASE 32 TO 217

ASTRS - ASTRS + AS PRINT AS; C* - C* + 1 CASE 8: ' - backspace character IF LEN(ASTRS) > 1 THEN

-29-

ASTRS - LEFTS(ASTRS, LEN(ASTRS) - 1)

LOCATE R*, C* - 1: PRINT " ": LOCATE R*, C* - 1 ELSE

ASTRS - ""

LOCATE RREF*, CREF*: PRINT " ": LOCATE RREF*. CREF* END IF

CASE 27: ' - for the ESC key

ESCHITS - "YES" CASE ELSE END SELECT WEND RETURN

GET. AL.DATA: ' - routine to get the calibration data for the employee Et - INDEX.NUM*

CALPARMS(l) - DACTLASTS(Et): CALPARMS(2) - DACTFIRSTS(Et)

CALPARMS(3) - DACTINITS(E*): CALPARMS(4) - RTRIMS(LTRIMS(STRS(DEMPNO*(Et)) )) CAI_PARMS(5) - DSEX(Et)

CALPARMS(6) - RTRIMS(LTRIMS(STRS(DHEIGHTfE*)))) CALPARMS(7) - RTRIMS(LTRIMS(STRS(DWEIGHT(E*))) ) CALPARM$(8) - DBRIDGE(E*)

CALPARMS(9) - DIMPLANT(E*) : CALPARMS(IO) « DPACE(Et) CALPARMS(ll) - DOTHER$(E*) RETURN

GET.STATS: ' - routine to get the mean and standard deviation for feature FOR It - 1 TO NUM.FEATURES* SUM - 0

FOR Jt - 1 TO MAX.PASSNUM*: SUM » SUM + CALFEATURE(J*, I*) : NEXT Jt AMEAN - SUM / MAX.PASSNUM* SUM - 0 FOR Jt - 1 TO MAX.PASSNUM*

SUM - SUM + (-CALFEATURE(J*, It) - AMEAN) 2

NEXT Jt ASTDEV - SQR(SUM / MAX.PASSNUM*)

IF ASTDEV < LIM.STDEV(H) THEN ASTDEV » LIM.STDEV(I*) D.STDEV(INDEX.NUM*, I*) » ASTDEV DMEAN(INDEX.NUMt, I*) - AMEAN NEXT It RETURN

PRINT.STATS: ' - routine to print the mean and standard deviations calculated. LOCATE 13 •> MAX. ASSNUM* + 1, I: PRINT "MEAN "; FOR It - 1 TO NUM.FEATURES*

PRINT USING "fffff.f"; DMEAN(INDEX.NUM*, It); NEXT It: PRINT

LOCATE 13 + MAX.PASSNUM* + 2, 1: PRINT "ST.DEV "; FOR I* - 1 TO NUM.FEATURESt

PRINT USING "##.#*._"; DSTDEV(INDEX.NUMt, I*); NEXT It: PRINT RETURN

CHECK.STATS: ' - routine to determine the mean and standard deviations ' are consistent with the employee's data.

' - first, the values must all fall within 2 standard deviations I* - 1: REDO.PASS* - 0 WHILE I* <- NUM.FEATURES* AND REDO.PASS* - 0

HIVAL •> DHEAN(INDEX.NUM*, It) + CAL.NSTDEVfl*) * DSTDEV(INDEX.NUM*, I*) LOVAL - DMEAN(INDEX.HUM*, It) - CAL.NSTDEV(I*) * DSTDE (INDEX.NUM*, I*) PASS* - 1 WHILE PASS* <- MAX.PASSNUM* AND REDO.PASS* - 0

IF CALFEATURE(PASSt, It) > HIVAL OR CALFEATURE(PASS*, I*) < LOVAL THEN REDO.PASS* - PASSt: CHECK.FEATURE* - It: STATS.OKS = NOS CALL BLANKLINE(25)

PRINT "Feature "; CHECK.FEATUREt: " on Pass "; REDO.PASSt; PRINT ; " isn't ok - press return. "; GOSUB CHECK.INKEY END IF PASSt - PASSt + 1 WEND It - It + 1 WEND ' - now to-ensure the data is consistent with the employee height,weight and ' other information.

RETURN

PUT.CAL.BORDER: • - routine to plot the border for the calibration plots. DPWt « 83: DPVHt - 100

SPACE.Ht - 139 -. DPVHt * (PASSNUM* - 4 * INT((PASSNUM* - 1) / 4)) SPACE.V* » 0 + DPWt * INT((PASSNUM* - 1) / 4)

VIEW (SPACE.Ht, SPACE.V*)-(SPACE.H* + DPVH*, SPACE.V* + DPWt) WINDOW (LBNDt, LBNDt)-(UBNDt, UBND*) CLS 1

PSET (LBNDt, LBNDt)

LINE -(LBNDt, UBNDt): LINE -(UBNDt, UBNDt): LINE -(UBNDt, LBND*) LINE -(LBND*, LBND*) RETURN

OPERATE: ' - routine to operate the PMD in normal operation.

MAX.SAMPLES.BEFORE.EVENT* • OPERATE.MAX.DELAY.TIMEt * INTERRUPT.RATE

ALARM.ONS - NOS: NEED.TO.BLANKS - YESS

SCREEN 10, , 1, 1: CLS 0: COLOR 1

LOCATE 1, 1: PRINT CHRS(201) + STRING$(27, 205) + CHRS(187);

LOCATE 2, 1: PRINT CHRS(186) + SPACES(27) + CHRS(186);

LOCATE 3, 1: PRINT CHR$(186) + SPACES(27) + CHRS(186);

LOCATE 4, l: PRINT CHRS(200) + STRINGS(27, 205) + CHRS(188) ;

COLOR 3

LOCATE 2, 5J PRINT "THE WISE COMPANY'S"

LOCATE 3, 3: PRINT "PRECIOUS METAL DETECTOR"

LOCATE 5, β: PRINT "OPERATION MODE": COLOR 1

LASTKEYS - "": F1HITS - NO$

EVENTt - 0: COUNTt - -1: TOTAL.COUNT* - -1: OLDTIME - TIMER

IRT* - COUNTt - SAMPLES.IN. ISETIME*: IHT* - COUNT* - SAMPLES.IN. ISETIME* /

-31-

WHILE F1HITS - NOS • In the OPERATE mode an employee number is entered from the keyboard. EMPNO* - 0

CALL READ.KEYBOARD: ' - returns EMPNO* IF EMPNO* > 0 THEN PERSON.WAITINGS » YESS IF PERSON.WAITINGS - YESS THEN GOSUB PROCESS.PERSON.WAITING ELSE ' - situation when there is nobody waiting to walk through the PMD. GOSUB CHECK.INVALID.ENTRY END IF

GOSUB CHECK.KEYBOARD: ' - returns F1HITS ESCHITS - NOS

IF AS » CHRS(4) THEN ' - CNTL T pressed for changing the time OP. OWt - CSRLIN: OP.COL* - POS(O) SCREEN 10, , 0, 0 SHELL "DATE": SHELL "TIME"

SCREEN 10, , 1, 1: LOCATE OP.ROW*, OP.COL* END IF WEND RETURN

EMP.DATA.SAVE.ERROR: • - routine to check for Drive B

LPRINT : LPRINT CHRS(27) + "Wl"; : LPRINT CHRS(27) + "wl"; PRINT "EMPLOYEE DATA IS NOT SAVED"

LPRINT CHRS(27) + "WO"; : LPRINT CHRS(27) + "WO"

DRIVE.ERRORS - YESS

RESUME NEXT

PROCESS.PERSON.WAITING: • - routine to control the procedure for the person 1 waiting to pass through the PMD.

FOR I* - 1 TO NUM.OPERATE.ALERTS*: OPERATE.ALERT*(It) - 0: NEXT I* PERSON.WAITINGS - YESS

CALL CHECK.ID: • routine returns PERSON.CALIBRATED?, ALARMS and PERSON.IN.DATABASES

- If a person is waiting to go through the PMD, then the 'GO' light will be activated, and the person iε expected to go through the unit. The ALARM.ONS ■ YESS occurs when excessive noise is detected. When this condition exists, access to the portal is denied until the noise goes away.

WHILE ALARM.ONS • YESS

GOSUB CHECK.INVALID.ENTRY

WEND

- For the person who is in the database and is calibrated, access to the PMD is granted, and the persons signal is digitized and processed. PASS.ALERT* - 0 Et - INDEX.NUMt

IF INDEX.NUM* > 0 THEN

AINITS - DACTINITS(Et)

ANAMES » DACTFIRSTS(Et) + " " + LEFTS(AINITS, 1) + " " + DACTLASTS(E*) ELSE

ANAMES - « UN-KNOWN " END IF

GOSUB DEFINE.OPERATE.BORDER

GOSUB PLOT.OPERATE.BORDER: ' - selects SCREEN 10, ,1,1(page 1) LOCATE 8, l: PRINT SPACES(30): LOCATE 8, 1: PRINT ANAMES; OP.COL* - POS(O) + 2: OP. OW* - 8 CALL GET.DATA IF ABS(XAVG* - X.AT.COMP*) > RECOMP.CHECK* THEN

CALL COMPENSATE ELSE

IF ΛBS(YAVG* - Y.AT.COMPt) > RECOMP.CHECKt THEN CALL COMPENSATE END IF

GOSUB BELAY. ALK CALL GETSIGNATURE IF PASS.ALERTt - 0 THEN

CALL GETFEATURES(O)

IF PASS.ALERTt - 0 THEN GOSUB COMPARE.FEATURES END IF

PERSON.CLEANS - YESS IF ALARMS - YESS THEN

PERSON.CLEANS - NO$ _E-C_S_E

GOSUB RANDOM.ALARM END IF IF ALARMS - YESS THEN

GOSUB RELAY.ALARM ELSE

LPRINT MONTHS; " "; MIDS(DATES, 4, 2); " at "; TIMES; " ";

LPRINT "Employee "; ANAMES; " clean."

OUT PDISOt, PDISO.WAIT* + PDISO.CLEAN*

ON T-_MER(CLEAN.TIMEt) GOSUB CLEAN.OFF

TIMER ON END IF

' - now I need to update the mean and standard deviation values used. IF PERSON.CLEANS - "YES" THEN Et - INDEX.NUMt FOR It - 1 TO NUM.FEATURES*

DHEAN(Et, It) - (DMEAN(Et, It) * SBM* + FEATUREfl*)) / SB* ADEL - ABS(FEATURE(It) - DMEAN(Et, It)) IF ADEL > LIM.STDEV(I*) THEN

IF ADEL < DSTDEV(E«, It) OR ADEL < 1.5 * LIM.STDEV(It) THEN NEW.STDEV - (DSTDEV(E*, I*) * SBM* + ADEL * 2) / SB* IF NEW.STDEV < DSTDEV(£t, I*) THEN DSTDEV(E*, I*) - NEW.STDEV END IF END IF NEXT It END IF

LOCATE OP. OW*, OP.COL* IF ALARMS - YESS THEN

COLOR 2: PRINT " alarmed.": COLOR 1 ELSE

PRINT " clean." END IF

PERSON. AITINGS - NOS

EVENT* - 0: COUNT* » -1: TOTAL.COUNT* - -1: OLDTIME - TIMER

IRTt » COUNTt - SAMPLES.IN.RISETIME*

IHT* - COUNTt - SAMPLES.IN.RISETIME* / 2

RETURN

DEFINE.OPERATE.BORDER: ' - routine to define the border for the operate mode. DOTS.PER.VIEW.V* - VIEW.LENGTH / 13.9 * 350 DOTS.PER.VIEW.H* «• VIEW. ENGTH / 20.4 * 640 SPACE.H* - 639 - DOTS.PER.VIEW.H*

VIEW (SPACE.H*, 1)-(SPACE.H* + DOTS.PER.VIEW.H*, 1 + DOTS.PER.VIEW.V%) WINDOW (LBNDt, LBNDt)-(UBNDt, UBNDt) CLS 1 RETURN •

PLOT.OPERATE.BORDER: ' - routine to plot the border SCREEN 10, , 1, 1 VIEW PRINT 7 TO 24: CLS 2

VIEW (SPACE.Ht, l)-(SPACE.Ht + DOTS.PER.VIEW.Ht, 1 + DOTS.PER.VIEW.V*) WINDOW (LBNDt, LBNDt)-(UBNDt, UBNDt) CLS 1

PSET (LBNDt, LBNDt)

LINE -{LBNDt, UBNDt): LINE -(UBNDt, UBNDt): LINE -(UBNDt, LBNDt) LINE -(LBNDt, LBNDt) RETURN

COMPARE.FEATURES: ' - routine to compare signature features with cal. features. Et - INDEX.NUMt: NALARMt - 0 FOR It - 1 TO NUM.FEATURES*

IF F»EATURE{I*) < DMEAN(Et, It) - OP.NSTDEV(It) * DSTDEV(E*, I*) THEN NALARMt - NALARMt + 1 ALARMNUMt(NALARMt) - I* END IF NEXT It FOR It ■ 1 TO NUM.FEATURES*

IF FEATURE(It) > DMEAN(E*, I*) + OP.NSTDEV(I*) * DSTDEV(E*, It) THEN NALARM* - NALARMt + 1

ALARMNUMt(NALARMt) - I* + NUM.FEATURES* END IF NEXT It

IF NALARMt > 0 THEN ALARMS - YESS OPERATE.ALERT*(6) - 1 END IF

NF* - NUM.FEATURES*

COLOR 1: LOCATE 16, 1

PRINT " DELX DELY DIF.AN MID.AN ANGL1 ANGL2 ANGRl ANGR2";

PRINT " DELYL DELYR"

PRINT " MEAN ";

FOR It - 1 TO NFt: PRINT USING "fffff.f"; DMEANfE*, It); : NEXT I*

PRINT : PRINT " ST.DEV ";

FOR I* - 1 TO NFt: PRINT USING "fffff.f"; DSTDEV(Et, It); : NEXT I*

PRINT : PRINT "FEATURES";

FOR It - 1 TO NFt

FOR Jt » 1 TO NALARMt

IF ALARMNUMt(Jt) - I* OR ALARMNUH*( *) - I* + NUM.FEATURES* THEN

COLOR 3: J* - NALARM* + 1 ELSE

COLOR 1 END IF NEXT J*

PRINT USING "fffff.f"; FEATURE(I*) ; NEXT It COLOR 1 PRINT RETURN

RELAY.WALK: • - routine to indicate to walk through the PMD. PORTVALt - INP(PDISOt) OR PDISO.GO* OUT PDISO*, PORTVALt

CALL BLANKLINE(23): PRINT "Okay for "; DACTFIRSTS(Et) ; " "; DACTINITS(Et) ; PRINT " "; DACTLASTS(Et); " to walk through."; SOUND 100, 3: SOUND 50, 2 RETURN

RANDOM.ALARM: ' - routine to select an employee at random. IF RND(l) * 100 < PERCENT.ALARM* THEN ALARMS - YESS OPERATE.ALERT*(7) - 1 END IF RETURN

ALARM.OFF: • - routine to turn the alarm off

PORTVALt - INP(PDISOt) AND (255 - PDISO.ALARM*) OUT PDISOt, PORTVALt TIMER OFF RETURN

CLEAN.OFF: • - routine to turn the CLEAN light off PORTVALt - INP(PDISOt) AND (255 - PDISO.CLEA t) OUT PDISOt, PORTVALt TIMER OFF RETURN

CHECK.KEYBOARD: • - routine to check if key 'Fl' has been hit AS - INKEYS: LASTKEYS - AS

IF AS - CHRS(123) THEN

ATIME •> TIMER: AS - "": F1HITS - NOS

WHILE TIMER - ATIME < 2 AND AS - "" AND F1HITS - NOS AS - INKEYS IF AS - CHRS(200) THEN AS - ""

WHILE TIMER - ATIME < 2 AND AS - "" AND F1HITS - NOS AS - INKEYS

IF AS - CHRS(O) + CHRS(59) THEN F1HITS - YESS WEND END IF WEND END IF RETURN

CHECK.INVALID.ENTRY: ' routine to check for excessive signal sources. CALL GET.DATA IF IHT* > 0 THEN

IF ABS(XAR*(COUNTt) XAR*(IHT*)) DEL.CHK.INV.S* THEN EVENT* - 1 IF ABS(Y Rt(COUNTt) YAR*(IHT*)) DEL.CHK.INV.S* THEN EVENT* •• 1 END IF

IF IRTt > 0 THEN IF ABS(XAR*(COUNT*) XARtfIRT*)) DEL.CHK.INV.S* THEN EVENT* » 1 IF ABS(YAR*(COUNT*) YAR*(IRTt)) DEL.CHK.INV.S* THEN EVENT* - 1 END IF IF EVENT* - 1 THEN EVENT* - 0 IF ALARM.ONS - NOS THEN

OUT PDISOt, PDISO.WAIT* + PDISO.ALARM* ALARM.ONS - YESS END IF ELSE

IF ALARM.ONS - YESS THEN GOSUB ALARM.OFF ALARM.ONS - NOS END IF END IF RETURN

RELAY.ALARM: ' - routine to set alarm and to display the alarm conditions. ' - turn on the relay to activate the 'ALARM' light. OUT PDISOt, PDISO.WAIT* + PDISO.ALARM* ON TIM-_R(ALARM.TIMEt) GOSUB ALARM.OFF TIMER ON FOR It - 1 TO NUM.OPERATE.ALERTS*

IF OPERATE.ALERT*(It) - 1 THEN ALERTNUM* » I* NEXT It

LPRINT MONTHS; " »; MIDS(DATES, 4, 2); " at "; TIMES; " "; IF ALERTNUM* - 1 THEN

LPRINT "Employee "; ANAMES;

SELECT CASE ALERTNUM*

CASE 2

LPRINT " is not calibrated." CASE 4

LPRINT " took too long to enter." CASE 5

LPRINT " took too long to walk through." CASE 6

LPRINT " -features";

FOR J* - 1 TO NALARM*: LPRINT " "; LTRIMS(STRS(ALARMNUMt(J*) )) ; : NEXT Jt

LPRINT " detected." CASE 7

LPRINT " selected randomly." CASE ELSE

LPRINT " alarm for unknown reason." END SELECT END IF RETURN

SET.BOARD: ' - routine to set up the frequency, phase, and gain. CALL TCINITIALIZATION NEWFREQt - TCFREQSET*(FREQi, PHASE*) NEWGAIN* - TCGAINSET*(GAINt) CALL COMPENSATE RETURN

SAVE.DATABASE: ' - routine to save the database

OPEN DATA.FILENAMES FOR OUTPUT AS fl

IF DRIVE.ERRORS - NOS THEN

WRITE fl, NUMBER.OF.EMPLOYEES*

IF NUMBER.OF.EMPLOYEES* > 0 THEN FOR It « 1 TO NUMBER.OF.EMPLOYEES* AIS • DACTLASTS(It)

A2S - DACTFIRSTS(It): A3S - DACTINITS(It) : A4t - DEMPNOt(I*) A5S - DSEX(It)

A6 - DHEIGHT(It): A7 - DWEIGHT(It) : A8S - DBRIDGE(It) A9S - DIMPLAN *) : AAS - DPACEd*): ABS - DOTHERS(It) WRITE fl, AIS, A2S, A3S, A4*, A5S, A6, A6S, A7, A8S, A9S, AAS, ABS Bl - DMEAN(I*, 1): B2 - DMEANd*, 2): B3 - DMEAN(I*, 3) B4 - DMEAHdt, 4): B5 - DMEAN(It, 5): B6 - DMEAN(I*, 6) B7 - DMEAN(I*, 7): B8 - DMEANJIt, 8): B9 « DMEAN(I*. 9) BA - DMEANd*, 10)

WRITE fl, Bl, B2, B3, B4, B5, B6, B7, B8, B9, BA Bl - DSTDEV(It, 1): B2 - DSTDEV(It, 2): B3 » DSTDEV(I*, 3) B4 - DSTDEV(I», 4): B5 - DSTDEVflt, 5): B6 - DSTDEV(I*. 6) B7 - DSTDEV(I*, 7): B8 - DSTDEV(I*, 8): B9 " DSTDEV(I*, 9) BA » DSTDEV(It, 10)

WRITE fl, Bl, B2, B3, B4, B5, B6, B7, B8, B9, BA NEXT I* END IF

DATA.CHANGES - N0$

CLOSE fl

END IF

-37-

RETURN

EMPLOYEE.DATABASE: ' - routine to read the employee database A - FRE("A"): B - FRE(O): C - FRE(l): D - FRE(-l) DATA.FILENAMES - "C:\PMD\DATA\EMPLOYE2.DAT" ON ERROR GOTO EMPLOYEE.DRIVE OPEN DATA.FILENAMES FOR INPUT AS fl ON ERROR GOTO 0

INPUT fl, NUMBER.OF.EMPLOYEES* IF NUMBER.OF.EMPLOYEES* > 0 THEN FOR It ■ 1 TO NUMBER.OF.EMPLOYEESt

INPUT fl, DACTLASTS(It), DACTFIRSTS(It) , DACTINITS(It)

INPUT fl, DEMPNO*(I*)

INPUT fl, DSEX(I»), DHEIGHTd*), DWEIGHT(I«) , DBRIDGE(It)

INPUT fl, DIMPLANT(It), DPACE(It) , DOTHERSd*)

FOR K* - 1 TO NUM.FEATURES*: INPUT fl, DMEAN *', K*) : NEXT K*

FOR K* - 1 TO NUM.FEATURES*: INPUT fl, DSTDEV(It, K*) : NEXT K*

NEXT It END IF CLOSE fl RETURN

EMPLOYEE.DRIVE: ' - routine to get the proper drive to read the ' employee database.

LOCATE 24, 10: PRINT "Cannot locate the data file "; DATA.FILENAMES ANSS - "Y" WHILE ANSS - "ϊ"

LOCATE , 2: INPUT "Do you wish to enter a DOS command? (Y/N) "; ANSS IF ANSS » "Y" THEN

LOCATE , 10: INPUT "Enter the DOS command "; DOSCOMMANDS SHELL DOSCOMMANDS

LOCATE , 1: INPUT "Press any key to continue"; AS END IF WEND LOCATE 24, 1: INPUT "Enter the new filename "; DATA.FILENAMES RESUME

CONSTANT.HEAD.DISPLAY: ' - routine to display the CONSTANT screen SCREEN 0: CLS FOR It - 1 TO NUM.CON.HEAD*

LOCATE CONHEADRt(It) , CONHEADC (I*)

PRINT CONHEADTSd*);

NEXT It COLOR 10 FOR It > 1 TO NUM.CON.PARMt

LOCATE CONROWtfIt), CONCOLt(It); PRINT LEFTS(SPACECHRS, CONSPCS*(It) ) ;

LOCATE CONROWt(It), CONCOLt(It): PRINT CONPARMS(It);

NEXT I* COLOR 3 RETURN

CONSTANT.DISPLAY.CHANGE: ' - routine to change the entries on the constant

display.

IPRMt - Is IPRMMAXt - NUM.CON.PARM* FOR I* - 1 TO IPRMMAX*

DATARt(It) -CONROWt(It): DATACt(It) - CONCOL1 (It) : SPCSt(lt) - CONiU'Cϋl(11) NEXT It ALLDATAS - "NOT OK" WHILE ALLDATAS - "NOT OK" FINISHS - NOS WHILE FINISHS - NOS COLOR 10

IF IPRMt > IPRMMAXt THEN IPRM* - 1 IF IPRM* <- 0 THEN IPRM* » IPRMMAX* SOUND 100, 3: SOUND 50, 2

ROWt - DATARt(IPRMt): COLUMNt - DATACt(IPRMt) LOCATE ROWt, COLUMNt CALL ADDNEWCHAR IF EXITS - YESS THEN

CALL BLANKLINE(25) : SOUND 100, 3: SOUND 50, 2

PRINT ; "Is it okay to quit without saving the changes? (Y/N) "; CALL GETINKEY: PRINT AS; IF AS - "Y" OR AS - "y" THEN RETURN CALL BLANKLINE(25) END IF WEND COLOR 3

GOSUB CONSTANT.SETUP.NAME ALLDATAS - "OK" WEND RETURN

CONSTANT.SETUP.NAME: ' - routine to name the constants FOR It - 1 TO NUM.CON.PARMt BS - " " FOR Jt » 1 TO CONSPCSt(It)

AS » CHRS(SCREEN(CONROWt(It), CONCOLt(It) + Jt - 1)) IF AS - ASPACECHRS THEN Jt - CONSPCSt(It) + 1 ELSE

BS - BS + λ$ END IF NEXT Jt

CONPARHS(It) - RTRIMS(LTRIM$(BS)) NEXT It

FREQfi - VAL(CONPARM$(l)): GAIN* - VAL(CONPARMS(2) ) PHASE* - VAL(CONPARMS(3)): DRANGEt - VAL(CONPARMS(4) ) LBNDt - -DRANGEt: UBNDt - DRANGEt X.DEL.CHX.St - VAL(CONPARM$(5)) X.DEL.CHK.Et - VAL(CONPARM$(6)) RECOMP.CHECKt - 2 * X.DEL.CHK.St

Y.DEL.CHX.St - X.DEL.CHK.St / 2: Y.DEL.CHK.Et - X.DEL.CHK.Et CALIBRATE.MAX.DELAY.TIME* - VAL(CONPARMS(7) ) OPERATE.MAX.DELAY.TIME* ■ VAL{CONPARMS(8) )

CLEAN.TIME* - VAL(CONPARMS(17) ) ALARM.TIME* - VAL(CONPARH$(18) ) PERCENT.ALARM* - VAL(CONPARM$(19)) PRINT.DISPLAYS - CONPARH$(20) VIEW.LENGTH - VAL(C0NPARM$(21) ) RETURN

ERROR.FOR. EAD.NAME: ' - error routine for reading names and employee f ERRNUM* - ERR REASONS - "" SELECT CASE ERRNUM* CASE 53

REASONS - "Cannot find file " + NAME.FILES CASE 62

REASONS - "Tried to read past the βhd of the file." CASE 71

REASONS « "Disk is not ready - please ensure disc drive is ready." CASE ELSE

REASONS - "Error number " + STRS(ERRNUM*)

REASONS - REASONS + " detected while accessing " + NAME.FILES END SELECT RESUME NEXT

FEATURE.ERROR: ' - routine to check on the error occuring in FEATURE. FOR I* - 1 TO NUM.FEATURES*: FEATURE(I*) - 0: NEXT I* PASS.ALERTt - 1 IF RUN.MODES - "OPERATE" THEN OPERATE.ALERT*(8) - 1 ALARMS - YESS END IF

CALL GETFEATURES(l) RESUME NEXT

SUB ADDNEWCHAR

' routine to add a character AS - "" EXITS ■ "NO" WHILE AS <> CHRS(13) CALL GETINXEY SELECT CASE ASC(λ$)

CASE 13: ' - to advance to the next field IPRM* - IPRM* + 1

IF IPRM* > IPRMMAX* THEN IPRM* - 1 CASE 32 TO 217: ' - standard characters PRINT AS; : AS » "": ct » POS(O)

IF (Ct - COLUMNt) >- SPCSt(IPRMt) OR Ct < COLUMNt THEN

IPRMt - IPRMt + 1: AS - CHRS(13)

IF IPRMt > IPRMMAXt THEN IPRMt - 1

END IF CASE 8: * - backspace and overwrite LOCATE Rt, Ct: PRINT ASPACECHRS LOCATE Rt, Ct - 1: AS - "": Ct » POS(0)

IF Ct < COLUMNt THEN LOCATE Rt, COLUMNt CASE 9: • - tab to the next field IPRMt ■ IPRMt + 1

IF IPRMt > IPRMMAXt THEN IPRM* - 1 AS - CHRS(13) CASE 27: • - escape key - used to exit data entry - no checking λ$ - CHRS(13) EXITS " "YES" CASE 0: ' - look at keys having 2 byte responses SELECT CASE ASC(RIGHTS(AS, 1))

CASE 15: ' - shift tab - go back a field IPRM* - IPRMt - 1

IF IPRMt <- 0 THEN IPRMt - IPRMMAXt AS - CHRS(13) CASE 75: ' - shift left 1 character LOCATE Rt, Ct - 1 AS - "": Ct - POS(0)

IF Ct < COLUMNt THEN LOCATE Rt, COLUMN* CASE 77: ' - shift right 1 character CP* - Ct + 1

IF CPt <- 80 THEN LOCATE Rt, CPt: AS - "": Ct - POS(O) IF (Ct - COLUMNt) >- SPCS*(IPRM*) OR C* - 80 THEN IPRH* - IPRM* + 1: AS » CHRS(13) IF IPRM* > IPRMMAX* THEN IPRM* - 1 END IF CASE 68: ' - F10 - exit menu FINISHS - "YES" AS - CHRS(13) CASE ELSE

AS - "" END SELECT CASE ELSE END SELECT WEND END SUB

SUB BLANKLINE (LINE.TO.BLANK*)

' - routine to blank line 'LINE.TO.BLANK'

LOCATE LINE.TO.BLANK*, 1

PRINT SPACES (80) ;

LOCATE LINE. TO. BLANK*, 1

EXIT SUB END SUB

SUB CHECK.ID

' - This subprograa checks to ensure the EMPNOt is in the ' the database and that the employee is calibrated. ' Alarm conditions are set accordingly.

PERSON.CALIBRATEDS - "NO": ALARMS •* "NO": PERSON.IN.DATABASES - "YES"

IF RUN.MODES - "OPERATE" THEN

• In the OPERATE' mode, PERSON.WAITINGS «"YES" and it is necessary to ' determine if a valid person is waiting based on whether the person 1 ia in the database, and whether the person has been calibrated. INDEX.NUMt - 0

FOR It - 1 TO NUMBER.OF.EHPLOYEESt IF EMPNOt - DEMPNOt(It) THEN

INDEX.NUM* - I*: I* - NUMBER.OF.EMPLOYEES* + 1 END IF NEXT I* IF INDEX.NUM* - 0 THEN

PERSON.IN.DATABASES - "NO" ALARMS - "YES"

OPERATE.ALERT*(1) - 1: ' - case for person not in the database. LPRINT "Person with employee number "; EMPNO*; LPRINT " is not in the database." END IF

1 - now need to make sure the employee has been calibrated IF PERSON.IN.DATABASES - "YES" THEN I* » INDEX. UM* IF DMEANd*, 1) <> 0 THEN

PERSON.CALIBRATED? - "YES" ELSE

ALARMS - "YES": PERSON.CALIBRATEDS - "NO" OPERATE.ALERT*(2) » 1: ' - case for person not calibrated. LPRINT "Employee "; DACTFIRSTS(It) ; " "; DACTINITSd*) ; " "; LPRINT DACTLASTS(I*) ; " is not calibrated." END IF END IF END IF

' - Now test for the CALIBRATE mode IF RUN.MODES - "CALIBRATE" THEN INDEX.NUMt - 0

FOR It - 1 TO NUMBER.OF.EHPLOYEESt IF DEMPNOt(It) - EMPNOt THEN

INDEX.NUMt - It: It - NUMBER.OF.EMPLOYEESt + 1 END IF NEXT It IF INDEX.NUMt - 0 THEN

PERSON.IN.DATABASES - "NO": PERSON.CALIBRATEDS - "NO" ELSE

IF DMEAN(INDEX. UMt, 1) - 0 THEN PERSON.CALIBRATEDS » "NO" END IF END IF EXIT SUB

END SUB

SUB COMPENSATE

' - Routine to balance the signal

COMPCHECKt - TCCOMPENSATIONt(SEG COMP#(0))

FOR Jt ■ 1 TO 4: FOR It - 1 TO TIMELOOPt: NEXT It: NEXT Jt

CALL GET.DATA

XREF* - XAVGt: YREF* - YAVG*

X.AT.COMP* ■ XAVGt: Y.AT.COMP* - YAVG*

IF COMPCHECK* <> 0 THEN

LOCATE 21, 1: PRINT "Compensation not possible COMPCHECK*""; COMPCHECK*

FOR I - 1 TO 3: PRINT COHPf(I); : NEXT I

BEEP

INPUT ; " Press return to continue ", AS END IF EXIT SUB END SUB

SUB COPY.EMPLOYEE.DATA (OLD*, NEW*)

' this routine copies data from OLD* to-NEW*

DEMPNOt(NEWt) - DEMPNO*(OLD*)

DACTLASTS(NEW*) - DACTLASTS(OLD*)

DACTFIRSTS(NEW*) - DACTFIRSTS(OLD*)

DACTINITS(NEW*) « DACTINITS(OLD*)

DSEX(NEWt) - DSEX(OLD*): DHEIGHT(NEWt) - DHEIGHT(OLDt)

DWEIGHT(NEWt) » DWEIGHT(OLDt) : DBRIDGE(NEWt) - DBRIDGE(OLDt)

DIMPLANT(NEWt) » DIMPLANT(OLDt) : DPACE(NEWt) - DPACE(OLDt)

DOTHERS(NEWt) - DOTHERS(OLDt)

FOR It « 1 TO NUM.FEATURES*

DMEAN(NEW*, It) - DMEANfOLDt, It) DSTDEV(NEWt, It) - DSTDEV(OLD*, I*)

NEXT I*

EXIT SUB END SUB

SUB DELETE.EMPLOYEE.FROH.DATABASE 1 - routine to subtract an employee Jt - INDEX.NUMt + 1 WHILE Jt <» NUMBER.OF.EHPLOYEESt

JMt - Jt - 1

DEMPNOt(JMt) - DEMPNOt(Jt)

DACTLASTS(JMt) - DACTLASTS(Jt)

DACTFIRSTS(JHt) - DACTFIRSTS(Jt) : DACTINITS(JMt) - DACTINITS(Jt)

DSEX(JMt) - DSEX(Jt): DHEIOHT(JMt) - DHEIGHT(Jt)

DWEIGHT(JMt) - DWEIGHT(Jt): DBRIDGE(JMt) - DBRIDGE(Jt)

DIMPLANT(JHt) - DIMPLANT(Jt) : DPACE(JMt) - DPACE(Jt)

DOTHERS(JMt) - DOTHERS(Jt)

FOR Kt - 1 TO NUM.FEATURESt

DMEAN(JMt, Kt) - DMEAN(Jt, Kt) DSTDEV(JMt, Kt) - DSTDEV(Jt, Kt)

NEXT Kt

Jt - Jt -> 1 WEND

Jt - NUMBER.OF.EHPLOYEESt DEMPNOt(Jt) - 0: DACTLASTS(Jt) » "" DACTFIRSTS(Jt) - "": DACTINITS(Jt) « "" DSEX(Jt) - "": DHEIGHT(Jt) - 0: DWEIGHT(Jt) - 0: DBRIDGE(Jt) - ""

DIMPLANT(Jt) - "": DPACE(Jt) - "": DOTHERS(Jt) - "" FOR Kt » 1 TO NUM.FEATURESt

DMEAN(Jt, Kt) - 0

DSTDEV(Jt, Kt) - 0 NEXT Kt

NUMBER.OF.EHPLOYEESt > NUMBER.OF.EMPLOYEESt - 1 DATA.CHANGES - "YES" EXIT SUB

END SUB

SUB DISPLAY.DATABASE 1 - routine to display the database EMAX* « NUMBER.OF.EHPLOYEESt REDIM SEQ.NUM*(EMAX*) , SORTED*(EMAX*) SCREEN 0• CI_S • COLOR 3.0

LOCATE 1, 20: PRINT CHR$(201) + STRINGS(21, CHRS(205)) + CHRS(187) LOCATE 2, 20: PRINT CHR$(186) + " DATABASE VALUES " + CHRS(186) LOCATE 3, 20: PRINT CHRS{200) + STRINGS(21, CHRS(205)) + CHRS(188) CALL BLANKLINE(25): COLOR 10, 1: PRINT "Press 'Esc' key to exit."; COLOR 2: LOCATE 5, 2

PRINT "Do you want a print-out (P) or a display (D) of the database ? CALL GETINKEY: PRINT AS

IF AS " CHRS(27) THEN VIEW PRINT: CLS : EXIT SUB GOSUB PRINT.RESEQUENCE IF AS - "P" OR AS - "p" THEN

DBHEADS - "PRECIOUS METAL DETECTOR - DATABASE"

DATE.TIMES - "Date : " + DATES + " Time : " + TIMES

NUMBER.PER.PAGE* - 50

IBOTt - 0: PAGENUMt - 0: I* ■ 1

LPRINT CHRS(27) + "n"; : ' - sets printer to NLQ pica pitch PRINT "Positon the page in the printer to the top of the page." INPUT ; " Press return to continue. ", AS LPRINT CHRS(27) + "β": • - initialize the printer WHILE It <- NUMBER.OF.EMPLOYEES*

PAGENUMt - PAGENUMt + 1

ITOPt ■» IBOTt + 1: IBOTt - IBOTt + NUMBER.PER.PAGE*

IF PAGENUMt > 1 THEN LPRINT CHRS(12): ' - form feed

LPRINT " "; DATE.TIMES; SPACES(65 - LEN(DATE.TIMES)) i

LPRINT "Page "; PAGENUMt: LPRINT

LPRINT SPACES(40 - LEN(DBHEADS) / 2); DBHEADS

LPRINT SPACES(40 - LEN(DBHEADS) / 2 - 1) ;

LPRINT STRINGS(LEN(DBHEAD?) + 2, "-")

LPRINT " EMPLOYEE"

LPRINT " NUMBER LAST NAME FIRST NAME INITIAL ";

LPRINT "CALIBRATED"

LPRINT " ——— ";

LPRINT " "

WHILE It <- NUMBER.OF.EHPLOYEESt AND It <- IBOTt J* - SEQ.NUM*(I*) LPRINT USING "ffffffff"; DEMPNOt(Jt);

LPRINT " " ;

LPRINT USING "\ \"; DACTLASTS(J*) ;

LPRINT USING "\ \"; DACTFIRSTS(Jt) ;

LPRINT USING "\ \ "; DACTINITS(J*) ;

LPRINT " ";

IF DMEAN(J», 1) <> 0 THEN

LPRINT "YES"; ELSE

LPRINT " NO"; END IP* IF LEN(DACTINITS(J*)) > 1 THEN

IF RIGHTS(DACTINIT (J*), 1) - "V" THEN LPRINT " V" IF RIGHTS(DACTINITS(J*), 1) - "T" THEN LPRINT " T" ELSE

LPRINT END IF It - It + 1 WEND WEND

'LPRINT CHRS(27) + "P"; :' - reset to draft mode LPRINT CHRS(12): ' - form feed ELSE

LOCATE 5, 1: PRINT SPACES(79); : LOCATE 4, 1

PRINT " EMPLOYEE"

PRINT " »; : COLOR l: PRINT "NUMBER"; : COLOR 2: PRINT "

COLOR 1: PRINT "LAST NAME"; : COLOR 2: PRINT " ";

COLOR 1: PRINT "FIRST NAME"; : COLOR 2: PRINT " ";

COLOR I: PRINT "INITIAL"; : COLOR 2: PRINT " ";

COLOR 1: PRINT "CALIBRATED": COLOR 2

VIEW PRINT 6 TO 24

IEND* - 18

I* - 1

WHILE It <• NUMBER.OF.EHPLOYEESt

WHILE It <- lENDt AND It <- NUMBER.OF.EMPLOYEESt Jt - SEQ.NUMt(It)

PRINT USING "ffffffff"; DEMPNOt(Jt); PRINT " ";

PRINT USING "\ \"; DACTLASTS(Jt) ;

PRINT USING "\ \"; DACTFIRSTS(Jt) ;

PRINT USING "\ \ "; LEFTS(DACTINITS(J*) , 1) ; PRINT " "; IF DMEAN(J*. 1) <> 0 THEN

PRINT "YES"; ELSE

PRINT " NO"; END IF IF LEN(DACTINITS(J*)) > 1 THEN

IF RIGHTS(DACTINITS(J*), 1) - "V" THEN PRINT " V" IF RIGHTS(DACTINITS(J*), 1) - "T" THEN PRINT " T" ELSE

PRINT END IF

-45-

It - It + 1

WEND

AROWt - CSRLIN: ACOL* » POS(0)

IEND* - I* + 18

CALL BLANKLINE(25)

INPUT ; "Press return to continue", AS

LOCATE AROWt, ACOL* WEND END IF VIEW PRINT EXIT SUB

PRINT.RESEQUENCE: • - routine to determine the sequence to print the data ' in an alphabetical order.

NSORTt - 0: LSORTPOSt - 0: HSORTPOS* - EMAX* + 1 WHILE NSORT* < EMAX* FOR It - 1 TO EMAX*

IF SORTED*(I*) - 0 THEN

MINS - DACTLASTS(I*) + DACTFIRSTS(I*) + DACTINITS(I*) MAXS - MINS

SORTL* - I*: SORTH* - I* It - EMAXt + 1 END IF NEXT It FOR It - 1 TO EMAXt

IF SORTEDt(It) « 0 THEN

ASTRS - DACTLASTS(It) + DACTFIRSTS(It) + DACTINITSd*) IF ASTRS < MINS THEN MINS - ASTRS: SORTL* - I* IF ASTRS > MAXS THEN MAXS = ASTRS: SORTH* - I* END IF NEXT I*

NSORT* » NSORTt + 1 LSORTPOSt - LSORTPOSt + 1 SEQ.NUMt(LSORTPOSt) - SORTL* SORTEDt(SORTLt) - 1 IF SORTLt <> SORTHt THEN NSORTt » NSORTt + 1 HSORTPOSt - HSORTPOSt - 1 SEQ.NUMt(HSORTPOSt) - SORTHt SORTEDt(SORTHt) - 1 END IF WEND RETURN

END SUB

SUB GET.DATA

1 - routine to collect a sample

1 This routine is used when checking for an invalid entry, and when the

' balancing of the card is required.

CALL TCACQUISITION(SEG λ*(0)): Z* - 1: SXt « λ*(0): SY4 - λ*(l)

OLDTIME - TIMER

WHILE TIMER - OLDTIHE

CALL TCACQUISITION(SEG λ*(0))

SXi » SXt + A*(0): SYi - SYβ + A*(l): Z* - Z* + 1 WEND

XAVG* » SXi / Zt: YAVGt - SYS / Zt OLDTIME - NEWTIME

COUNTt - COUNTt + l: IF COUNTt > MAX.SAMPLES.FOR.EVENTt THEN COUNT* - 0 IRT* - IRT* + l: IF IRT* > MAX.SAMPLES.FOR.EVENT* THEN IRT* « 0 IHT* - IHT* + 1: IF IHT* > MAX.SAMPLES.FOR.EVENT* THEN IHT* - 0 XAR*(COUNTt) - XAVGt YARt(COUNTt) - YAVGt EXIT SUB END SUB

SUB GET.DAYS.FROM.1990

' - this procedure gets the number of days since JAN 1,1990

ADATES M DATES

YRENDt - VAL(RIGHTS(ADATES, 4))

ANUM& - 0: YR* - 1990

WHILE YR* < YRENDt

ANUMt - ANUMt + 365

IF (YRt MOD 4) - 0 THEN ANUMt » ANUMt + 1

YRt - YRt + 1 WEND

MONTHENDt - VAL(LEFTS(ADATES, 2)) MONTHt ■ 1 WHILE MONTHt < MONTHENDt

ANUMt - ANUMt + DM*(MONTH*)

MONTH* - MONTH* + 1 WEND IF (YRENDt MOD 4) - 0 THEN

IF MONTHENDt > 2 THEN ANUMt - ANUMt + 1 END IF

DAYS.FROM.1990t - ANUMt + VAL(HIDS(ADATES, 4, 2)) EXIT SUB

END SUB

SUB GETFEATURES (conditiont)

' - Procedure to determine the features in the detected event

' -Features include amplitude maximums, mean slopes,

' and idrangβ Y separations.

IF conditiont - 1 THEN GOTO END.FEATURE.ERROR

' - need to adjust the values to allow for some drift

NAVGt - 4 ' - get average value for the first point at the start of the εignal

SUMX - 0: SUMY - o

1ST* ■ It IEND* - 1ST* + NAVGt - 1: IREFST* • IEND*

FOR It - ISTt TO lENDt: SUMX - SUMX + X*(It): SUMY - SUMY + Y*(I*) : NEXT I*

AVGXST - SUMX / NAVG*: AVGYST « SUMY / NAVGt

- get average value for the last point at the end of the signal SUMX » 0: SUMY » 0

ISTt - NSAMPt - NAVGt + 1: IEND* - NSAMPt: IREFENDt - ISTt

FOR It - ISTt TO IENDt: SUMX - SUMX + X*(I*): SUMY - SUMY + Y*(I*): NEXT It

AVGXEND - SUMX / NAVG*: AVGYEND - SUMY / NAVG*

DELXPERPOINT - (AVGXEND - AVGXST) / (IREFENDt - IREFSTt)

DELYPERPOINT » (AVGYEND - AVGYST) / (IREFENDt - IREFSTt)

- adjust values to make end points match J* - 1

FOR I* - IREFST* + 1 TO IREFENDt - 1

Jt - Jt + 1

Xt(Jt) - Xt(It) - DELXPERPOINT * (J* - 1)

Y*(J*) » Y*(It) - DELYPERPOINT * (J* - 1) NEXT I*

NSAMP* - J* + 1

X*(l) - AVGXST: Y*(l) - AVGYST Xt(NSAMPt) - X*(l): Yt(NSAMP*) - Y*(l)

- now I need to find the maximum ranges and the points where they occur. XMIN* - X*(l): XMAX* - X*(l)

YMIN* - Y*(l): YMAX* » Y*(l)

CXMIN* - 0: CXMAX* - 0: CYMINt - 0: CYMAX* - 0

FOR I* » 1 TO NSAMP*

IF X*(I*) < XMINt THEN XMINt - Xt(It): CXMIN* I*

IF X*(It) > XMAX* THEN XMAX* - Xt(It): CXMAX* I*

IF Yt(It) < YMIN* THEN YMIN* - Y*(It): CYMIN* I*

IF Yt(It) > YMAX* THEN YMAX* - Y*(I*): CYMAX* I*

NEXT It

IF CXMIN* > 2 THEN XMINt «■ (Xt(CXMINt - 1) + XMINt X*(CXMIN* D>

IF CXMAX* > 2 THEN XMAXt - (Xt(CXMAXt - 1) + XMAXt X*(CXMAX* D>

IF CYMIN* > 2 THEN YMINt - (Yt(CYMIN* - 1) + YMIN* Yt(CYMIN* D)

IF CYMAXt s 2 THEN YMAX* - (Yt(CYMAXt - 1) + YMAXt Y*(CYMAX* D) DELXMAXt - XMAX* - XMIN* DELYMAX* - YMAXt - YMINt FEATURE(1) - DELXMAXt: FEATURE(2) - DELYMAX*

- now I need to get the slope between the points determine from the maximum change IF DELXMAX* > DELYMAX* THEN IF CXMIN* < CXMAX* THEN

1ST* - CXMIN*: IEND* - CXMAX*: GOSUB GET.SLOPE ANG - RADTODEG * ATN(SLOPE) ELSE

ISTt - CXMAXt: IENDt - CXMIN*: GOSUB GET.SLOPE ANG - RADTODEG * ATN(SLOPE) + 180 END IF ELSE

IF CYMINt < CYMAXt THEN

ISTt - CYMINt: IENDt - CYMAXt GOSUB GET.SLOPE ANG - RADTODEG * ATN(SLOPE) IF SLOPE < 0 THEN ANG - ANG + 180

________

1ST* - CYMAX*: IENDt - CYMINt: GOSUB GET.SLOPE

ANG - RADTODEG * ATN(SLOPE)

IF SLOPE > 0 THEN ANG » ANG - 180 END IF END IF

IF SLOPE - 9999 THEN ANG » 999 FEATURE(3) - ANG

- now I will get the slope between the middle of the left wing and the middle of the right wing obtained as the signal goes from left to right.

XLOC.LEFTt - (XMIN* -I- X*(l)) / 2

XLOC.RΣGHT* - (XMAXt + Xt(NSAMPt)) / 2

I* - CXMIN*: CHECKX* - XLOC.LEFT*

WHILE I* <- NSAMP* AND X*(It) < CHECKX* ' : I* - I* + 1: WEND: 1ST* - I* - 1

I* - CXMAX*: CHECKX* - XLOC.RIGHT*

WHILE I* >•> 0 AND X*(I*) > CHECKX*: I* « I* - 1: WEND: IEND* - I* + 1

GOSUB GET.SLOPE

IF SLOPE - 9999 THEN

ANG - 999 ELSE

ANG - RADTODEG * ATN(SLOPE) END IF FEATURE(4) - ANG

- now I will get the slope and mean Y values at the midpoints between the balance points and the left and right extremes of the X-signal

- first to get the values on the left of the balance point DX.LEFT* - ABS((X*(1) - XMIN*)) / 5

I* - CXMIN*: CHECKX* ■ XLOC.LEFT* - DX.LEFT*

WHILE I* >- 0 AND X*(I*) < CHECKX*: It - It - 1: WEND: IENDt - It + 1

It - CXMINt: CHECKXt - XLOC.LEFTt + DX.LEFTt

WHILE It >« 0 AND Xt(It) < CHECKXt: It - I* - 1: WEND: ISTt - It

GOSUB GET.SLOPE

IF SLOPE - 9999 THEN

ANG.LEFT1 - 999: YMEAN.LEFT1 - 999 ELSE

YMEAN.LEFT1 - SUMY / NP: ANG.LEFT1 - RADTODEG * ATN(SLOPE) + 180 END IF

I* - CXMINt: CHECKX* - XLOC.LEFT* - DX.LEFT*

WHILE I* <- NSAMPt AND Xt(It) < CHECKXt: It - It + 1: WEND: 1ST* - I* - 1

I* - CXMINt: CHECKXt - XLOC.LEFTt + DX.LEFTt

WHILE It <- NSAMPt AND Xt(It) < CHECKXt: It - I* + 1: WEND: IEND* - I*

GOSUB GET.SLOPE

IF SLOPE - 9999 THEN

ANG.LEFT2 - 999: YMEAN.LEFT2 » 999 ELSE

YMEAN.I_SFT2 - SUMY / NP: ANG.LEFT2 - RADTODEG * ATN(SLOPE) END IF

' - now to get the values on the right of the balance point

DX.RIGHTt - (XMAXt - Xt(NSAMP*)) / 5

I* - CXMAX*: CHECKX* - XLOC.RIGHT* + DX.RIGHT*

WHILE I* >- 0 AND X*(I*) > CHECKX*: I* - I* - 1: WEND: IEND* - I* + 1

I* - CXMAX*: CHECKX* - XLOC.RIGHT* - DX.RIGHT*

WHILE I* >- 0 AND X*(It) > CHECKX*: It * I* l: WEND: 1ST* I*

GOSUB GET.SLOPE

IF SLOPE - 9999 THEN

ANG.RIGHT1 - 999: YMEAN.RIGHT1 - 999 ELSE

YMEAN.RIGHT1 - SUMY / NP: ANG.RIGHT1 RADTODEG * ATN(SLOPE) END IF

I* - CXMAX*: CHECKX* - XLOC.RIGHT* + DX.RIGHT*

WHILE It <» NSAMPt AND Xt(It) > CHECKX*.: I* - I* + 1: WEND: 1ST* - I* - 1

I* - CXMAX*: CHECKX* - XLOC.RIGHT* - DX.RIGHT*

WHILE I* <- NSAMP* AND X*(It) > CHECKXt: It - It + 1: WEND: IENDt - I*

GOSUB GET.SLOPE

IF SLOPE - 9999 THEN

ANG.RIGHT2 - 999: YMEAN. IGHT2 - 999 ELSE

YMEAN.RIGHT2 » SUMY / NP: ANG.RIGHT2 >» RADTODEG * ATN(SLOPE) + 180 END IF

FEATURE(5) » ANG.LEFT1: FEATURE{6) « ANG.LEFT2 FEATURE(7) - ANG.RIGHT1: FEATURE(β) - ANG.RIGHT2 FEATURE(9) - YMEAN.LEFT1 - YMEAN.LEFT2 FEATURE(10) - YMEAN. IGHT1 - YMEAN.RIGHT2

END.FEATURE.ERROR: where FEATURE.ERROR resumes ON ERROR GOTO 0 EXIT SUB

GET.SLOPE: ' - routine to get the mean slope between points ISTt and IENDt ' - a linear regression formulation is used.

SUMX - 0: SUMY ■ 0: SUMXY - 0: SUMXSQ » 0 IF 1ST* < 0 THEN 1ST* - 0 IF IEND* < 0 THEN IEND* - 0 NP - IENDt - ISTt + 1

ASTEPt « 1: IF IENDt < ISTt THEN ASTEP* -1 FOR It - ISTt TO IENDt STEP ASTEPt

SUMX - SUMX + Xt(It)

SUMY - SUMY + Yt(It)

SUMXY - SUMXY + 1! * Xt(It) * Yt(It)

SUMXSQ - SUMXSQ -4- 1! * Xt(It) * X*(I*) NEXT It

DIVISOR » NP * SUMXSQ - SUMX * SUMX NUMERATOR - NP * SUMXY - SUMY * SUMX IF ABS(DIVISOR) < 1 THEN

SLOPE - 9999 ELSE

SLOPE - NUMERATOR / DIVISOR

END IF RETURN

END SUB

SUB GETINKEY

' - routine to get a character using the INKEYS command AS - "" WHILE AS - ""

Rt - CSRLIN: Ct - POS(0): ACHAR - SCREEN(Rt, Ct) : PRINT IF ACHAR <« 32 THEN ACHAR ■ ASC(ASPACECHRS) LOCATE Rt, C*

FOR I* - 1 TO TIMELOOP*: NEXT It: PRINT CHRS(ACHAR) ; FOR I* - 1 TO TIMELOOP*: NEXT It: LOCATE Rt, C* AS - INKEYS WEND END SUB

SUB GETSIGNATURE

1 - routine to acquire the signature as the person walks

' through the metal detector.

1 - initialize some parameters

EVENT* - 0: COUNT* ■ -1: TOTAL.COUNT* « -1: OLDTIME - TIMER

START.EVENT* - -1: END.EVENTt - -1

IRTt « COUNTt - SAMPLES.IN.RISETIHE*

IHT* - COUNTt - SAMPLES.IN.RISETIME* / 2

GOSUB SGET.DATA

XT1* - XARt(COUNT*): YT1* - YAR*(COUNT*)

PSET (XT1* - XREFt, YT1* - YREF*)

' checking for the event occuring before 1 full rise time

WHILE COUNT* < SAMPLES.IN. ISETIME* GOSUB SGET.DATA

LINE -(XAR*(COUNT*) - XREFt, YAR*(COUNT*) - YREF*) IF EVENT* - 0 THEN

IF ABS(XAR*(COUNT*) - XT1*) > X.DEL.CHK.S* THEN

EVENT* » 1: DETECT.COUNT* - COUNT* END IF IF ABS(YARt(COUNT*) - YT1*) > Y.DEL.CHK.S* THEN

EVENT* » 1: DETECT.COUNT* - COUNT* END IF ELSE

IF RELAY.CONTROLSS « YESS THEN

PORTVAL* - INP(PDISO*) AND (255 - PDISO.GO*) OUT PDISO*, PORTVALt END IF END IF WEND

IF EVENT* - 1 THEN MART.EVENT* - 0 WHILE TOTAL.COUNT* < SAMPLES.IN.RISETIME*

GOSUB SGET.DATA

LINE -(XARt(COUNT*) - XREF*, YAR*(COUNTt) - YREFt) WEND END IF now need to check for an event after 1 risetime IF EVENT* - 0 THEN PROBLEM* - 0

WHILE EVENT* - 0 AND PROBLEM* - 0 GOSUB SGET.DATA

LINE -(XARt(COUNTt) - XREFt, YARt(COUNTt) - YREFt) IF ABS(XARt(COUNTt) - XARt(IRTt)) > X.DEL.CHK.St THEN EVENT* - 1 IF ABS(XAR*(COUNT*) - XAR*(IHT*)) > X.DEL.CHK.S* THEN EVENT* - 1 IF ABS(YAR*(COUNT*) - YAR*(IRT*)) > Y.DEL.CHK.S* THEN EVENTt - 1 IF ABS(YARt(COUNTt) - YARt(IHTt)) > Y.DEL.CHK.St THEN EVENT* » 1 IF TOTAL.COUNT* > MAX.SAMPLES.BEFORE.EVENTt THEN PROBLEM* - 1 PASS.ALERTt - 1 IF RELAY.CONTROLS? - YESS THEN IF RUN.MODES - "OPERATE" THEN

OPERATE.ALERTt(4) • 1: ALARMS » YESS END IF IF RUN.MODES » "CALIBRATE" THEN

OUT PDISOt, PDISO.WAITt END IF END IF END IF WEND IF EVENTt - 1 THEN

IF RELAY.CONTROLSS - YESS THEN

PORTVALt » INP(PDISOt) AND (255 - PDISO.GOt) OUT PDISOt, PORTVALt END IF

START.EVENTt - IRTt END IF IF PROBLEM* - 1 THEN

LPRINT NAMES; " waited too long before entering the portal." END.IF END IF

' - if an event has been detected, the end of the event must ' be determined IF EVENTt - 1 THEN PROBLEMt - 0

SAMPLES.TO.ALERTt - TOTAL.COUNT* + MAX.SAMPLES.FOR.EVENTt WHILE EVENT* - 1 AND PROBLEM* - 0 GOSUB SGET.DATA

LINE -(XAR*(COUNT*) - XREFt, YARt(COUNTt) - YREFt) IF ABS(XAR*(COUNT*) - XAR*(IRT*)) < X.DEL.CHK.E* THEN IF ABS(XAR*(COUNT*) - XAR*(IHT*)) < X.DEL.CHK.E* THEN IF ABS(YAR*(COUNT*) - YAR*(IRT*)) < Y.DEL.CHK.E* THEN IF ABS(YARt(COUNTt) - YARt(ΣHTt)) < Y.DEL.CHK.E* THEN EVENT* - 0 END.EVENT* « COUNT*

END IF END IF END IF END IF

IF TOTAL.COUNTt > SAMPLES.TO.ALERT* THEN PROBLEM* - 1 PASS.ALERT* - 1

OPERATE.ALERT*(5) - 1: ALARMS - YESS END IF WEND IF PROBLEM* - 1 THEN

LPRINT NAMES; " took too long to walk through the portal." END IF ENO IF

' - need to obtain a new properly sequenced array. IF END.EVENT* > 0 THEN J* - 0

IF END.EVENT* > START.EVENTt THEN FOR I* » START.EVENTt TO END.EVENT*

J* - J* + 1: X*(J*) - XAR*(I*): Yt(Jt) - YAR*(It) NEXT I* ELSE

FOR I* » START.EVENT* TO MAX.SAMPLES.FOR.EVENT*

J* » J* + 1: Xt(J*) - XAR*(I*): Y*(Jt) - YAR*(I*) NEXT I* FOR I* - 0 TO END.EVENT*

J* - J* + 1: X*(J*) » XAR*(I*): Y*(J*) - YARt(I*) NEXT I* END IF NSAMPt - Jt END IF EXIT SUB

SGET.DATA: ' - routine to collect a sample

1 - This routine is called from GETSIGNATURE, and needs TOTAL.COUNTt CALL TCACQUISITION(SEG At(0)): SXt - λt(0): SYt - λt(l): Zt - 1 WHILE TIMER - OLDTIME

CALL TCACQUISITION(SEG λ*(0))

SXt - SXt + λ*(0): SYt • SYt + A*(l): Zt - Z* + 1 WEND

OLDTIME - TIMER

XAVG* - SXt / Zt: YAVG* - SYt / Z* TOTAL.COUNTt - TOTAL.COUNT* + 1

COUNT* » COUNT* + l: IF COUNT* > MAX.SAMPLES.FOR.EVENT* THEN COUNT* » 0 IRT* - IRT* + 1: IF IRT* > MAX.SAMPLES.FOR.EVENT* THEN IRT* » 0 IHT* - IHT* + 1: IF IHT* > MAX.SAMPLES.FOR.EVENT* THEN IHT* » 0 XAR*(COUNT*) - XAVG* YARt(COUNT*) - YAVG* RETURN

END SUB

SUB MAIN.MENU.DISPLAY

1 - procedure to display the main menu SCREEN 0, , 1, 1: CLS : COLOR 10 VIEW PRINT

LOCATE 1, 1: PRINT CHRS(201) + STRINGS(78, 205) + CHRS(187); LOCATE 2, 1: PRINT CHRS(186) + SPACES(78) + CHRS(186); LOCATE 3, 1: PRINT CHRS(200) + STRINGS{78, 205) + CHRS(188);

COLOR 9: LOCATE 2, 18: PRINT "THE WISE COMPANY'S PRECIOUS METAL DETECTOR"

COLOR 2

LOCATE 7, 10: PRINT "Select COLOR 9: PRINT "C"

COLOR 2: PRINT " - to calibrate an employee."

LOCATE 9, 19: COLOR 9: PRINT "O"*

COLOR 2: PRINT " - to operate in the detection mode. LOCATE 11, 19: COLOR 9: PRINT "U";

COLOR 2: PRINT to update the employee data base. LOCATE 13, 19: COLOR 9: PRINT "D"; COLOR 2: PRINT - to display the database." LOCATE 17, 2: PRINT "Enter your selection ( "; COLOR 9: PRINT "C, O, U, ",- : COLOR 2: PRINT or COLOR 9: PRINT "D"; COLOR 2: PRINT " ) "; EXIT SUB END SUB

SUB PMDCONS (A*)

GOSUB PROGRAM.MENU.CONSTANTS GOSUB PROGRAM.CONSTANTS EXIT SUB

PROGRAM.MENU.CONSTANTS: ' - routine used to set up the program constants ' used in the MENU.CONSTANTS routine.

OPEN "C:\PMD\DATA\LASTSAVE.DAT" FOR INPUT AS fl

INPUT fl, FILE.CONSTANTS?

CLOSE fl

OPEN FILE.CONSTANTSS FOR INPUT AS fl

INPUT fl, LAST.DATES, LAST.TIMES

INPUT fl, X.DEL.CHK.S*, Y.DEL.CHK.S*, X.DEL.CHK.E*, Y.DEL.CHK.E*

INPUT fl, CALIBRATE.MAX.DELAY.TIME*, OPERATE.MAX.DELAY.TIME*

INPUT fl, VIEW.LENGTH

INPUT fl, FREQt, PHASE*, GAIN*, DRANGEt

INPUT fl, CLEAN.TIMEt, ALARM.TIMEt, PERCENT.ALARMt

CLOSE fl

LBNDt - -DRANGEt: UBNDt - DRANGEt: ' - sets display limits of digitized data.

CONPARMS(l) » LTRIMS(STRS(FREQt)): CONPARM$(2) - LTRIMS(STRS(GAINt) )

CONPARM$(3) - LTRIM$(STRS(PHASE*)): CONPARMS(4) - LTRIMS(STRS(DRANGEt) )

CONPARM$(5) - LTRIM$(STR$(X.DEL.CHK.St))

CONPARM$(6) - LTRIMS(STRS(X.DEL.CHK.Et))

CONPARM$(7) - LTRIMS(STRS(CALIBRATE.MAX.DELAY.TIMEt))

CONPARMS(8) - LTRIMS(STRS(OPERATE.MAX.DELAY.TIME ) )

C0NPARM$(17) - LTRIMS(STRS(CLEAN.TIMEt) )

CONPARMS(18) - LTRIMS(STRS(ALARM.TIME*) )

CONPARMS(19) « LTRIMS(STRS(PERCENT.ALARMt) )

C0NPARMS(21) - LTRIMS(STRS(VIEW. ENGTH) ) RETURN

PROGRAM.CONSTANTS: - routine used to set up the other program constants

MS(1) - "Jan": M$(2) *Feb" MS(3) « "Mar"' MS(4) "Apr": MS(5) "May" MS(6) - "Jun"' M$(7) "Jul" MS(8) - "Aug" MS(9) "Sep": MS(10) ■ "Oct"

MS l) "NOV": MS(12) - "Dec" DM*(1) » 31: DM*(2) • 28: DDMM*t((33)) » 31: DMt(4) » 30 DM*(5) 31: DM*(6) - 30: DM*(7) - 31: DM*(β) - 31 DM*(9) 30: DM*(10) - 31: DM*(11) « 30: DM*(12) - 31

INTERRUPT. ATE - 18.2

RISETIME - 1!

DIFFERENTIAL.TIME - .75

MAX.WALK.TIME* - 10

REFLINE - 21

PI - 4 * ATN(l): RADTODEG - 180 / PI

PDISO* - IH2A0

PDISO.WAIT* - 0: PDISO.GO* - 1: PDISO.ALARM* » 32: PDISO.CLEAN* =■ 64

MAX.SAMPLES.FOR.EVENT* - MAX. ALK.TIMEt * INTERRUPT. ATE SAMPLES.IN. ISETIMEt - RISETIME * INTERRUPT.RATE

CALQUESTS(1) - "Enter the person's last name."

CALQUESTS(2) » "Enter the person's first name."

CALQUESTS(3) - "Enter the person's middle initial."

CALQUESTS(4) - "Enter the person's identification number - use 8 numerals.

CALQUESTS(5) - "Enter the person's sex. M-male F-female"

CALQUESTS(6) - "Enter the person's height - use centimetres."

CALQUEST (7) ■ "Enter the person's weight - use kilograms."

CALQUESTS(8) » "Does the person wear a dental bridge? Y-yes N-no"

CALQUESTS(9) - - ""DDooeess tthhee ppeerrssoonn hhaavvee aa mmeettaalllliicc iimmppllaanntt ?? Y Y--yyeess N-no" CALQUESTS(10) ■ "Does the person have a pacemaker? Y-yes N-no" CALQUESTS(11) - "Enter any other features beside the 'other' heading CALQUESTS(ll) » CALQUESTS(11) + "- otherwise enter 'NONE'" TIME.TEST* « 0: JEND* - 1: IEND* - 20000 WHILE TIME.TEST* - 0

JEND* - 2 * JEND*

STTIHE - TIMER

FOR Jt - 1 TO JENDt: FOR It - 1 TO IENDt: NEXT It: NEXT J*

ENDTIME - TIMER

IF ENDTIME - STTIHE > 1.5 THEN TIME.TEST* - 1 WEND

LOOPSPERSEC - JENDt / (ENDTIME - STTIME) * IEND* BLINKTIME - .05 TIMELOOPt - BLINKTIME * LOOPSPERSEC

MAX.PASSNUM* - 8

NUM.FEATURES* - 10 NUM.OPERATE.ALERTS* » 8

OP.NSTDEV(l) » 41: CAL.NSTDEV(l) - 3! LIH.STDEV(l) - 4: DEL-X OP.NSTDEV(2) - 31: CAL.NSTDEV(2) - 2! LIM.STDEV(2) - 3: DEL-Y

SUB PMDKEAD

1 This subprogram calls all the heading and data entry positions.

' The data statements are contained in the main module.

DIM HEADR*(25), HEADC*(25), HEADTS(25)

DIM DATASPCS*(25)

OPEN "C:\PMD\DATA\HEADING1.DAT" FOR INPUT AS fl

GOSUB CALIBRATE.HEADING

GOSUB UPDATE.HEADING

GOSUB UPDATE.ADD.HEADING

GOSUB CONSTANT.HEADING

GOSUB CALIBRATE.POSN

GOSUB UPDATE. OSN

GOSUB CONSTANT.POSN

CLOSE fl

EXIT SUB

GENERAL.HEADING: ' - routine to set up a general heading AS - ""

WHILE LEFTS(AS, 3) <> "998" LINE INPUT fl, AS PRINT AS WEND

IHEAD* - 0 INPUT fl, IROWt WHILE IROWt <> 999 INPUT fl, NHEADt FOR It - 1 TO NHEADt INPUT fl, ICOLt, HEADS IHEAD* - IHEAD* + 1

HEADRt(IHEADt) - IROWt: HEADC*(IHEAD*) » ICOL* HEADTS(IHEAD*) - HEADS NEXT I* INPUT fl, IROW* WEND NUMBER.OF.HEADINGS* - IHEAD* RETURN

•CALIBRATE.HEADING: • - routine to set up the CALIBRATE screen

SUBS π ru I £ SHEET

GOSUB GENERAL.HEADING

NUM.CAL.HEAD* » NUMBER.OF.HEADINGS*

FOR It - 1 TO NUM.CAL.HEAD*

CALHEADR*(I*) - HEADR*(I*)

CALHEADC*(It) - HEADCt(It)

CALHEADTS(It) - HEADTS(It)

NEXT It RETURN

UPDATE.HEADING: ' - routine to set up the UPDATE screen GOSUB GENERAL.HEADING

NUM.UPDATE.HEADt - NUMBER.OF.HEADINGSt FOR It - 1 TO NUM.UPDATE.HEADt

UPDATEHEADRt(It) - HEADRt(It)

UPDATEHEADCt(It) - HEADCt(It)

UPDATEHEADTS(It) - HEADTSd*)

NEXT I* RETURN

UPDATE.ADD.HEADING: ' - routine to set up the UPDATE.ADD screen GOSUB GENERAL.HEADING

NUM.UPDATE.ADD.HEAD* - NUMBER.OF.HEADINGS* FOR I* - 1 TO NUM. PDATE.ADD.HEAD*

UPDATEADDHEADR*(I*) - HEADRt(It)

UPOATEADDHEADC*(I*) - HEADC*(It)

UPDATEADDHEADTS(It) - HEADT?(It)

NEXT I* RETURN

CONSTANT.HEADING: ' - routine to set up the CONSTANT screen GOSUB GENERAL.HEADING NUM.CON.HEAD* - NUMBER.OF.HEADINGS* FOR I* - 1 TO NUM.CON.HEAD*

CONHEADRt(It) - HEADR*(I*)

CONHEADCtd*) - HEADCtd*)

CONHEADTS *) - HEADTSd*)

NEXT It RETURN

GENERAL.DATA.POSN: ' - routine for entering data entry positions AS - "" WHILE LEFTS(A$, 3) <> "998"

LINE INPUT fl, AS

PRINT AS WEND

IHEAD* - 0 INPUT fl, IROWt WHILE IROWt <> 999

INPUT fl, NHEADt

FOR I* - 1 TO NHEAD* INPUT fl, ICCL*, ISPC* IHEAD* - IHEAD* + 1

DATAR*(IHEAD*) - IROW*: DATAC*(IHEAD*) - ICOLt: DATASPCSt(IHEADt) - ISPCt NEXT I* INPUT fl, IROW* WEND NUMBER.OF.POSITIONS* » IHEAD* RETURN

CALIBRATE.POSN: - routine for entering CALIBRATE data positions GOSUB GENERAL.DATA.POSN NUM.CAL.PARM* - NUMBER.OF.POSITIONS* FOR I* - 1 TO NUMBER.OF.POSITIONS*

CALROW*(I*) - DATAR*(I*)

CALCOLt(It) - DATAC*(I*)

CALSPCS*(I*) - DATASPCSt(It)

NEXT It RETURN

UPDATE.POSN: ' - routine for entering UPDATE.ADD data positions GOSUB GENERAL.DATA.POSN

NUM.UPDATE. ARMt - NUMBER.OF.POSITIONS* FOR It » 1 TO NUMBER.OF.POSITIONSt

UPDATEROWt(It) - DATARt(It)

UPDATECO t(It) - DATAC*(I*)

UPDATESPCStd*) - DATASPCSt(It)

NEXT I* RETURN

CONSTANT.POSN: - routine for entering CONSTANT data positions GOSUB GENERAL.DATA.POSN NUM.CON.PARM* - NUMBER.OF.POSITIONS* FOR It - 1 TO NUMBER.OF.POSITIONS*

CONROW*(It) - DATAR*(I*)

CONCOL*(It) - DATAC*(I*)

CONSPCS*(I*) ■ DATASPCΞt(It)

NEXT It RETURN

END SUB

SUB READ.KEYBOARD

1 - routine to read the keyboard to get the employee number

SHARED PERSON. AITINGS, NEED.TO.BLANKS, F1HITS

SHARED LASTKEYS, EMPNOt, DEMPNOt(), NUMBER.OF.EMPLOYEES*

SHARED INDEX.NUMt

SHARED YESS, NOS, OKS, NOTOKS

PERSON. AITINGS - NOS

VIEW PRINT 22 TO 24

SUBSTITUTE SHEET

IF NEED.TO.BLANKS - YESS THEN

CLS 2

CALL BLANKLINE(23): PRINT "Press any key to initiate a test.";

SOUND 100, 3: SOUND 50, 2

NEED.TO.BLANKS - NOS END IF AS - LASTKEYS

IF LEN(AS) <> 0 THEN

CALL BLANKLINE(23): SOUND 500, 2: SOUND 200, 2

INPUT ; "Enter employee number : ", EMPNO*

NEED. O.BLANKS - YESS

IF EMPNOt > 0 THEN : PERSON.WAITINGS » YESS: CALL BLANKLINE(23) END IF VIEW PRINT EXIT SUB END SUB

SUB SWAP.EMPLOYEE (HIGH.INDEX.NUMt, ARRAY.ENTRY.POINT*) ' - routine to swap the employee at the proper location in the database. IF ARRAY..ENTRY.POINT* < NUMBER.OF.EMPLOYEES* THEN

FOR J* » HIGH.INDEX.NUM* TO ARRAY.ENTRY.POINT* + 1 STEP -1 Wt ■ Jt - 1

SWAP DEMPNOt(Jt), DEMPNO (JMt) SWAP DACTLASTS(J*), DACTLASTS(JMt) SWAP DACTFIRSTS(J*), DACTFIRSTS(JM*) SWAP DACTINITS(J*), DACTINITS(JM*)

SWAP DSEX(Jt), DSEX(JM*): SWAP DHEIGHT(Jt) , DHEIGHT(JM*) SWAP DWEIGHT(J*) , DWEIGHT(JMt) : SWAP DBRIDGE(Jt) , DBRIDGE(JMt) SWAP DIMFLANT(Jt), DIMPLANT(JM*) : SWAP DPACE(J*) , DPACE(JMt) SWAP DOTHERS(Jt), DOTHERS(JMt) FOR I* - 1 TO NUM.FEATURES*

SWAP DMEAN(J*, I*), DMEAN(JM*, It) SWAP DSTDEV(Jt, It), DSTDEV(JMt, It) NEXT It NEXT Jt END IF

IN.SECURE.AREA*(ARRAY.ENTRY.POINT*) - 0 EXIT SUB END SUB

SUB UPDATE.EMPLOYEE.DATABASE SHARED INDEX.NUMt

' - routine to update the employee database DIM UPDATEPARM$(5) RESPONSES - "" VALID.ENTRYS - "YES"

WHILE RESPONSES <> "Q" AND RESPONSES <> "q" GOSUB UPDATE.HEAD.DISPLAY IF VALID.ENTRYS - "NO" THEN

LOCATE 21, 1: PRINT "Invalid entry - try again "; SOUND 500, 2: SOUND 300, 2: VALID.ENTRYS - "YES"

END IF

LOCATE 7, 54: PRINT NUMBER.OF.EMPLOYEES*

LOCATE 19, 2: PRINT "Enter your selection ( A, D, C,or Q ) "j SOUND 100, 3: SOUND 50, 2 CALL GETINKEY RESPONSES - AS

PRINT AS;

SELECT CASE RESPONSES CASE "A" **a"

GOSUB ADD.EMPLOYEE CASE IS - "D", "d"

GOSUB DELETE.EMPLOYEE CASE "C", "c"

GOSUB CHANGE.EMPLOYEE CASE IS - "Q", "q"

LOCATE 23, 1: PRINT "STOP" CASE ELSE

VALID.ENTRYS - "NO" END SELECT WEND EXIT SUB

UPDATE.HEAD.DISPLAY: ' - routine to display the UPDATE screen SCREEN 0: CLS : VIEW PRINT FOR I* - 1 TO NUM.UPDATE.HEAD*

LOCATE UPDATEHEADRt(I*), UPDATEHEADC*(I*)

PRINT UPDATEHEADTS(It); NEXT I* RETURN

ADD.EMPLOYEE: ' - routine to add an employee to the database VIEW PRINT 9 TO 24 CLS 2

LOCATE 25, 1: COLOR 10, 1: PRINT "Press 'Esc' key to exit.": COLOR 2, 1 LOCATE 9, 1 EXITS - "NO" ALLDATAS - "NOT OK" IPRMMAXt - NUM.UPDATE.PARM* FOR I* - 1 TO IPRMMAX*

DATAR*(I*) - UPDATEROW*(I*): DATAC*(It) - UPDATECOL*(It) SPCStfl*) - UPDATESPCS*(I*) NEXT It

ANOTHERS - "Y" WHILE ANOTHERS - "Y" IPRMt - 1

GOSUB UPDATE.ADD.HEAD.DISPLAY ALLDATAS - "NOT OK" WHILE ALLDATAS - "NOT OK" FINISHS - "NO" WHILE FINISHS - "NO" . IF IPRMt > IPRMMAXt THEN IPRMt - 1 IF IPRMt <- 0 THEN IPRMt - IPRMMAXt

SOUND 100, 3: SOUND 50, 2

ROWt - DATAR*(IPRMt): COLUMNt - DATACt(IPRMt) LOCATE ROWt, COLUMNt CALL ADDNEWCHAR IF EXITS - "YES" THEN RETURN CALL BLANKLINE(18): CALL BLANKLINE(17) WEND

GOSUB UPDATE.CHECK IF ALLDATAS » "OK" THEN

GOSUB UPDATE.EMP.NUM.IN.USE.CHECK IF EMP.NUM.IN.USES » "YES" THEN

CALL BLANKLINE(18): CALL BLANKLINE(17) PRINT "This employee number is currently in use - "; PRINT "enter a new value"

PRINT " or delete the other employee from the database." SOUND 500, 2: SOUND 300, 2 IPRMt - 4: ALLDATAS » "NOT OK" END IF END IF IF ALLDATAS - "OK" THEN

ARRAY.ENTRY.POINTt - NUMBER.OF.EMPLOYEESt + 1 GOSUB UPDATE.ADD.DATABASE FOR Jt » 1 TO NUH.FEATURESt

DHEAN(ARRAY.ENTRY.POINTt, Jt) - 0 DSTDEV(ARRAY.ENTRY.POINT*, J*) - 0 NEXT Jt

CALL BLANKLINE(17): CALL BLANKLINE(18) PRINT "Enter another? Y(yes) N(no) "; CALL GETINKEY ANOTHERS - UCASES(AS) END IF WEND RETURN

UPDATE.ADD.HEAD.DISPLAY: • - routine to display the UPDATE.ADD screen SCREEN 0: CLS : VIEW PRINT FOR It - 1 TO HUM.UPDATE.ADD.HEAD*

LOCATE UPDATEADDHEADR*(It), UPDATEADDHEADC (It)

PRINT UPDATEADDHEADTS(It) ; NEXT It FOR It - 1 TO NUH.UPDATE.PARMt

LOCATE UPDATEROWt(It), UPDATECOLt(It)

PRINT LEFTS(SPACECHRS, UPDATESPCSt(It) ) ; NEXT It RETURN

UPDATE.CHG.HEAD.DISPLAY: ' - routine to display the UPDATE.CHG screen SCREEN 0: VIEW PRINT: CLS FOR It - 1 TO NUM.UPDATE.ADD.HEADt

LOCATE UPDATEADDHEADRt(It) , UPOATEADDHEADC*(It)

PRINT UPDATEADDHEADTSdt) ; NEXT It

FOR It » 1 TO NUM.UPDATE.PARMt

LOCATE UPDATEROWt(It) , UPDATECOLt(I )

PRINT LEFTS(SPACECHRS, UPDATESPCSt(I*) ) ; NEXT I*

LOCATE UPDATEROW*(l), UPDATECOL*(1) : PRINT DACTLASTS(ECHG*) LOCATE UPDATEROW*(2), UPDATECOL*(2) : PRINT DACTFIRSTS(ECHG*) LOCATE UPDATEROW*(3), UPDATECOL*(3) : PRINT DACTINITS(ECHG*) LOCATE UPDATEROW*(4), UPDATECOL*(4) - 1: PRINT DEMPNO*(ECHG*) RETURN

DELETE.EMPLOYEE: ' - routine to remove an employee from the database. VIEW PRINT 7 TO 25 CLS 2

LOCATE B, 10

INPUT "Enter the employee number to delete from the database "; AEMPNOt EMP.FOUNDS - "NO"

FOR I* - 1 TO NUMBER.OF.EMPLOYEES* IF AEMPNOt - DEMPNOt(It) THEN EMP.FOUNDS « "YES" ARRAY.ENTRY.POINTt - It I* -.NUMBER.OF.EMPLOYEES* + 1 END IF NEXT I*

IF EMP.FOUNDS » "YES" THEN I* » ARRAY.ENTRY.POINT*

ANAMES ■ DACTFIRSTS(I*) + " " + DACTINITS(I*) + " " + DACTLASTS(It) LOCATE 10, 5: PRINT "Do you wish to delete - "; PRINT ANAMES;

INPUT " ? Y(Yes) N(No) ", ANSS IF ANSS - "Y" OR ANSS - "y" THEN INDEX.NUM* - I*

CALL DELETE.EMPLOYEE.FROM.DATABASE

LPRINT "Employee "; ANAMES; " number "; AEMPNOt; " deleted." END IF E-LSE

LOCATE 10, 10: PRINT "Employee number "; AEMPNOt; " is not found." LOCATE 12, 10: PRINT "Press any key to continue "; CALL GETINKEY END IF VIEW PRINT RETURN

CHANGE.EMPLOYEE: ' - routine to change an employee's data in the database.

' This routine is to be used when an existing employee changes either

' their name or employee number.

VIEW PRINT 7 TO 25: CLS 2: LOCATE 8, 10 INPUT "Enter the employee's last name : ", CHGLASTNAMES LOCATE , 10: INPUT "Enter the employee's number : ", CHGNUMBER* EMP.FOUNDS - "NO"

FOR I* - 1 TO NUMBER.OF.EMPLOYEES* IF CHGNUMBER* - DEMPNO*(I*) THEN ECHGt - It

It - ECHGt + 1 EMP.FOUNDS - "YES" END IF NEXT I* IF EMP.FOUNDS - "NO" THEN

PRINT "An entry in the database with Employee f "; PRINT CHGNUMBER*; " is not found." INPUT " - press return to continue.", AS RETURN END IF IF DACTLASTS(ECHGt) <> CHGLASTNAMES THEN

PRINT "Last names do not match - employee f "; CHGNUMBERt; " is "; PRINT DACTLASTS(ECHGt): INPUT " T press return to continue", A? RETURN END IF

The employee number and last names are okay - now ' ready to accept changes. ALLDATAS - "NOT OK" IPRMMAXt - NUM.UPDATE.PARMt FOR It » 1 TO IPRMMAXt

DATARt(It) - UPDATEROWt(It): DATACt(It) - UPDATECOL*(I*) . SPCS*(It) - UPDATESPCSt(It) NEXT I*

ANOTHERS - "Y" IPRM* - 1

GOSUB UPDATE.CHG.HEAD.DISPLAY ALLDATAS - "NOT OK" WHILE ALLDATAS - "NOT OK" FINISHS - "NO" WHILE FINISHS - "NO"

IF IPRMt > IPRMMAXt THEN IPRM* - 1 IF IPRM* <- 0 THEN IPRM* - IPRMMAX* SOUND 100, 3: SOUND 50, 2

ROWt - DATARt(IPRMt): COLUMN* - DATAC*(IPRM*) LOCATE ROWt, COLUMNt CALL ADDNEWCHAR IF EXITS - "YES" THEN RETURN CALL BLANKLINE(17) WEND

GOSUB UPDATE.CHECK GOSUB UPDATE.EMP.NUM.IN.USE.CHECK

IF EMP.HUH.IN.USES - "YES" AND IH. SE.NUMt <> ECHGt THEN CALL BLANKLINE(17)

PRINT "This employee number is currently in use - "; PRINT "enter a new value." SOUND 500, 2: SOUND 300, 2 IPRMt » 4: ALLDATAS - "NOT OK" END IF

IF ALLDATAS - "OK" THEN GOSUB UPDATE.CHECK DACTLASTS(ECHGt) - UPDATEPARMS(l) DACTFIRSTS(ECHGt) - UPDATEPARMS(2) DACTINITS(ECHGt) - UPDATEPARMS(3)

DEMPNOt(ECHGt) - VAL(UPDATEPARMS(4) ) DATA.CHANGES - "YES" END IF

WEND RETURN

UPDATE. HECK: ' - routine to check that the UPDATE values are ok, and to 1 place values in the UPDATEPARMS() array. This routine is called ' from ADD.EMPLOYEE and CHANGE.EMPLOYEE. ALLDATAS - "OK"

FOR It - 1 TO NUM.UPDATE.PARM* BS - " " FOR Jt - 1 TO UPDATESPCSt(It)

AS - CHRS(SCREEN(UPDATEROWt(It) , UPDATECOLt(It) + J* - 1)) IF AS - ASPACECHRS THEN

J* - UPDATESPCS*(It) -I- 1 ELSE

BS - BS + AS END IF NEXT Jt

UPDATEPARMS(It) - RTRIMS(LTRIMS(BS) ) NEXT It ' FOR It - 1 TO NUM.UPDATE.PARMt

IF LEN(UPDATEPARMS(It)) < 1 AND I* <> 3 THEN ALLDATAS - "NOT OK"

CALL BLANKLINE(17): PRINT "A value must be entered here." SOUND 500, 2: SOUND 300, 2 IPRMt - It RETURN END IF NEXT It

AEMPNOt - VAL(UPDATEPARMS(4)) IF AEMPNOt <- 0 THEN ALLDATAS - "NOT OK"

CALL BLANKLINE(17) : PRINT "This employee » is not valid - "; PRINT "enter a new value." SOUND 500, 2: SOUND 300, 2 IPRMt - 4 RETURN END IF RETURN

UPDATE.EMP.NUH.IN.USE.CHECK: ' - routine to determine if the employee f is in use

EMP.NUM.IN.USES » "NO" FOR It - 1 TO NUMBER.OF.EMPLOYEES* IF DEMPNO*(I*) - AEMPNOt THEN IN.USE.NUM* - I* It - NUMBER.OF.EMPLOYEES* + 1 EMP.NUM.IN.USES - "YES" RETURN END IF

NEXT I* RETURN

UPDATE.ADD.DATABASE: ' - routine to UPDATE the database K* - ARRAY.ENTRY.POINT* DEMPNOt(Kt) - AEMPNOt DACTLASTS(Kt) - UPDATEPARMS(1) DACTFIRSTS(Kt) - UPDATEPARMS(2) DACTINITS(Kt) - UPDATEPARMS(3) DATA.CHANGES - "YES"

NUMBER.OF.EHPLOYEESt - NUMBER.OF.EHPLOYEESt + 1 CALL BLANKLINE(24)

LPRINT "Employee "; DACTFIRSTS(K*) ; " "; DACTINITS(K*) ; " "; DACTLASTS(Kt) ; LPRINT " number "; DEMPNO*(K*) ; " added." RETURN

END SUB