Cluster Analysis Documentation The cluster program is designed to analyze unit activity in a histogram in a manner similar to how our eyes perceive changes in activity. Chapter A (Cluster analysis) discusses this method with examples as a possible solution to the problem of relating unit activity to behavior. Like the other programs presented here this program also is written in Forth, but unlike the other programs it is written in the version of Forth for Windows 3.1 from Laboratory Microsystems Inc (the earlier DOS version is Micromotion's MasterForth). Much of the programming that is unfamiliar is related to controlling window displays. There are actually two programs here in this appendix. The dave.txt program is an implementation of the Summary's Review routine. Like that review routine, dave.txt displays data from a data disk on a trial-by-trial basis and allows for averaging trials together. In fact, with some minor but important formatting differences, the DOS version of Forth was directly imported to the Windows version. An additional feature of dave.txt is that it implements the cluster analysis program for two kinds of displays: for unit histograms, significant unit clusters are filled whereas nonsignificant clusters are open figures; for unit clusters per se, a frequency display is created for a block of trials. Both of these displays have been illustrated in Chapter A (Cluster analysis). The second program is cluster.txt which gives a detailed printout (or file) on a trial-by-trial basis of all the clusters. There are a number of different options, described below in the documentation, for the type of information printed. The two most useful types of information are the onset latency of the cluster and the frequency of the cluster. As we discuss below, however, this cluster analysis is only a prelude to further statistics which relate consistency and strength of responding between unit activity and behavior. One of the advantages of the Laboratory Microsystems version of Forth is that the source code files are text files which can be edited with any ASCII word processor. A big difference between the Laboratory Microsystems and the Micromotion's MasterForth versions is that the latter uses the traditional screen structure, whereas the former can use either the screen structure or the free format that we have used. Thus, there are no references to the screeen in the two cluster programs that follow. A minor difference related to this lack of screen structure is that almost all of our comments are placed within parentheses. There are other differences in the implementation of the languages that we will not go into detail but will be obvious to the reader (for example, the Windows version uses equ to change the value of variables and switches). Finally, it should be noted that the cluster program is not that difficult to implement, and there is no reason why one could not reverse the direction and import the essence of the Windows cluster analysis program to the DOS version. The formal documentation for loading and using the cluster programs follows. This documentation begins with an introduction to the problem of analyzing unit activity, particularly with regard to independently and consistently determining the latency of the activity. Next, a cluster is defined and the analysis is discussed. Described next are how to load the programs and use the options for the print outs. A nice feature about the Windows version is that, instead of printing out a hard copy, the information can be printed to disk. This feature is potentially useful for exporting the information to a spreadsheet. Finally, the assumptions of the cluster program are explicitly identified. This is useful for interpreting the cluster results and for comparison with other methods. Following this documentation are the actual source files for dave.txt and cluster.txt which make up the bulk of this appendix. Cluster Analysis Documentation Introduction The cluster analysis software is designed to analyze unit activity that has been collected with our forth Runtime/Summary programs. The purpose of this analysis is to identify the latency and magnitude of unit activity during each trial of classical conditioning and to determine if that activity is significantly different from baseline activity. The results are displayed to screen or printed out. Background on data representation To understand this analysis one needs to know just a little bit about how data is represented. In the Runtime program the unit data is collected into an array. The first array position is the beginning of the trial, and the last array position is the end of the trial. Each array position is referred to as a “bin” and represents a period of time. For example, a bin could be defined as 4 msec in duration. Within each bin is stored the number of units counted in that duration. In a typical trial, an array for the unit activity might be made up of a succession of 250 bins; with each bin representing 4 msec, the whole trial is therefore 1000 msec (1 sec) in duration. Typically, a zero (0) is found in most bins, indicating that no unit activity was found during that 4 msec period. Cluster The key to this analysis program is the definition of a cluster of unit activity. A “cluster” is defined as a bin with unit activity or as a succession of bins that all have unit activity, bounded before and after by bins with no unit activity. The following are a few examples of a cluster. Example 1. Starting at the beginning of a trial we examine each bin. Initially, every bin has a zero, indicating that no unit activity was recorded in that period. Then we encounter a bin with a count of one, and the very next bin has a count of zero. The cluster is the bin with the unit activity, bounded by bins before and after with no unit activity. Example 2. Starting at the beginning of a trial we examine each bin. Initially, every bin has a zero, indicating that no unit activity was recorded in that period. Then we encounter a bin with a count of five, and the very next bin has a count of zero. The cluster is the bin with the unit activity, bounded by bins before and after with no unit activity. Example 3. Starting at the beginning of a trial we examine each bin. Initially, every bin has a zero, indicating that no unit activity was recorded in that period. Then we encounter a bin with a count of one, another bin with a count of one, a third bin with a count of two, and the very next bin has a count of zero. The cluster is all the bins with the unit activity, bounded by bins before and after with no unit activity. The number of units in this cluster is 4. In each of the examples above, a cluster is defined as a group of neighboring bins which all have unit activity. The actual source of that activity is not defined. The unit activity can be either single or multiple unit data. The responsibility for the ultimate interpretation of the clusters depends upon the experimenter. Latency The latency of the cluster is defined as the time when the first bin of the cluster is encountered. The latency could be reported as the time since the beginning of the trial or as the time since some meaningful event in the trial. For the latter we have chosen the time relative to the onset of the conditioned stimulus (before or after CS onset). Frequency The frequency of the cluster is determined by the amount of unit activity in the cluster divided by the time associated with the cluster, and scaled to activity per second (Hertz, Hz). The time associated with the cluster has two components: the time of unit activity that makes up the cluster (the time associated with the bins that have unit activity; see duration below) plus the time preceding the cluster where no unit activity was recorded (see ici -- intercluster interval -- below). This formula works out to be frequency in spikes/second = ((1000 msec) * (#spikes_in_cluster)) / (duration_of_cluster msec + duration_of_ici msec) The latter (the intercluster interval) will be recognized as a Poisson distribution. An easy way to think about this distribution is to consider that random unit activity could be plotted as a function of the interval between that same randomly generated activity. For example, pretend that unit activity has a frequency of 10 Hz. If there was exact spacing between units, then one unit would occur every 100 msec. That is the exact average. However, this exactness is very unlikely. Sometimes there could be a gap of 500 msec between units, sometimes a gap of only five msec. It could even be that all the unit activity occurs close together, and that most of the time nothing happens. A plot of data that is randomly distributed (that is, the intervals between unit activity is random) results in a plot where the sense is that if you have waited a really long time and no unit activity has happened, then the chances are very good that unit activity will happen before too long. Or another way of thinking about it: it would be surprising if unit activity occurred too quickly or too infrequently. The point here is that the expectation about the frequency of the units found in the cluster is a function of the preceding interval when nothing happened. Emissions of radioactivity are another example of a Poisson distribution. Other programs The cluster analysis program, per se, was written after dissatisfaction with the performance, limitations and assumptions that I have observed in other unit analysis programs. Crude comparisons of unit activity with behavior can be made with cross-correlations. Arguments have been made that this is the best way to determine whether the unit activity “models” the behavior; however, significant correlations exist when the unit activity looks very different than the behavioral data (for example, when the unit activity corresponds to the conditioned response, but the recording also includes tone evoked responses, which do not correspond to the behavior). The “latency” of the unit is given as the lag of the cross-correlation which yields the greatest correlation; yet the same analysis might yield several peaks and valleys of high correlations (which one to use?) and the correlations are unlikely to be statistically distinguishable from neighboring correlations. A statistically significant cross-correlation does not mean that there is a very good match with the behavior or that the latency of unit activity is confidently determined. Further, as practiced, the analysis is usually performed on data collected from several trials, rather than in individual trials. Another method is the use of z-scores. In one example of a z-score analysis, several trials are combined and then the mean and standard error of the total unit activity in the baseline period are used to compare the total unit activity in the CS period. An improvement is possible by using smaller time periods that we refer to as “epochs” -- the first, middle and last thirds of the CS period, for example, could be compared to a similar amount of time in the baseline period. The more epochs one has, the greater the discrimination (within the limits of the length of the epoch) of when significant activity occurred. Also the less stable the measurements because the baseline period similarly gets smaller. Typically, with three epochs, we define epochs that we interpret to represent CS-related or CR-related activity. Latency measurements of the unit activity are not reasonable expectations. This analysis is usually performed on data collected from several trials, although once the baseline mean and standard error are determined then epochs in individual trials can be compared for significant activity. To do this comparison, the actual activity in the epoch for a trial is compared with the previously computed mean and standard error. A different z-score method, again based on data from several trials, is designed to get at the questions of how much activity is there, and when does the latency occur? The baseline period is used to determine the mean and standard error for a bin (rather than for an epoch), and this is compared with each bin in the CS period. To help this analysis a Gaussian curve of a few bins in duration is added to each bin as a smoothing operation. The result is that bins that previously had no data now have some Gaussian-added activity. As a result of this smoothing operation, the computed latency of unit activity (when a bin exceeds a z-score criterion level) can occur in bins that actually had no activity. The size and width of the Gaussian curve are massaged to prevent this -- in one early instance, for example, unit activity was seen to occur before the airpuff was delivered. The assumptions inherent in this approach lead me to suspect the arbitrariness of the latencies. Another method is the use of t-scores. In this method, unit activity of the CS period is compared with a similar period of baseline activity. The first bin of each period is compared, the second bin is next compared, etc. The number of pairs of bins, for the whole CS period would be 63, which means that a zscore could be used instead. Typically, however, as with the epoch approach above, subsets (epochs) of the CS period would be compared. As with the methods above, the analysis is usually performed on data collected from several trials, and no reasonable latency score can be obtained. Dissatisfaction None of the above approaches analyzes unit data the way that we can do with our own eyes. We can see, on a trial by trial basis, within each trial’s record, when unit activity appears to increase or to decrease. What we are particularly bad at, however, is being able to determine when that activity began. The purpose of the cluster analysis program is to approximate what our eyes do in such a way that the program can reliably and consistently tell us when significant activity occurred. The cluster program The cluster analysis program is derived from a Windows version of the review program. The review program should be familiar to the reader, and is written in MasterForth from Micromotion (now defunct) for IBM DOS machines. The Windows version is written in WinForth from Laboratory Microsystems. The review program allows one to see, on a trial by trial basis, or as an average of several trials, the behavioral and unit data. The cluster program is based upon the cluster analysis portion of the Windows review program with the added feature of printing out the results in a trial by trial format. Before the Windows review program I had written a program to determine interspike intervals using MasterForth from Micromotion for Apple II machines. Rather than go into detail about how the cluster program works, the reader is probably more interested in how to use the program and what the options are. The following is a description of the cluster program and how to use it. Loading the cluster program On our 486 computer with Windows, open the Winforth group and double click on the Winforth program to start it. You will see a notice that says that Winforth is ready and instructs you to press the OK button or press <return> to continue. At this point you should see an “ok”, and every time you press <return> you should see an “ok”. The “ok” tells you that you are talking to the forth interpreter. To load the cluster program you first need to create a marker called “it”, you then need to load the review program (called dave.txt) and then the cluster program (called cluster.txt). create it<return> include dave.txt<return> include cluster.txt<return> or create it include dave.txt include cluster.txt<return> Note that these can be on separate lines or all on the same line. The program will return with some instructions and with an “ok”. The instructions You need to set several parameters before starting the program. Since this program is a work in progress the instructions and their names may change in the future. The instructions may be something like this: Specify unit for analysis -- e.g., unit1, unit2 ... Specify parameters -- e.g., bob, xty, claire_tones ... Specify computations -- e.g., special_info, hz_info, latency_info, spike_info, bin_info ... Specify criterion level -- e.g., 3 equ unit_Hz_criterion Specify bad trial criterion -- e.g., 100 equ bad_units Specify type of analysis -- e.g., by_block or by_session Set printer -- e.g., +printer, -printer, true equ printing, false equ printing Start analysis with cluster<return> Examples: unit2 bob hz_info 2 equ unit_Hz_criterion -printer cluster<return> latency_info cluster<return> unit1 +printer cluster<return> ... You need to specify which unit you are analyzing, the training parameters, what kind of information you want, what is your criterion for significant activity, what is your criterion for bad activity, whether you want a block or session analysis, and whether you want a printout. You need to do this once before actually running the program, and you can change any parameter at any time without having to respecify the other parameters. Let’s go through each of these: Specify unit for analysis -- e.g., unit1, unit2 ... Type unit1, unit2, unit3 or unit4 to analyze those unit channels, respectively. Those are the only legal values. Specify parameters -- e.g., bob, xty, claire_tones ... Type bob or xty or claire_tones etc to automatically select the training parameters. Or specify the individual parameters yourself for number of trials (108 equ #trls), number of trials per block (9 equ #t/blk), number of blocks (12 equ #blks), the first trial to start with (1 equ trl#), the number of a/d (eyelid data) that exists in this data (1 equ #a/d), the number of units in this data (4 equ #units), the number of milliseconds (in whole numbers) per bin (4 equ bin), the total number of bins per trial (756 bin / equ pts) [note that the forth commands here divide 756 msec by the 4 msec bin to yield the number of bins that make up pts], the onset of the tone conditioned stimulus (252 bin / equ toneon), the offset of the tone conditioned stimulus (598 bin / equ toneoff), the onset of the unconditioned stimulus (504 bin / equ shkon), the offset of the unconditioned stimulus (598 bin / equ shkoff), and the horizontal scaling used by the review program (3 equ xscalex). All of these parameters are loaded in when you type bob. You could define your own set of parameters for your data. Unknown to you, a trial type table is also assumed. This trial type table indicates the sequence of tone alone (1), paired tone-airpuff (2) and air alone (3) trials. Currently it is set as "122232222122232222122232222122232222122232222122232222122232222122232222122232222122 232222122232222122232222". To enter your own table, use a similar format and use: "1222322221222322221222322221222322221222322221222322221222322221222322 22122232222122232222122232222122232222" trialtypetable strcpy To make your own parameters and trial type table you would currently have to modify the file dave.txt. DO NOT DO THIS. It is better for me to make a copy of the dave.txt file and rename it for you to use. Specify computations -- e.g., special_info, hz_info, latency_info, spike_info, bin_info ... Type in your selection for the analysis. I think the most useful is special_info, which gives an x,y pair of latency,hertz on the printout for every cluster found. The other options for cluster analysis are to print out the frequency (hz_info), the latency (latency_info), unit count or spikes (spike_info), bin number (bin_info), the intercluster interval (ici_info), cluster duration (duration_info). Hz_info prints a + in front of significant high cluster activity, and prints a - in front of significant low cluster activity (see unit_Hz_criterion next). Frequency for each cluster is calculated and reported to the 1s place, whereas frequencies for the baseline and session are calculated and reported to the 0.01s place. Latency_info prints a - in front of clusters that begin before CS onset. Latencies have the precision of the bin width -- if the bin is 4 msec, then all reported latencies will be multiples of 4. Specify criterion level -- e.g., 3 equ unit_Hz_criterion You really do not have to specify this; you only have to specify this if you want to change it. The default is currently 3 (3 equ unt_Hz_criterion). Alternatively, type any whole number using this format to define the frequency criterion. This parameter is used to determine significant unit activity. The frequency of each cluster is compared with some baseline activity times (for high activity) or divided by (for low activity) the unit_Hz_criterion. The baseline activity is the preCS activity for the block (see by_block below) or for the session (see by_session below). In addition, preCS activity reported for each block is always compared with the preCS activity of the session, and indicated with a + or - sign if it is significant. This method for determining significance is so simple that it seems too good to be true. But it is true. Because of the number of observations involved, calculation of the mean and standard error of preCS frequencies yields a very small standard error. Even using several standard errors to determine significance is less conservative than simply using two or three times the baseline frequency. For the test file that I have been using to write this program (file = data.bob) the baseline is 14.14 +/- 2.28 Hz (mean +/- standard error). In this instance, using a criterion of twice the frequency is more than 6 times the standard error. Obviously, the standard error would be much greater when calculating the baseline frequency of a block of trials (because a block has fewer trials than the whole session). For the first block of the the data.bob file, the mean and standard error is 49.03 +/- 6.66 Hz when just using the data in the print out. The point here is that the standard error of 6.66 for the block is about 3 times the error for the day. Also noticed is that the mean reported for the first block (14.12 Hz) is not the same as what was just calculated (49.03) and that the frequencies reported at the end of the trials for the preCS activity does not have an obvious relation to either number (for trials 1-9 the frequencies are 12.71, cannot calculate, 25.42, 25.42, 41.67, 46.88, cannot calculate, 62.50, and 30.00). The discrepancy is due to the way that individual trials (i) cannot calculate the very first frequency, (ii) do not consider inactivity in the previous trial, and as a result (iii) cannot take into consideration frequencies when less than two clusters occur in the trial’s preCS period. A comparison of the frequencies for the individual trials with the frequency reported for the second block of data.bob (where there are not trials with “cannot calculate”) yields 18.66 versus 17.79 (respectively), which is much closer. This still does not take into consideration the very first cluster of every trial (i.e., clusters that begin at the end of one trial and start at the beginning of the following trial, as assumed by the baseline calculations). Based on the clusters reported in the printout for the second block, the mean +/- standard error are 40.68 +/- 6.34, which again does not take into consideration the the very first cluster or the clusters that span over trials. A simple calculation of the session preCS frequency found by dividing the total number of preCS units (385) by the total preCS time (252 msec times 107 good trials) and scaling for 1 second yields 14.28 Hz. This is very close to the reported session preCS frequency of 14.14 Hz. The reason they are not exactly the same is because the reported session preCS frequency does not include the time before the very first cluster of the session, does not include the units in the very first cluster of the session, and does not include the time after the very last cluster of the session -- all of which seem very reasonable to me. The reported frequency of 14.14 Hz is what I believe. The bottom line is that the trial, block and session frequencies and the trial clusters are accurately being reported on the printout. See assumptions below. [If you do analyze data.bob you might notice that trials 3 and 4 yield the same print outs -- that is because I copied trial 3 over trial 4 (or vice versa) because previously I had purposely corrupted the baseline of trial 4 (or trial 3) to create a bad trial when I was testing the programs.] Specify bad trial criterion -- e.g., 100 equ bad_units You really do not have to specify this; you only have to specify this if you want to change it. The default is currently 50 (50 equ bad_units). What this means is that if the total amount of unit activity found in the preCS period exceeds 50 counts, then that trial is treated as a bad trial and it is not included in the calculations. Specify type of analysis -- e.g., by_block or by_session You really do not have to specify this; you only have to specify this if you want to change it. The default is currently by_blocks. This parameter is used for determining whether the clusters in a trial will be compared with the preCS frequency that was computed for the block that the trial resides in (by_block), or compared with the preCS frequency that was computed for the entire session (by_session). Set printer -- e.g., +printer, -printer, true equ printing, false equ printing You really do not have to specify this; you only have to specify this if you want to change it. The default is currently set so that the analysis is displayed on the monitor, not the printer (-printer, which is the same as false equ printing). Start analysis with cluster<return> You start the analysis by typing cluster<return> . This command used to be xxx but it was recently changed -- I use xxx as a handy abbreviation when I am writing and debugging programs. That way, I do not have to remember what is the execute command (eXecute, xxx -- get it?). Once you start the analysis, you will be asked for the name of the file to analyze. You can specify the file name and the drive in the popup window. As the analysis proceeds to display (on the monitor) or print (on the laser printer) trial by trial, (almost) any press of any key will temporarily halt the display or printout. (Almost) any other key press will cause the display to continue. It is probably a good idea to keep your hands off the keyboard when printing -- you might accidentally pause the printing operation and not realize it, and end up wondering what is going on. The one special key is the <return> key -- pressing <return><return> or pressing any (other) key and then pressing <return> as the second key will cause the analysis to abort. Note that in the examples given they show that the commands can be given all on one line, and that multiple analyses can be done. The printout The printout tells you the file that the analysis is for, the type of data that is being reported, the unit criterion, the bad trial criterion, whether the analysis is by block or by session, and the number of unit channel being analyzed. The data is printed out trial by trial, and organized into blocks. Each trial is described as T (tone alone), P (paired) or A (air alone), followed by the trial number. If the trial is bad (i.e., if too many preCS unit counts were made) then this is indicated and no further computations are made for that trial. If the trial is good, then the clusters are printed out according to the type of information that you requested. PreCS clusters are separated from CS clusters by a “/” mark; CS clusters separated from UCS clusters by “//” marks. A new line is forced on the laser printer or the record would go beyond the right side of the page -- this sometimes leaves + or - signs or pairs of numbers on another line. [This is not a bug, it is just some prettying that I have not got around to fixing up.] At the end of the line is printed the preCS frequency for that trial (computed to 0.01 places) unless there are fewer than two clusters in the preCS period of that trial and then the message “cannot calculate PCS Hz” appears. The reason for this message is that the frequency of the very first cluster cannot be computed because it cannot be determined what the preceding intercluster interval should be. In working out different computation schemes I found that strangely high frequencies would be reported if I made the assumption that the intercluster interval began at the start of the trial. For example, if a unit occurred near the very beginning then the frequency of its cluster would be computed to be very high, even though the remaining clusters in the preCS period could be very low. I decided that it was better to drop the calculations for the first cluster rather than making an assumption about when previous activity might or might not have occurred. (See assumptions below.) At the end of every block the block number and the block’s preCS frequency is printed. The block frequency (to 0.01 places) is always compared with the preCS frequency computed for the entire session. A + is placed before the block’s preCS frequency if it is significantly above the session preCS frequency, and a - is placed if the block’s preCS frequency is significantly below the session preCS frequency. This is useful to know because it tells whether the preCS activity changes from block to block over the course of the session. Finally, at the end of the print out, is reported the total number of preCS units, the number of good trials, and the preCS frequency for the whole session (to 0.01 places). Creating a disk file If you wish to save the print out to a disk file instead of printing on the laser printer or to the console then you can use the following: >file c:\winforth\results.txt cluster console <return> or, if you are already in the directory that you wish, simply use >file results.txt cluster console <return> or, better yet, save to a floppy disk with >file b:results.txt cluster console <return> It is important to type this all on one line, with appropriate spacing and no errors, and to make sure that the filename does not already exist (here results.txt, but any legal DOS name can be used) -- if it already exists then that data will be written over. It would be a better idea if you save this on a floppy disk. A printout-to-disk using special_info yielded a file more than 21k in size. A lot of files like this would easily take up all the hard disk space. So I recommend that you save to a floppy instead of to the hard drive. Removing a disk file If you wish to remove the file you just created above then you can type del results.txt <return> That’s all there is to it. Be sure that you are removing the file that you intend. Assumptions Very few assumptions are actually made in this analysis. First, I am assuming that clustering is a reasonable thing to do -- that seems to be what my eye and brain is doing when I look at unit activity. For single unit activity the only real question is whether the precision of the data -- determined by the bin width -- can resolve frequencies and latencies. Given the nature of the data, and experience with the analysis, I think this is reasonable within those limits. Whether single and multiple unit activity can be treated in the same way is an open question. If multiple unit data is considered to be a sample of single units then I see no problem as long as one’s conclusions stay within the limits of the data -- (i) that this is a sample, (ii) that conclusions about individual units cannot be made. Second, since I am not using the standard error of preCS activity, I am not making any assumptions about a normal distribution. But I am assuming that a simple arithmetic computation (two or three times the baseline activity, for example) is a reasonable way to determine significant unit activity. This seems reasonable to me since (i) this is far more conservative than using standard errors, and (ii) it is far easier to compute. Third, the only other assumption that I recall occurs in the computation of the preCS baseline. The frequency of the very first cluster of every trial is not computed when printing out each trial’s clusters because the previous period of inactivity is indeterminate. When computing the session preCS baseline, however, if I adopted this strategy of dropping the first cluster of every trial, then I would lose a lot of clusters in the course of a session (in a session of 108 trials, I could potentially lose 108 clusters). Instead, for the computation of preCS baseline for both the block and session (but not for reporting clusters for every trial), I pretend that all the preCS baseline periods occur one right after the other. That way, for example, the intercluster interval on the second trial includes the period of inactivity at the beginning of its baseline period and it includes the inactivity at the end of the preceding trial, trial 1. Therefore, for computing the baseline frequency, only the very first cluster of the block or of the session is excluded in the computation of the frequency. It seems to me that this is a reasonable assumption if the baseline preCS periods are truly independent of each other and representative samples, and because this approach includes as much of the data as possible. This is confirmed by the fact that the reported frequency for the session for the file data.bob of 14.14 Hz is very close to the frequency when the total number of units is divided by the total amount of baseline time (14.28 Hz). Cluster analysis source code: dave.txt The following is the actual source code for the basic implementation of the cluster program. This file, dave.txt, is a modification of the Review routine that has been imported from the Summary program. As noted above, this program differs from other Forth programs we have seen in that it does not use the 'screen' structure of the original Forth programming, comments are mostly enclosed in parentheses, and some of the programming is specific to implementing and maintaining windows (Windows 3.1). Note that we have made good use of the case structure that is available for this version of Forth for programming options. ( ( ( ( ( ( ( ( ( ( ( o based on demo27.4th using GDI drawing Copyright C 1993 LMI) o created as dave.4th on 04jan96dgl) o functions with the printer. ) o however, i just spent a long time with C and windows and did not) o figure out how to use the printer correctly. gave up. 12mar96dgl.) o most recent update of dave.4th was 23may96dgl) o created as dave.txt on 11 February 1997 -- brought 4th files together into one large txt file) o dave.txt modified 12 Februarry 1997 -- prettying format) o dave.txt modified 11 March 1997 -- prettying format) o dave.txt modified 12 March 1997 -- rename some words) o dave.txt modified 25 March 1997 -- added +printer, -printer, frequency_info, freq_info) forget it create it ( programming helps ...) 1024 constant 1k 13 constant eol# 27 constant esc# 0 constant dummy 80 equ items 0 equ counter ( used by graphics.) 0 equ _trl# ( temporary storage for trial number; used by graphics.) : nuf? ( -- flag) false ?terminal ( was there a key press?) if key drop ( don't care what first key was) key eol# = ( is second key a return?) if drop true then then ; : u<= ( n1 n2 -- flag) 2dup = -rot u< or ; ( printer enhancements) false equ printing : page ( --) 12 emit ; : +condensed ( --) esc# emit " (s16.66h8.5v0T" count type ; : -condensed ( --) esc# emit " (s12h10v3T" count type ; : +printer ( --) true equ printing ; : -printer ( --) false equ printing ; ( the following was originally in the file definitions.run) ( common definitions for runtime/summary programs) ( runtime/summary definitions) ( total) ( counter) 0 equ #a/d 0 equ a/d# 0 equ #units 0 equ unit# 0 equ #trls 0 equ #blks 0 equ #t/blk 0 equ trl# 0 equ blk# 0 equ t/blk# 0 equ bin 0 equ pts 0 equ toneon 0 equ lton 0 equ shkon 0 equ bin# 0 equ toneoff 0 equ ltoff 0 equ shkoff 6 equ badtime ( Note: this is in bins, not milliseconds) 7 equ bada/d 0 equ badtrial ( flag for bad trial) 50 equ bad_units ( number of counts in entire preCS period) ( bad_units is used in .info, .cmds, get_PCS_spikes, bad_PCS_spikes) 40 equ baseln ( Note: this is in bins, not milliseconds, before CS period) 5 equ critlevel ( CS period criterion level for a/d) 3 equ unit_Hz_criterion ( used for graphing Hz for several trials.) 1 equ start 10 equ end 0 equ stagger 1 equ _unit# ( temporary storage variable) : valid_trials ( to fr -- to|to' fr|fr') 1 max swap #trls 1+ min swap ; : through ( start end --) valid_trials equ end equ start ; ascii 0 equ tones ascii 0 equ airs ascii 0 equ pairs : tone ( --) ascii 1 equ tones ascii 0 equ pairs ascii 0 equ airs ; : paired ( --) ascii 0 equ tones ascii 2 equ pairs ascii 0 equ airs ; : air ( --) ascii 0 equ tones ascii 0 equ pairs ascii 3 equ airs ; : all ( --) ascii 1 equ tones ascii 2 equ pairs ascii 3 equ airs ; : trial ( --) noop ; : trials ( --) noop ; : alone ( --) noop ; all trials ( default) ( used for graphing single trial display.) 0 equ mode ( 0 = unit histogram, 1 = unit frequency ) ( common values ...) 0 equ array ( used to hold pointer to beginning of data bloc) 3 equ xscalex 1 equ a/d1x 1 equ a/d2x 1 equ a/d3x 1 equ a/d4x 3 equ a/d1/ 3 equ a/d2/ 3 equ a/d3/ 3 equ a/d4/ 3 equ unit1x 3 equ unit2x 3 equ unit3x 3 equ unit4x 1 equ unit1/ 1 equ unit2/ 1 equ unit3/ 1 equ unit4/ 1 equ hz1x 3 equ hz1/ ( drawing variables ...) 0 equ offset ( used to set y origin of plot) 0 equ cr_offset ( used by calculating functions) 0 equ x1 0 equ y1 0 equ x2 0 equ y2 ( switches ...) 0 equ trial/-block ( 0 = trial, 1 = block, 2 = unit frequencies) false equ bad_trial? false equ info ( display info about CR criteria, etc.) false equ cmds ( measurements ...) 0 equ PCSamp+ 0 equ PCSamp- 0 equ PCSpklat+ 0 equ PCSpklat- 0 equ |PCSamp| 0 equ baseline 0 equ CSamp+ 0 equ CSamp- 0 equ CSpklat+ 0 equ CSpklat- 0 equ CScrit+ 0 equ CScrit0 equ UCSamp+ 0 equ UCSamp- 0 equ UCSpklat+ 0 equ UCSpklat- 0 equ UCScrit+ 0 equ UCScrit0 equ accumulator ( arrays ...) create ram1 1024 allot ram1 1024 erase create ram2 2048 allot ram2 1024 erase create string1 256 allot create string2 256 allot ( the following used to be in the file trialtypes.run ) ( trial type table ) create trialtypetable 512 allot trialtypetable 512 erase ( data.ben ...) (" 122223222212222322221222232222122223222212222322221222232222122223222212222322221222 2322221222232222" trialtypetable strcpy) ( data.bob, claire_tones, claire_lights ...) " 122232222122232222122232222122232222122232222122232222122232222122232222122232222122 232222122232222122232222" trialtypetable strcpy ( the following used to be in the file datasets.run ) ( bob, xty, ben) : bob ( --) ( parameters for data.bob ...) 1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks 1 equ #a/d 4 equ #units 4 equ bin 756 bin / equ pts 252 bin / equ toneon 598 bin / equ toneoff 504 bin / equ shkon 598 bin / equ shkoff 3 equ xscalex ; : xty ( --) ( parameters for data.xty ...) 1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks 1 equ #a/d 4 equ #units 4 equ bin 756 bin / equ pts 252 bin / equ toneon 598 bin / equ toneoff 504 bin / equ shkon 598 bin / equ shkoff 3 equ xscalex ; : ben ( --) ( parameters for data.ben ...) 1 equ trl# 10 equ #t/blk 100 equ #trls 10 equ #blks 4 equ #a/d 0 equ #units 4 equ bin 1000 bin / equ pts 248 bin / equ toneon 596 bin / equ toneoff 496 bin / equ shkon 596 bin / equ shkoff 2 equ xscalex ; : claire_tones ( --) ( parameters for claire with tones) 1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks 1 equ #a/d 4 equ #units 4 equ bin 756 bin / equ pts 252 bin / equ toneon 598 bin / equ toneoff 504 bin / equ shkon 598 bin / equ shkoff 3 equ xscalex ; : claire_lights ( --) ( parameters for claire with lights) 1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks 1 equ #a/d 4 equ #units 4 equ bin 1008 bin / equ pts 252 bin / equ toneon 856 bin / equ toneoff 756 bin / equ shkon 856 bin / equ shkoff 3 equ xscalex ; ( the following used to be in the file windows.run ) ( local variables for drawing & printing ) 0 equ xpixels/inch ( logpixelsx) 0 equ localpagex 0 equ localhorizmarg 0 equ localdc 0 equ localfrom 2variable 2upperleft 0 equ rightside 0 equ ypixels/inch ( logpixelsy) 0 equ localpagey 0 equ localvertmarg 0 equ localto 2variable 2lowerright 0 equ bottomside ( magic numbers from WINDOWS.H from DEVCAPS.4TH ...) ( mapping modes ...) 1 constant mm_text ( pixel) 2 constant mm_lometric ( 0.1 mm) 3 constant mm_himetric ( 0.01 mm) 4 constant mm_loenglish ( 0.01 inch) 5 constant mm_hienglish ( 0.001 inch) 6 constant mm_twips ( 1/1440 inch) 7 constant mm_isotropic ( arbitrary x=y) 8 constant mm_anisotropic ( arbitrary x<>y) ( 0 CONSTANT DRIVERVERSION ) ( 2 CONSTANT TECHNOLOGY ) 4 CONSTANT HORZSIZE ( width in mm ) 6 CONSTANT VERTSIZE ( height in mm ) 8 CONSTANT HORZRES ( width in pixels ) 10 CONSTANT VERTRES ( height in pixels ) 12 CONSTANT BITSPIXEL ( ( ( ( ( ( ( ( ( ( ( ( ( 14 CONSTANT 16 CONSTANT 18 CONSTANT 20 CONSTANT 22 CONSTANT 24 CONSTANT 26 CONSTANT 28 CONSTANT 30 CONSTANT 32 CONSTANT 34 CONSTANT 36 CONSTANT 38 CONSTANT 40 CONSTANT 42 CONSTANT 44 CONSTANT 88 CONSTANT 90 CONSTANT ( 104 CONSTANT ( 106 CONSTANT ( 108 CONSTANT WCB MAINWIN PLANES ) NUMBRUSHES) NUMPENS ) NUMMARKERS ) NUMFONTS ) NUMCOLORS ) PDEVICESIZE ) CURVECAPS ) LINECAPS ) POLYGONALCAPS ) TEXTCAPS ) CLIPCAPS ) RASTERCAPS ) ASPECTX ( relative width in pixels ) ASPECTY ( relative height in pixels ) ASPECTXY ( relative diagonal in pixels) LOGPIXELSX ( width in pixels per inch ) LOGPIXELSY ( width in pixels per inch ) SIZEPALETTE ) NUMRESERVED ) COLORRES ) ( window control block for frame window) ( the following used to be in the file popups.run ) create filename 64 allot filename 64 erase : selectfile ( --) ( open data file for analysis ...) ( NOTE: open-scr automatically closes previous block file before opening new one.) " Data files | data.* | Block files | *.scr | All files | *.*" opendlg dup filename strcpy open-scr if ." Invalid file selection" quit then ; ( arbitrary identifiers for menu items) 100 CONSTANT IDM_FILEPRINT 101 CONSTANT IDM_FILEEXIT 102 CONSTANT idm_openfile 103 constant idm_trial+ 104 constant idm_trial105 constant idm_jump 106 constant idm_block+ 107 constant idm_block108 constant idm_stop 109 constant idm_start 110 constant idm_end 111 constant idm_interpretter 112 constant idm_source ( 113 constant idm_average) 114 constant idm_info 115 constant idm_cmds MENU APPMENU " &File" POPUP " &Open" idm_openfile mf_enabled menuitem " &Print" IDM_FILEPRINT MF_ENABLED MENUITEM "" 0 MF_SEPARATOR MENUITEM " &Exit" IDM_FILEEXIT MF_ENABLED MENUITEM END-POPUP " |<" idm_start mf_enabled menuitem " <<" idm_blockmf_enabled menuitem " <" idm_trialmf_enabled menuitem ( " -" idm_stop mf_enabled menuitem) " >" idm_trial+ mf_enabled menuitem " >>" idm_block+ mf_enabled menuitem " >|" idm_end mf_enabled menuitem " &Jump" idm_jump mf_enabled menuitem " &Interpretter" idm_interpretter mf_enabled menuitem " &Source" idm_source mf_enabled menuitem ( " &Average" idm_average mf_enabled menuitem) " i&Nfo" idm_info mf_enabled menuitem " &Cmds" idm_cmds mf_enabled menuitem END-MENU 100 equ id_ok 102 equ id_input 103 equ id_cancel 104 equ id_interpretter " Jump to Trial #..." 100 20 110 50 DS_MODALFRAME WS_CAPTION D+ WS_POPUP D+ dialog jumpdlg " Enter Trial Number" 10 10 70 16 -1 ltext 80 10 20 12 id_input edittext " OK" 24 30 32 16 id_ok defpushbutton " Cancel" 64 30 32 16 id_cancel pushbutton END-DIALOG variable jump# 1 jump# ! : jumpprocedure ( -- flag) ( this is the callback handler for jump) wMsg WM_INITDIALOG = if id_input jump# @ dsetuint true exit then wMsg WM_COMMAND = if wParam id_ok = if id_input dgetuint jump# ! 1 closedlg else wParam id_cancel = if 0 closedlg then then then false ; " Interpretter ..." 50 20 200 60 DS_MODALFRAME WS_CAPTION D+ WS_POPUP D+ dialog interpretterdlg " Enter Forth Command" 10 5 70 16 -1 ltext 10 15 180 12 id_input edittext " OK" 70 35 30 16 id_ok defpushbutton " Cancel" 110 35 30 16 id_cancel pushbutton END-DIALOG create interpretterbuffer 80 allot interpretterbuffer 80 erase : interpretterprocedure ( -- flag) ( this is the callback handler for jump) wMsg WM_INITDIALOG = if id_input interpretterbuffer dsettext true exit then wMsg WM_COMMAND = if wParam id_ok = if id_input dgettext interpretterbuffer strcpy 1 closedlg else wParam id_cancel = if 0 closedlg then then then false ; ( " Average Trials ..." 100 20 90 50 DS_MODALFRAME WS_CAPTION D+ WS_POPUP D+) ( dialog averagedlg) ( " Enter Beginning Trial Number" 5 10 70 16 -1 ltext) ( 75 10 10 12 id_input edittext) ( " OK" 5 30 32 16 id_ok defpushbutton) ( " Cancel" 40 30 32 16 id_cancel pushbutton) ( END-DIALOG) ( variable averagestart 1 averagestart !) ( : averageprocedure (( -- flag \\ this is the callback handler for jump) ( wMsg WM_INITDIALOG =) ( if id_input averagestart @ dsetuint true exit then) ( wMsg WM_COMMAND =) ( if wParam id_ok = ) ( if) ( id_input dgetuint averagestart ! ) ( 1 closedlg) ( else ) ( wParam id_cancel =) ( if 0 closedlg then) ( then) ( then ) ( false ;) : legendfont ( --) " Arial" ( ^fontname) ff_swiss ( family) 10 ( size) fs_normal fs_bold or ( style) localdc ( wcb) wsetfont ; : coloring ( dn --) 2dup ( dn dn) pen ( dn) brush ; ( the following used to be in the file measure1.run ) ( printout text output) ( : .out$ \\ str --) ( >r localdc dup GetCurrentPosition ds0 r> \\ str\\ count TextOut drop ;) ( : .out# \\ # --) ( >r localdc dup GetCurrentPosition ds0 r> \\ #\\ s>d <# #s #> TextOut drop ;) ( : .out.# \\ # --) ( >r localdc dup GetCurrentPosition ds0 r> \\ #\\ s>d <# # ascii . hold #s #> TextOut drop ;) ( : .out#$ \\ i+1|trl# str --) ( swap >r >r localdc dup GetCurrentPosition ds0 r> \\ str\\ count r> \\ i+1\\ s>d <# #s #> strcat TextOut drop ; ) : mm>string ( n -- adr #) s>d <# bl hold #s #> ; : mm>+-string.r ( n -- adr #) ( 10ths decimal place AND takes into account sign.) s>d dup -rot dabs <# bl hold # ascii . hold #s rot sign #> ; : ms>string ( n -- adr #) s>d <# bl hold #s #> ; : ms>+-string ( n -- adr #) s>d dup -rot dabs <# bl hold #s rot sign #> ; : device_cr ( --) ( device-independent carriage return) localdc 0 ( x) offset ( y) SetViewportOrg 2drop localdc 0 0 Moveto 2drop offset printing if 40 else 20 then + equ offset ; : .trial# ( --) ( print trial #) legendfont lightred coloring device_cr localdc dup GetCurrentPosition ds0 trial/-block case 0 of ( trial ...) " trial # " string1 strcpy string1 count trl# mm>string strcat " calculations ... " count strcat endof 1 of ( block ...) " block average" string1 strcpy string1 count " , trials " count strcat start mm>string strcat " through " count strcat end mm>string strcat " ; trial types = " count strcat tones ascii 1 = pairs ascii 2 = and airs ascii 3 = and if " all " count strcat else tones ascii 1 = if " tones " count strcat then pairs ascii 2 = if " paired " count strcat then airs ascii 3 = if " airs " count strcat then then endof 2 of ( unit frequencies ...) " unit # " string1 strcpy string1 count unit# mm>string strcat " , trials " count strcat start mm>string strcat " through " count strcat end mm>string strcat " ; trial types = " count strcat tones ascii 1 = pairs ascii 2 = and airs ascii 3 = and if " all " count strcat else tones ascii 1 = if " tones " count strcat then pairs ascii 2 = if " paired " count strcat then airs ascii 3 = if " airs " count strcat then then endof endcase TextOut drop device_cr noop ; : .info ( --) ( print information) info if localdc dup GetCurrentPosition ds0 " a CR is movement >= " string1 strcpy string1 count critlevel mm>+-string.r strcat " mm between tone onset plus " count strcat badtime bin * ms>string strcat " ms" count strcat TextOut drop device_cr localdc dup GetCurrentPosition ds0 " and airpuff onset" count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " a bad trial is movement >= +/-" string1 strcpy string1 count bada/d mm>+-string.r strcat " mm in the " count strcat baseln bin * ms>string strcat " ms before CS onset" count strcat TextOut drop device_cr localdc dup GetCurrentPosition ds0 " or >= +" string1 strcpy string1 count bada/d mm>+-string.r strcat " mm between CS onset and CS onset plus " count strcat badtime bin * ms>string strcat " ms" count strcat TextOut drop legendfont lightred coloring device_cr localdc dup GetCurrentPosition ds0 " also, a CR is unit activity > " string1 strcpy string1 count unit_Hz_criterion mm>string strcat " times each unit's PCS baseline frequency " count strcat TextOut drop device_cr localdc dup GetCurrentPosition ds0 " and, a bad trial is unit actvity >= " string1 strcpy string1 count bad_units mm>string strcat " counts in the entire PCS period" count strcat TextOut drop device_cr then ; : .cmds ( --) ( print commands) cmds if device_cr trial/-block case 0 of ( trial) localdc dup GetCurrentPosition ds0 " The following commands are available for trial analysis:" string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " frequency, frequencies, histogram, histograms, n equ unit_Hz_criterion," string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " ici_info, duration_info, spike_info, time_info, bin_info (raw_info)," string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " latency_info, hz_info, n equ bada/d, n equ badtime [postCS], n equ baseln [preCS], and n equ bad_units." string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " Execution is transparent to user (no special command) for trials." string1 strcpy string1 count TextOut drop device_cr endof 1 of ( block) localdc dup GetCurrentPosition ds0 " The following commands are available for block analysis:" string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " zero, n1 n2 through, add, subtract, average," string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " tone, tone alone, air, air alone, alone, paired, all trials, all, trials." string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " n equ bada/d, n equ badtime [postCS], n equ baseln [preCS], and n equ bad_units." string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " Execution is through add, subtract and average." string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " E.g.: zero paired 1 10 through add average." string1 strcpy string1 count TextOut drop device_cr endof 2 of ( frequencies) localdc dup GetCurrentPosition ds0 " The following commands are available for frequency analysis:" string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " n1 equ start, n2 equ end, n1 n2 through, unit1, unit2, unit3, unit4," string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " n1 equ unit_Hz_criterion, and n equ stagger; tone alone, air alone, paired, all trials, " string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " n equ bada/d, n equ badtime [postCS], n equ baseln [preCS], and n equ bad_units." string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " Execution is transparent to user (no special command) for frequencies." string1 strcpy string1 count TextOut drop device_cr localdc dup GetCurrentPosition ds0 " E.g.: unit2 paired 1 10 through." string1 strcpy string1 count TextOut drop device_cr endof endcase localdc dup GetCurrentPosition ds0 " Where n, n1 and n2 are numbers the user enters on the stack." string1 strcpy string1 count TextOut drop device_cr then ; : print_a/d_data ( --) ( print data legend) legendfont lightred coloring device_cr localdc dup GetCurrentPosition ds0 " a/d # " string1 strcpy string1 count ( adr1 #1) a/d# s>d <# #s #> ( adr1 #1 adr2 #2) strcat " ... " count strcat " " count strcat ( this adds spaces before the numbers) baseline mm>string strcat " " count strcat PCSamp+ mm>+-string.r strcat PCSpklat+ ms>string strcat PCSamp- mm>+-string.r strcat PCSpklat- ms>string strcat |PCSamp| mm>+-string.r strcat " " count strcat CSamp+ mm>+-string.r strcat CSpklat+ ms>string strcat CScrit+ ms>+-string strcat CSamp- mm>+-string.r strcat CSpklat- ms>string strcat CScrit- ms>+-string strcat " " count strcat UCSamp+ mm>+-string.r strcat UCSpklat+ ms>string strcat UCScrit+ ms>+-string strcat UCSamp- mm>+-string.r strcat UCSpklat- ms>string strcat UCScrit- ms>+-string strcat " " count strcat badtrial ms>+-string strcat ( calculate badtrial = badtime + bada/d ...) bada/d |PCSamp| u<= badtrial 0= or badtrial 0> or if " bad" count strcat then ( calculate CR trial = valid CRcrit+ ...) trl# 1- trialtypetable 1+ + c@ ascii 1 = ( tone alone trials) if CScrit+ 0= CScrit+ 0> or UCScrit+ 0= or UCScrit+ 0> or if " CR" count strcat then then trl# 1- trialtypetable 1+ + c@ ascii 2 = ( tone-airpuff trials) if CScrit+ 0= CScrit+ 0> or if " CR" count strcat then then TextOut drop ; ( the following used to be in the file measure2.run ) ( a/d analysis) : measure_baseline ( --) 000 ( dummy) toneon ( to) 0 ( fr) ?do array i + c@ + loop toneon / equ baseline ; : measure_badtime ( --) toneon badtime + bin * negate equ badtrial ( default_value) toneon badtime + ( to) toneon ( fr) ?do array i + c@ baseline bada/d - u<= if i toneon - bin * equ badtrial leave then loop ( actual crit latency) ; : measure_a/ds_precs ( --) 000 ( dummy) toneon ( to) toneon baseln - 0 max ( fr) ?do array i + c@ max loop ( fake minimum_value | dummy) equ PCSamptoneon ( to) toneon baseln - 0 max ( fr) ?do array i + c@ PCSamp- = if i leave then loop ( actual minimum latency) equ PCSpklat255 ( dummy) toneon ( to) toneon baseln - 0 max ( fr) ?do array i + c@ min loop ( fake maximum_value | dummy) equ PCSamp+ toneon ( to) toneon baseln - 0 max ( fr) ?do array i + c@ PCSamp+ = if i leave then loop ( actual maximum latency) equ PCSpklat+ ( corrections: invert calculations for actual values ...) baseline PCSamp+ - equ PCSamp+ baseline PCSamp- - equ PCSampPCSamp+ PCSamp- - abs equ |PCSamp| PCSpklat+ bin * equ PCSpklat+ PCSpklat- bin * equ PCSpklat- ; : measure_a/ds_cs ( --) 000 ( dummy) shkon ( to) toneon ( fr) ?do array i + c@ max loop ( fake minimum_value | dummy) equ CSamp000 ( dummy) shkon ( to) toneon ( fr) ?do array i + c@ CSamp- = if i + leave then loop ( actual minimum latency) equ CSpklat255 ( dummy) shkon ( to) toneon ( fr) ?do array i + c@ min loop ( fake maximum_value | dummy) equ CSamp+ 000 ( dummy) shkon ( to) toneon ( fr) ?do array i + c@ CSamp+ = if i + leave then loop ( actual maximum latency) equ CSpklat+ ( calculate CS +criterion ...) shkon toneon - bin * negate equ CScrit+ ( default_value) shkon ( to) toneon badtime + ( fr) ?do array i + c@ baseline critlevel - u<= if i toneon - bin * equ CScrit+ leave then loop ( actual crit latency) ( calculate CS -criterion ...) shkon toneon - bin * negate equ CScrit- ( default_value) shkon ( to) toneon badtime + ( fr) ?do array i + c@ baseline critlevel + swap u<= if i toneon - bin * equ CScrit- leave then loop ( actual crit latency) ( corrections: invert calculations for actual values ...) baseline CSamp+ - equ CSamp+ baseline CSamp- - equ CSampCSpklat+ toneon - bin * equ CSpklat+ CSpklat- toneon - bin * equ CSpklat- ; : measure_a/ds_ucs ( --) 000 ( dummy) pts ( to) shkon ( fr) ?do array i + c@ max loop ( fake minimum_value | dummy) equ UCSamp000 ( dummy) pts ( to) shkon ( fr) ?do array i + c@ UCSamp- = if i + leave then loop ( actual minimum latency) equ UCSpklat255 ( dummy) pts ( to) shkon ( fr) ?do array i + c@ min loop ( fake maximum_value | dummy) equ UCSamp+ 000 ( dummy) pts ( to) shkon ( fr) ?do array i + c@ UCSamp+ = if i + leave then loop ( actual maximum latency) equ UCSpklat+ ( calculate UCS +criterion ...) pts shkon - bin * negate equ UCScrit+ ( default_value) pts ( to) shkon ( fr) ?do array i + c@ baseline critlevel - u<= if i shkon - bin * equ UCScrit+ leave then loop ( actual crit latency) ( calculate UCS -criterion ...) pts shkon - bin * negate equ UCScrit- ( default_value) pts ( to) shkon ( fr) ?do array i + c@ baseline critlevel + swap u<= if i shkon - bin * equ UCScrit- leave then loop ( actual crit latency) ( corrections: invert calculations for actual values ...) baseline UCSamp+ - equ UCSamp+ baseline UCSamp- - equ UCSampUCSpklat+ shkon - bin * equ UCSpklat+ UCSpklat- shkon - bin * equ UCSpklat- ; : get_a/d_data ( --) trial/-block case 0 of ( trial) trl# block ( adr) ram1 1024 cmove ram1 ( adr) a/d# 1- pts * ( a/d offset) + equ array endof 1 of ( block) noop trl# block ( adr) ram1 1024 cmove ram2 ( adr) a/d# 1- pts * ( a/d offset) + equ array endof 2 of ( unit frequencies) endof endcase ; : measure_a/ds ( --) ( calculations for each a/d channel) #a/d ( to) 0 ( fr) ?do i 1+ equ a/d# ( useful for parameter passing) get_a/d_data measure_baseline measure_badtime measure_a/ds_precs measure_a/ds_cs measure_a/ds_ucs print_a/d_data loop ; ( the following used to be in the file measure3.run ) ( unit analysis -- definitions for cluster analysis) ( create cluster ) ( ********************************* variables *********************************) 0 equ spikes_this_trial 0 equ max_spikes/cluster 0 equ preCS_spikes/cluster 0 equ ici 0 equ spikes_in_cluster 0 equ start_bin# 0 equ end_bin# 0 equ cluster_duration 0 equ carryover 0 equ total_PCS_spikes 0 equ total_PCS_clusters 0 equ total_PCS_icis 0 equ total_PCS_spikes/cluster 0 equ total_maximum_PCS_spikes/cluster 0 equ total_spikes 0 equ PCS_clusters_this_trial ( ********************************* switches *********************************) false equ valid_cluster 0 equ total_good_trials ( ****************************** bookkeeping *********************************) 0 equ start_range 0 equ end_range ( *** arrays -- removed from this implementation.) ( size -- removed from this implementation.) ( distribution -- removed from this implementation.) ( empty -- removed from this implementation.) ( ******************************** procedures *********************************) noop ( ********************************* baseline **********************************) : get_PCS_spikes ( --) ( used in quietly_analyze_PCS_units) dummy toneon ( to) 0 ( fr) ?do ( determine total number of spikes in period in trial ...) array i + c@ + loop ( count) bad_units over u<= if true equ bad_trial? else false equ bad_trial? total_PCS_spikes over + equ total_PCS_spikes total_good_trials 1+ equ total_good_trials then total_spikes over + equ total_spikes ( accumulate counts from every trial) ( count) equ spikes_this_trial noop ; ( *** array management -- removed from this implementation.) ( ici_field -- removed from this implementation.) ( next_ici_field -- removed from this implementation.) ( spikes_in_cluster_field -- removed from this implementation.) ( frequency_field -- removed from this implementation.) ( update_spike_frequency -- removed from this implementation.) ( insert_in_distribution -- removed from this implementation.) ( exact_match -- removed from this implementation.) ( smaller_near_match -- removed from this implementation.) ( larger_near_match -- removed from this implementation.) ( default_match -- removed from this implementation.) ( search_distribution -- removed from this implementation.) ( enter_distribution -- removed from this implementation.) ( ****************************** cluster search *******************************) : skip_first_cluster ( --) ( I might want to keep this available for this implementation.) trl# 1 = ( prevent ici calc on very first cluster ...) if false equ valid_cluster else true equ valid_cluster then ; : find_start_of_cluster ( --) ( cannot be removed from this implementation.) begin ( find start of cluster ...) bin# end_range u< array bin# + c@ 0= and while bin# 1+ equ bin# repeat ; : calculate_ici ( --) ( cannot be removed from this implementation.) array bin# + c@ 0<> ( calculate ici ...) if ( if yes, can calculate ici) bin# equ start_bin# ( information = 1, in_bins) start_bin# end_bin# - carryover + equ ici ( information = 4, in_ici) else ( last bin of period has no unit in it) carryover toneon end_bin# - + equ carryover 0 equ start_bin# 0 equ end_bin# then ; : find_end_of_cluster ( --) ( cannot be removed from this implementation.) 0 equ spikes_in_cluster begin bin# end_range u< array bin# + c@ 0<> and while spikes_in_cluster array bin# + c@ + equ spikes_in_cluster ( equivalent to c+!) bin# 1+ equ bin# repeat ; ( print_information -- removed from this implementation.) ( find_and_print_clusters -- removed from this implementation.) ( find_and_print_PCS_clusters -- removed from this implementation.) ( print_distribution -- removed from this implementation.) ( ************************** unit data distribution ***************************) 1k 2* equ unit_size create unit_distribution unit_size allot 0 equ unit1_pointer 0 equ unit2_pointer 0 equ unit3_pointer 0 equ unit4_pointer : empty_unit_distribution ( --) unit_distribution unit_size erase 0 equ unit1_pointer 0 equ unit2_pointer 0 equ unit3_pointer 0 equ unit4_pointer ; : set_unit_pointers ( --) ( set pointers into unit_distribution depending on #units) ( used in measure_units, measure_one_unit & review) #units 0 u> if unit_distribution equ unit1_pointer then #units 1 u> if unit_distribution unit_size #units / + equ unit2_pointer then #units 2 u> if unit_distribution unit_size #units / 2 * + equ unit3_pointer then #units 3 u> if unit_distribution unit_size #units / 3 * + equ unit4_pointer then noop ; : print_data ( --) ( aka print_unit_distribution; used for debugging) cr cr " unit 1 > " count type cr pts 0 ?do unit1_pointer i 2* + @ u. i 20 mod 0= if cr then nuf? if leave then loop cr cr " unit 2 > " count type cr pts 0 ?do unit2_pointer i 2* + @ u. i 20 mod 0= if cr then nuf? if leave then loop cr cr " unit 3 > " count type cr pts 0 ?do unit3_pointer i 2* + @ u. i 20 mod 0= if cr then nuf? if leave then loop cr cr " unit 4 > " count type cr pts 0 ?do unit4_pointer i 2* + @ u. i 20 mod 0= if cr then nuf? if leave then loop noop ; 0 equ unit1_PCS_Hz 0 equ unit2_PCS_Hz 0 equ unit3_PCS_Hz 0 equ unit4_PCS_Hz ( ********************************** main ************************************) : get_unit_data ( --) trial/-block case 0 of ( trial) trl# block ( adr) ram1 1024 cmove ram1 ( adr) unit# 1- #a/d + pts * ( a/d offset) + equ array endof 1 of ( block) noop trl# block ( adr) ram1 1024 cmove ram2 ( adr) unit# 1- #a/d + pts * ( a/d offset) + equ array endof 2 of ( unit frequencies) trl# block ( adr) ram1 1024 cmove ram1 ( adr) unit# 1- #a/d + pts * ( a/d offset) + equ array endof endcase ; : quietly_analyze_PCS_units ( --) ( used in review) ( does NOT print out and does NOT use debugging words ...) ( to see the results use print_distribution.) ( empty has been removed from this implementation) #units ( to) 0 ( fr) ?do i 1+ equ unit# 0 equ start_bin# 0 equ end_bin# 0 equ total_spikes 0 equ max_spikes/cluster 0 equ total_PCS_spikes 0 equ total_PCS_clusters 0 equ total_PCS_icis 0 equ total_good_trials 0 equ carryover false equ bad_trial? toneon 256 u< not if " Distribution array too small " count type abort then ( ... error handler) #trls ( to) 0 ( fr) ?do ( for every trial ...) i 1+ equ trl# get_unit_data get_PCS_spikes ( find_and_print_PCS_clusters has been removed from this implementation) nuf? if leave then loop ( calculate PCS Hz for each unit ...) 1000 ( msec/sec) 10 * ( scale) ( n1) total_PCS_spikes ( n2) total_good_trials toneon * bin * ( n3) */ 5 + 10 / ( answer) ( ... round) unit# case 1 of equ unit1_PCS_Hz endof 2 of equ unit2_PCS_Hz endof 3 of equ unit3_PCS_Hz endof 4 of equ unit4_PCS_Hz endof drop ( default) endcase noop loop ; : bad_PCS_spikes? ( --) dummy toneon ( to) 0 ( fr) ?do ( determine total number of spikes in period in trial ...) array i + c@ + loop ( count) bad_units over u<= if true equ bad_trial? else false equ bad_trial? total_PCS_spikes over + equ total_PCS_spikes total_good_trials 1+ equ total_good_trials then ( count) equ spikes_this_trial noop ; : calculate_Hz ( -- hz) 1000 ( msec/sec) 10 * ( scale) ( n1) spikes_in_cluster ( n2) ici cluster_duration + bin * ( n3) */ 5 + 10 / ( answer) ( ... round) noop ; 7 equ information ( default) ( used in find_CS_clusters & in measure_units) : ici_info ( --) 1 equ information ; : duration_info ( --) 2 equ information ; : spike_info ( --) 3 equ information ; : time_info ( --) 4 equ information ; : bin_info ( --) 5 equ information ; : raw_info ( --) bin_info ; ( alias) : start_info ( --) bin_info ; ( alias) : latency_info ( --) 6 equ information ; : hz_info ( --) 7 equ information ; : frequency_info ( --) hz_info ; ( alias) : freq_info ( --) hz_info ; ( alias) : special_info 8 equ information ; : test_info 9 equ information ; : find_CS_clusters ( dc x y ds0 adr n -- dc x y ds0 adr n|n') 0 equ start_bin# 0 equ end_bin# 0 equ spikes_in_cluster 0 equ carryover false equ valid_cluster bad_trial? not if 0 equ start_range pts equ end_range ( parameters needed for passing to cluster words) end_range ( to) start_range ( fr) ?do i equ bin# find_start_of_cluster calculate_ici find_end_of_cluster spikes_in_cluster ( print) if bin# equ end_bin# end_bin# start_bin# - equ cluster_duration ( valid_cluster \\ this turns out to be unnecessary.) ( if) ( print + in front of significant increase in unit activity ...) calculate_Hz ( n1) unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase ( n2) ( n1 n2) unit_Hz_criterion * u> ( identify significant unit activity) if " +" count strcat then ( print - in front of significant decrease in unit activity ...) calculate_Hz ( n1) unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase ( n2) ( n1 n2) unit_Hz_criterion / swap u> ( identify significant unit activity) if " -" count strcat then ( put frequency into distribution ...) calculate_Hz ( n) unit# case 1 of unit1_pointer endof 2 of unit2_pointer endof 3 of unit3_pointer endof 4 of unit4_pointer endof endcase ( ptr) start_bin# 2* + ( adr) ! ( choose ONE of the following ...) information case 1 of ici ( n) endof ( time of interval between clusters; i.e., inter-cluster-interval) 2 of cluster_duration ( n) endof ( time of unit activity; i.e., duration of cluster) 3 of spikes_in_cluster ( n) endof ( number of spikes to calc frequency) 4 of ici cluster_duration + ( n) endof ( total time to calc frequency) 5 of start_bin# ( n) endof ( latency of cluster from start of trial) 6 of start_bin# ( n) trl# 1- trialtypetable 1+ + c@ case ascii 1 of toneon endof ascii 2 of toneon endof ascii 3 of shkon endof ( default) toneon endcase - ( n') endof ( latency from tone or shkon) 7 of calculate_Hz endof ( Hz) 8 of noop endof ( special) 9 of noop endof ( test) noop ( default) endcase ( n) mm>string strcat ( if line length is too long, then print out now and start new line ...) dup items u> if ( dc x y ds0 adr n) TextOut drop device_cr " " string1 strcpy localdc dup GetCurrentPosition ds0 string1 count ( dc x' y' ds0 adr' n') then ( \\\\ 0 equ carryover \ is this needed? here?) ( else) ( true equ valid_cluster) ( then) then ( update loop ...) bin# i +loop then ; : measure_units ( --) ( calculations for each a/d channel) empty_unit_distribution set_unit_pointers #units ( to) 0 ( fr) ?do i 1+ equ unit# get_unit_data bad_PCS_spikes? legendfont lightred coloring device_cr localdc dup GetCurrentPosition ds0 ( dc x y ds0) trial/-block case 0 of ( trial) " unit # " string1 strcpy string1 count unit# mm>string strcat information 7 = if ( print baseline frequency for each unit ...) " (" count strcat unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase mm>string strcat " Hz) " count strcat then " ... " count strcat bad_trial? if " bad units " count strcat then endof 1 of ( block) " block average " string1 strcpy ( this may not seem efficient but it is necessary) string1 count ( for printing whole line to printer.) endof 2 of ( unit frequencies) ( if measure not done in dave.4th, this is never done for source=frequencies.) " unit # " string1 strcpy string1 count unit# mm>string strcat information 7 = if ( print baseline frequency for each unit ...) " (" count strcat unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase mm>string strcat " Hz) " count strcat then " ... " count strcat endof endcase ( dc x y ds0 adr n) find_CS_clusters ( get results) ( dc x y ds0 adr n') TextOut drop ( print whole line) loop ; : measure_one_unit ( --) ( calculations for one unit channel. Must set unit#.) empty_unit_distribution set_unit_pointers ( 2 equ unit# \\ debugging) get_unit_data bad_PCS_spikes? 0 equ start_bin# 0 equ end_bin# 0 equ spikes_in_cluster 0 equ carryover false equ valid_cluster bad_trial? not if 0 equ start_range pts equ end_range ( parameters needed for passing to cluster words) end_range ( to) start_range ( fr) ?do i equ bin# find_start_of_cluster calculate_ici find_end_of_cluster spikes_in_cluster ( print) if bin# equ end_bin# end_bin# start_bin# - equ cluster_duration ( put frequency into distribution ...) calculate_Hz ( n) unit# case 1 of unit1_pointer endof 2 of unit2_pointer endof 3 of unit3_pointer endof 4 of unit4_pointer endof endcase ( ptr) start_bin# 2* + ( adr) ! then ( update loop ...) bin# i +loop then noop ; : measure ( --) measure_a/ds measure_units ; ( the following used to be in the file draw.run ) : hollowed_rectangle ( dc x1 y1 x2 y2 -- dummy) ( draw hollow rectangle.) equ y2 equ x2 equ y1 equ x1 ( dc) drop y1 y2 <> if ( only draw hollow if data exists \\ prevents score line over CS & UCS marks) localdc x1 y1 Moveto 2drop localdc x2 y1 LineTo drop localdc x2 y2 LineTo drop localdc x1 y2 LineTo drop localdc x1 y1 LineTo drop then 0 ( dummy) ; : filled_rectangle ( dc x1 y1 x2 y2 -- dummy) ( draws filled rectangle.) equ y2 equ x2 equ y1 equ x1 ( dc) drop localdc x1 y1 Moveto 2drop x2 x1 ?do localdc i y1 Moveto 2drop localdc i y2 LineTo drop loop 0 ( dummy) ; : draw_a/ds ( --) ( for each a/d channel ...) #a/d ( to) 0 ( fr) ?do ( index is a/d channel number 0 - #a/d) i 1+ equ a/d# ( useful for parameter passing) get_a/d_data blue coloring ( select coordinate origin ... ) localdc 0 ( x) offset ( y) SetViewportOrg 2drop ( draw a/d channel ...) pts ( to) 0 ( fr) ?do ( index is data bin number, used to get into array) i 0= ( true if first data point) if localdc 0 ( x) array i + c@ ( y) j 0 = if a/d1x a/d1/ */ then ( magnification of a/d1 ...) j 1 = if a/d2x a/d2/ */ then j 2 = if a/d3x a/d3/ */ then j 3 = if a/d4x a/d4/ */ then 1+ ( magical offset; otherwise no plot if y is equal to zero) MoveTo 2drop else ( false for all other data points) localdc i xscalex * ( x2) array i + c@ ( y2) j 0 = if a/d1x a/d1/ */ then ( magnification of a/d1 ...) j 1 = if a/d2x a/d2/ */ then j 2 = if a/d3x a/d3/ */ then j 3 = if a/d4x a/d4/ */ then 1+ ( magical offset; otherwise no plot if y is equal to zero) LineTo drop then loop ( NOTE: LineTo seems to automatically advance x,y whereas Rectangle does not seem to.) ( print data legend ...) legendfont lightred coloring localdc dup GetCurrentPosition ds0 " a/d # " count i 1+ s>d <# #s #> strcat TextOut drop ( select offset for next picture ...) 0 ( dummy) pts 0 ?do array i + c@ max loop ( maximum_value | dummy) i 0 = if a/d1x a/d1/ */ then i 1 = if a/d2x a/d2/ */ then i 2 = if a/d3x a/d3/ */ then i 3 = if a/d4x a/d4/ */ then ( scaled_value) 20 max ( at least this much space) offset + equ offset loop ; true equ style : filled ( --) true equ style ; : hollowed ( --) false equ style ; : draw_units ( --) ( additional space required between a/d and units ...) offset 20 + equ offset ( for each unit channel ...) #units 0 ?do i 1+ equ unit# get_unit_data blue coloring ( select coordinate origin ...) ( select offset for next picture ...) 10 ( dummy) ( give at least this amount of space if no units) pts 0 ?do array i + c@ max loop ( maximum_value | dummy) i 0 = if unit1x unit1/ */ then i 1 = if unit2x unit2/ */ then i 2 = if unit3x unit3/ */ then i 3 = if unit4x unit4/ */ then ( scaled_value) 10 + ( at least this much space between unit pictures) offset + equ offset localdc 0 ( x) offset ( y) SetViewportOrg 2drop ( draw unit channels ...) pts 0 ?do i equ bin# localdc i xscalex * ( x1) 0 ( y1) i 1+ xscalex * ( x2) array i + c@ ( y2) j 0 = if unit1x unit1/ */ then ( magnification of unit1 ...) j 1 = if unit2x unit2/ */ then j 2 = if unit3x unit3/ */ then j 3 = if unit4x unit4/ */ then negate ( with setviewportorg above, negate plots units up rather than down) ( dc x1 y1 x2 y2) ( NOTE: y2 is the value to plot.) ( determine hollow/filled ...) dup 0= if hollowed then ( reset to hollowed if no units) unit# ( check latency in unit_distribution ...) case 1 of unit1_pointer bin# 2* + endof 2 of unit2_pointer bin# 2* + endof 3 of unit3_pointer bin# 2* + endof 4 of unit4_pointer bin# 2* + endof endcase ( adr) @ ( n1) unit# ( ... get criterion ...) case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase unit_Hz_criterion * ( n2) ( n1 n2) u> ( make comparison) trial/-block 1 = or ( always fill if block display) if ( beginning of cluster, meets criterion ...) filled else ( could be within criterial cluster ...) style ( if units in same filled cluster then keep filled) if filled else ( if units in unfilled cluster then keep unfilled) hollowed then then ( execute drawing ...) style if ( dc x1 y1 x2 y2) filled_rectangle ( flag) drop else ( dc x1 y1 x2 y2) hollowed_rectangle ( flag) drop then noop loop ( draw underline and stimulus marks ...) trl# 1- trialtypetable 1+ + c@ case ascii 1 ( tone alone marks) of localdc 0 ( x1) 2 ( y1) toneon xscalex * ( x2) 0 ( y2) filled_rectangle drop ( draw underline) localdc toneon 1+ xscalex * ( x1) 2 ( y1) pts xscalex * ( x2) 0 ( y2) filled_rectangle drop endof ascii 2 ( paired tone and air marks) of localdc 0 ( x1) 2 ( y1) toneon xscalex * ( x2) 0 ( y2) filled_rectangle drop ( draw underline) localdc toneon 1+ xscalex * ( x1) 2 ( y1) shkon xscalex * ( x2) 0 ( y2) filled_rectangle drop localdc shkon 1+ xscalex * ( x1) 2 ( y1) pts xscalex * ( x2) 0 ( y2) filled_rectangle drop endof ascii 3 ( air alone marks) of localdc 0 ( x1) 2 ( y1) shkon xscalex * ( x2) 0 ( y2) filled_rectangle drop ( draw underline) localdc shkon 1+ xscalex * ( x1) 2 ( y1) pts xscalex * ( x2) 0 ( y2) filled_rectangle drop endof endcase ( move to right of plot and print info ...) localdc pts xscalex * ( x) 0 ( y) MoveTo 2drop ( NOTE: Rectangle must not advance x,y automatically like LineTo seems to.) legendfont lightred coloring localdc dup GetCurrentPosition ds0 " unit # " count i 1+ s>d <# #s #> strcat TextOut drop loop ; 0 equ mark : timing_marks ( --) ( marks for time from trial onset ...) ( additional space for coordinate ...) offset printing if 100 else 20 then + equ offset localdc 0 ( x) offset ( y) SetViewportOrg 2drop black pen pts ( to) 0 ( fr) ?do i 0= if localdc 0 0 Moveto 2drop else localdc i xscalex * 0 LineTo drop localdc i xscalex * mark negate LineTo drop localdc i xscalex * mark 2* LineTo drop localdc i xscalex * 0 Moveto 2drop then 100 bin / ( approximately every 100 msec) +loop localdc pts xscalex * 0 Lineto drop ( timing legend ...) legendfont lightred coloring localdc dup GetCurrentPosition ds0 " " string1 strcpy string1 count 100 bin / bin * mm>string strcat " msec ticks" count strcat TextOut drop ( update coordinates ...) offset 20 + equ offset ; : cs_marks ( --) ( CS marks ...) ( additional space for coordinate ...) offset printing if 40 else 20 then + equ offset localdc 0 ( x) offset ( y) SetViewportOrg 2drop black pen localdc 0 0 Moveto 2drop localdc toneon xscalex * 0 LineTo drop localdc toneon xscalex * mark negate LineTo drop localdc toneoff xscalex * mark negate LineTo drop localdc toneoff xscalex * 0 LineTo drop localdc pts xscalex * 0 LineTo drop ( CS legend ...) legendfont lightred coloring localdc dup GetCurrentPosition ds0 " CS " count TextOut drop ( update coordinates ...) offset 20 + equ offset ; : ucs_marks ( --) ( UCS marks ...) ( additional space for coordinate ...) offset printing if 40 else 20 then + equ offset localdc 0 ( x) offset ( y) SetViewportOrg 2drop black pen localdc 0 0 Moveto 2drop localdc shkon xscalex * 0 LineTo drop localdc shkon xscalex * mark negate LineTo drop localdc shkoff xscalex * mark negate LineTo drop localdc shkoff xscalex * 0 LineTo drop localdc pts xscalex * 0 LineTo drop ( UCS legend ...) legendfont lightred coloring localdc dup GetCurrentPosition ds0 " UCS" count TextOut drop ( update coordinates ...) offset 20 + equ offset ; : draw_cursors ( --) ( the following draws the cursor marks ...) printing if 15 else 5 then equ mark timing_marks trl# 1- trialtypetable 1+ + c@ case ascii 1 of cs_marks endof ascii 2 of cs_marks ucs_marks endof ascii 3 of ucs_marks endof endcase ; ( the following used to be in the file draw2.run ) ( display frequency x latency unit data) 0 equ tempx 0 equ tempy 0 equ actual_y 3 equ radius : symbol ( --) ( draw up-down line ...) ( localdc tempx tempy Lineto drop) ( localdc tempx tempy 6 + Lineto drop) ( localdc tempx tempy 6 - Lineto drop) localdc ( dc) tempx radius printing if 2 * then - ( x1) tempy radius printing if 2 * then - ( y1) tempx radius printing if 2 * then + ( x2) tempy radius printing if 2 * then + ( y2) ( dc x1 y1 x2 y2) ( significant? ...) actual_y ( n1) unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase unit_Hz_criterion * ( n2) ( dc x1 y1 x2 y2 n1 n2) u> if ( draw hollow/filled with coloring ...) lightred coloring filled_rectangle drop else blue coloring hollowed_rectangle drop then localdc tempx tempy MoveTo 2drop blue coloring noop ; false equ moved? : get_unit_pointer ( -- adr) unit# case 1 of unit1_pointer endof 2 of unit2_pointer endof 3 of unit3_pointer endof 4 of unit4_pointer endof endcase ( adr) noop ; : (draw_Hz) ( --) ( draw one channel; set unit# before calling this routine.) false equ moved? pts ( to) 0 ( fr) ?do get_unit_pointer ( adr) i 2* + @ 0<> if ( found data point ...) localdc ( dc) i xscalex * ( x) get_unit_pointer i 2* + @ dup equ actual_y negate ( y) ( dc x y) hz1x * hz1/ / ( scaled y) printing if 3 * then ( scaled for printing) 2dup equ tempy equ tempx moved? if ( all subsequent data points) ( dc x y) LineTo drop symbol else ( first data point) ( dc x y) MoveTo 2drop symbol true equ moved? then then loop noop ; : histograms ( --) 0 equ mode ; ( select histogram display for trial unit data.) : histogram ( --) histograms ; ( alias) : frequencies ( --) 1 equ mode ; ( select frequency display for trial unit data.) : frequency ( --) frequencies ; ( alias) : draw_Hz ( --) ( draws frequencies for current trial for all units.) offset 100 + equ offset #units ( to) 0 ( fr) ?do ( index is unit number 0 - #units) i 1+ equ unit# ( useful for parameter passing) blue coloring localdc ( dc) 0 ( x) offset ( y) printing if 4 * then SetViewportOrg 2drop (draw_Hz) offset 50 + equ offset loop noop ; : unit1 ( --) 1 equ unit# ( _for_display) ; : unit2 ( --) 2 equ unit# ( _for_display) ; : unit3 ( --) 3 equ unit# ( _for_display) ; : unit4 ( --) 4 equ unit# ( _for_display) ; : multiple_Hz ( --) ( draws range of frequencies { start end} for selected unit { unit1 unit2 unit3 unit4} ) offset 200 + equ offset trl# equ _trl# end 1+ start u> if ( make sure do-loop limits are correct ...) end 1+ ( to) start ( fr) ?do i equ trl# trl# 1- trialtypetable 1+ + c@ tones = trl# 1- trialtypetable 1+ + c@ pairs = or trl# 1- trialtypetable 1+ + c@ airs = or if ( trial type matches request, therefore include this trial in display ...) localdc ( dc) 0 ( x) offset ( y) printing if 4 * then SetViewportOrg 2drop get_unit_data measure_one_unit (draw_Hz) offset stagger + equ offset then loop else localdc dup GetCurrentPosition ds0 " Error! Check order and values of start and end trials " count ( dc x' y' ds0 adr' n') TextOut drop then _trl# equ trl# noop ; ( the following used to be in the file graphics.run ) : zero ( --) ram2 2048 0 fill 0 equ counter ; : (add) ( --) counter 1+ equ counter 1024 ( to) 0 ( fr) ?do ram2 i 2* + @ ( current value) ram1 i + c@ + ( add) ram2 i 2* + ! ( to) loop ; : add ( --) ( use n1 n2 through to set end, start.) trl# equ _trl# end 1+ start ?do i equ trl# trl# 1- trialtypetable 1+ + c@ tones = trl# 1- trialtypetable 1+ + c@ pairs = or trl# 1- trialtypetable 1+ + c@ airs = or if ( trial type matches request, therefore include this trial in display ...) get_a/d_data (add) then loop _trl# equ trl# get_a/d_data ; : (subtract) ( --) counter 1- equ counter 1024 ( to) 0 ( fr) ?do ram2 i 2* + @ ( current value) ram1 i + c@ - ( minus) ram2 i 2* + ! ( to) loop ; : subtract ( --) ( use n1 n2 through to set end, start.) trl# equ _trl# end 1+ start ?do i equ trl# trl# 1- trialtypetable 1+ + c@ tones = trl# 1- trialtypetable 1+ + c@ pairs = or trl# 1- trialtypetable 1+ + c@ airs = or if ( trial type matches request, therefore include this trial in display ...) get_a/d_data (subtract) then loop _trl# equ trl# get_a/d_data ; : average ( --) pts #a/d * ( to) 0 ( fr) ( average the a/d data) ?do ram2 i 2* + @ counter / ( mean) ram2 i + c! ( to) loop 0 equ counter 1024 ( to) pts #a/d * ( fr) ( the remaining space is cumulative unit data) ?do ram2 i 2* + @ ( cumulative) ram2 i + c! ( to) loop noop ; ( *** this is not loaded >>> include go.run ...) ( analyzes PCS activity for Claire) ( i.e., go<return> prints out total PCS units for each trial and for every unit) ( this gives an idea of PCS unit activity.) : process ( --) localdc logpixelsx GetDeviceCaps equ xpixels/inch localdc logpixelsy GetDeviceCaps equ ypixels/inch localdc mm_text ( mm_loenglish) SetMapMode drop 20 equ offset ( set y position of plot) .trial# .info .cmds trial/-block case 0 of ( trial) measure printing if draw_cursors then draw_a/ds mode 0= ( selected by histogram|histograms {default} versus frequency|frequencies) if draw_units else draw_Hz then draw_cursors endof 1 of ( block) measure printing if draw_cursors then draw_a/ds draw_units draw_cursors endof 2 of ( unit frequency) ( measure) multiple_Hz draw_cursors endof endcase localdc mm_text SetMapMode drop ; ( printer support) 0 EQU PDC ( DC for printing) 0 EQU CHARY ( character height, printer font) 0 EQU CHARX ( average character width, printer font) 0 EQU PAGEY ( total page height) 0 EQU PAGEX ( total page width) 0 EQU HORZMARG ( width of each side margin) 0 EQU VERTMARG ( height of top & bottom margins) CREATE DOCINFO 10 , 0 , 0 , 0 , 0 , ( Data structure used by various Windows 3.1 printing APIs) ( --- ; process File-Print command) : DOPRINT PRINTDLG ( show print dialog to user) IF true equ printing 2DROP ( discard flags ) EQU PDC ( save printer DC) 3DROP ( discard page numbers etc. ) " Print Test" ASCIIZ DOCINFO 2+ ! DS0 DOCINFO 4 + ! ( print job name into DOCINFO structure ) PDC DS0 DOCINFO StartDoc DROP ( start print job, start first page) PDC StartPage DROP ( make drawing ...) pdc equ localdc xscalex a/d1x a/d2x a/d3x a/d4x unit1x unit2x unit3x unit4x ( save values) xscalex 3 * equ xscalex a/d1x 5 * equ a/d1x a/d2x 5 * equ a/d2x a/d3x 5 * equ a/d3x a/d4x 5 * equ a/d4x unit1x 5 * equ unit1x unit2x 5 * equ unit2x unit3x 5 * equ unit3x unit4x 5 * equ unit4x process equ unit4x equ unit3x equ unit2x equ unit1x equ a/d4x equ a/d3x equ a/d2x equ a/d1x equ xscalex ( restore values) PDC EndPage DROP ( clean up everything) PDC EndDoc DROP ( end print job) PDC DeleteDC ( discard printer DC) false equ printing THEN ; : ERRORBOX ( ^str --) ( display error message and OK button in message box) " Error Condition" [ MB_ICONHAND MB_OK OR ] LITERAL MSGBOX DROP ; : WNDPROC ( -- dn) ( message handler for the frame window ) wMsg CASE WM_PAINT ( returns hDC, psRect, lpPS) OF ( --; process WM_PAINT message for frame window) hDC equ localdc process ENDOF WM_SIZE OF ( change in window size, force complete repaint) MAINWIN WREPAINT ENDOF WM_COMMAND OF ( --; This routine handles WM_COMMAND messages from the frame window's menu.) wParam CASE IDM_FILEPRINT OF DOPRINT ENDOF IDM_FILEEXIT OF ( send message to frame window) WM_CLOSE ( msg --) MAINWIN WCB>HWND SWAP 0 0. SendMessage 2DROP ENDOF idm_openfile of selectfile endof idm_start of trl# 1 <> if 1 equ trl# mainwin wrepaint then endof idm_block- of trl# #t/blk - 0> if #t/blk negate trl# 1+ + equ trl# mainwin wrepaint then endof idm_trial- of trl# 1 <> if trl# 1- equ trl# mainwin wrepaint then endof idm_stop of ( currently has no function; mainwin wrepaint) endof idm_trial+ of trl# #trls <> if trl# 1+ equ trl# mainwin wrepaint then endof idm_block+ of trl# #t/blk + #trls 1+ u< if trl# #t/blk + equ trl# mainwin wrepaint then endof idm_end of #trls trl# <> if #trls equ trl# mainwin wrepaint then endof idm_jump of trl# ( n) ( used to check to see if trial number has actually changed) jumpdlg ['] jumpprocedure rundlg if jump# @ dup #trls u<= over 1 swap u<= and ( make sure 1 <= jump# @ <= #trls) if ( n) equ trl# else drop then then ( n) trl# <> if mainwin wrepaint then ( repaint if trial # has changed) endof idm_interpretter of interpretterdlg ['] interpretterprocedure rundlg if interpretterbuffer eval mainwin wrepaint then endof idm_source of trial/-block case ( rotate through selection of sources ...) 0 of 1 equ trial/-block endof 1 of 2 equ trial/-block endof 2 of 0 equ trial/-block endof endcase mainwin wrepaint endof ( idm_average) ( of ) ( averagedlg ['] averageprocedure rundlg) ( if ) ( noop) ( then) ( mainwin wrepaint ) ( endof) idm_info of info 0= equ info ( clever way to toggle switch) mainwin wrepaint endof idm_cmds of cmds 0= equ cmds ( clever way to toggle switch) mainwin wrepaint endof " Command not implemented" ERRORBOX ENDCASE ENDOF ( menu command message) WM_DESTROY OF ( kill message loop) 0 PostQuitMessage ENDOF DEFMSGHANDLER EXIT ( set by setmsghandler, the default case passes message to DefWindowProc( ) ENDCASE 0 0 ; ( double value to return from this message handler back to window loop ) : review ( --) ( "main word" creates the frame window and then enters message loop) ( bob \\ select runtime/summary parameters: bob, xty, ben ) #trls 0= pts 0= if " Select parameters first " count type abort then selectfile ( open data file ) cr " Please wait while analyzing baseline units. " count type cr quietly_analyze_PCS_units " End baseline unit analysis. " count type cr 1 equ trl# ( figure out preliminaries for unit data ...) empty_unit_distribution set_unit_pointers ['] WNDPROC MAINWIN SETMSGHANDLER ( install msg handler, returns hWnd, wMsg, wParam, lParam, pWCB) ( getmsghandler ) " Data Review Program" MAINWIN WSETNAME ( set frame window caption) ( wsetpos) ( wsetsize) ( wsetstyle) " APPICON" MAINWIN WLOADICON DROP ( wloadmenu | wsetmenu; set icon) ( wsetparent) MAINWIN WCREATE 0= ( create main window) IF " Can't create frame window!" ERRORBOX 0 RETURN THEN 100 100 mainwin wsetpos pts pts 5 / + xscalex * ( x) 650 ( y) mainwin wsetsize ( whide) ( wminimize | wmaximize) ( wrestore ) APPMENU MAINWIN WSETMENU FALSE = ( set frame window menu) IF " Can't create menu!" ERRORBOX 0 RETURN THEN MAINWIN WSHOW ( display frame window) ( winsmgloop | the following ...) ( begin ... processwinmsg | processrawmsg | peekwinmsg | peekrawmsg ... until) WINMSGLOOP ( wait for WM_QUIT message) MAINWIN WCLOSE flush QUIT ( 0 RETURN ) ; CR CR .( To run the review program, enter parameters then type: review <Enter> ) CR ( the end ) Cluster analysis source code: cluster.txt This second cluster-related file (cluster.txt) is used to give a print out, on a trial-by-trial basis, of the information about each cluster found in every trial. Cluster analysis is actually implemented in the review program (dave.txt). This information can be useful in deciding whether unit activity is significantly related to behavior. This information is also overwhelming, however, and you are going to find more clusters than you know what to do with. The program identifies significant clusters compared with baseline, however it itself does not determine whether that activity is or is not significantly related to behavior. The problem with cluster analysis is how to cross this last step. One way to continue the analysis would be to correlate the first, second, third, etc. cluster after CS onset (or before US onset) with the onset of the behavioral response versus with the onset of the CS or US (i.e., is it behavior-related or stimulus-related?). When unit activity is found to be consistent (i.e., to have a high correlation with behavior or a stimulus event) then it becomes interesting to know about the latencies and strength of the unit response. ( cluster.txt ) ( copied from cluster.bak) ( this program is designed to give a printout of unit clusters for every trial.) ( a cluster is defined as the bins that make up a period of continuous unit activity.) ( the latency of the cluster is the first bin where unit activity begins.) ( to calculate the frequency, the total amount of unit activity that makes up the cluster is divided by the time { the time occupied by a cluster plus the time before the cluster when no unit activity happened } and scaled for 1 second to report it in Hz.) ( commands are indicated at the end of this file and are printed out when the program is compiled.) ( significant clusters are indicated by +/- signs with the hz_info option, where a comparison of each cluster is made against the average frequency of baseline preCS activity for the BLOCK or SESSION multiplied by a criterion factor.) ( BLOCK is chosen with by_block; SESSION is chosen with by_session.) ( cluster.txt, therefore, is suited to analyzing data where manipulations are made on a blockby-block or session basis.) ( the frequency in the baseline preCS activity is calculated on the basis of the number of units that make up a cluster and the time occupied by the cluster and the preceeding period -that is, the very first cluster is NOT counted in the calculation { because the preceding period is indeterminate } and therefore at least two clusters must be identified in the block before the preCS frequency can be calculated.) ( this is a more conservative and more accurate measure of the preCS frequency than is used by the review program.) ( note that baseline frequencies and significances are calculated differently between cluster.txt and the review program.) ( in the review program, each cluster is compared with the average frequency of baseline preCS activity {total activity, not clusters} for the SESSION multiplied by a criterion factor.) ( in the review program, preCS activity is simply calculated by counting all unit activity in the preCS periods.) ( this calculation includes, therefore, the quiet periods before the first cluster appears in the day, and the quiet period after the last cluster has been found.) create marker 0 equ total_PCS_spikes_in_block 0 equ total_PCS_spikes_in_session 0 equ ici false equ CS? false equ UCS? ( variables for figuring out PCS Hz ...) 0 equ end_of_first_cluster_in_block 0 equ end_of_last_cluster_in_block \ 0 equ trial_of_first_cluster_in_block ( debugging) \ 0 equ trial_of_last_cluster_in_block ( debugging) 0 equ pcs_time 0 equ #clusters 0 equ #spikes 0 equ pcs_hz ( temporary storage for block and session pcs frequency calculations) : is_this_a_good_trial? ( --) ( count total number of spikes in PCS period ...) dummy toneon ( to) 0 ( fr) ?do array i + c@ + loop ( count) ( determine if too many PCS spikes ...) bad_units over ( bad_units count) u<= if ( bad trial ...) true equ bad_trial? " bad units " count type else ( good trial; update counters ...) false equ bad_trial? total_PCS_spikes_in_block over + equ total_PCS_spikes_in_block ( equivalent to +!) total_PCS_spikes_in_session over + equ total_PCS_spikes_in_session ( ~ +!) total_good_trials 1+ equ total_good_trials ( ~ to +!) then ( count) drop ; 0 equ items : check_items ( n--n) ( needed for HP laserjet printout ...) dup 100 / 0<> if ( true if >= to 100) items 3 + equ items else dup 10 / 0<> ( true if >= to 10 AND ALSO less than 100) if items 2 + equ items else items 1 + equ items then then items 82 u> printing and if 0 equ items cr 10 spaces then ; 0 equ session : by_session true equ session ; ( true = compare cluster frequency with session frequency) : by_block false equ session ; ( false = compare cluster frequency with block frequency) by_block ( default) : hertz ( -- hz) ( select session or block hz for comparison with cluster's hz) session case true of ( session analysis hz) unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase endof false of ( block analysis hz) pcs_hz endof endcase 100 / ( necessary scaling to compare with hz calculated for each cluster) noop ; 0 equ PCS_clusters_this_trial : find_and_print_clusters ( --) ( for every trial ...) ( initialize variables ...) false equ CS? false equ UCS? 0 equ items 0 equ PCS_clusters_this_trial 0 equ ici 0 equ start_range pts equ end_range ( parameters needed for passing to cluster words) ( identify clusters ...) end_range ( to) start_range ( fr) ?do ( where does cluster begin? ...) i equ bin# ( bin# used for parameter passing) find_start_of_cluster ( set start_bin# if cluster has been found ...) array bin# + c@ 0<> if bin# equ start_bin# then ( calculate ici if previous cluster has been found ...) ici 0= if ( no, previous cluster was not found) bin# equ ici else ( yes, previous cluster was found; calculate ici) bin# end_bin# - equ ici then ( where does cluster end? ...) find_end_of_cluster ( is there a valid cluster? ...) start_bin# pts <> if ( yes, valid cluster; otherwise, no action) CS? not toneon start_bin# u<= and ( yes = cluster found in CS period) if true equ CS? ascii / emit space then UCS? not shkon start_bin# u<= and ( yes = cluster found in UCS period) if true equ UCS? ascii / emit ascii / emit space then CS? not ici 0<> ( only count valid ici) and ( yes =PCS cluster) ( this test must come after above tests for CS and UCS) if PCS_clusters_this_trial 1+ equ PCS_clusters_this_trial ( needed to calc PCS Hz) then spikes_in_cluster 0<> if ( needed to calculate frequency ...) bin# equ end_bin# end_bin# start_bin# - equ cluster_duration ( choose display type ...) information case 1 of ( ici) ici 0<> if ici check_items u. then endof 2 of ( duration) cluster_duration check_items u. endof 3 of ( spikes) spikes_in_cluster check_items u. endof 4 of ( time) start_bin# bin * check_items u. endof 5 of ( bin) start_bin# check_items u. endof 6 of ( latency) start_bin# ( n) CS? if ( yes, passed into CS period) toneon else ( no, still in PCS period) ascii - emit items 1 + equ items toneon swap then ( n|n') bin * check_items u. endof 7 of ( frequency) calculate_Hz dup hertz unit_Hz_criterion * u> if ascii + emit items 1+ equ items then dup hertz unit_Hz_criterion / swap u> if ascii - emit items 1+ equ items then check_items u. endof 8 of ( special) ( latency) start_bin# ( n) CS? if ( yes, passed into CS period) toneon else ( no, still in PCS period) ascii - emit items 1 + equ items toneon swap then ( n|n') bin * check_items ( n|n') s>d <# #s #> type ( separator) ascii , emit ( frequency) calculate_Hz dup hertz unit_Hz_criterion * u> if ascii + emit items 1+ equ items then dup hertz unit_Hz_criterion / swap u> if ascii - emit items 1+ equ items then check_items u. endof 9 of ( test) noop endof noop ( default) endcase then then bin# i - ( update loop counter) +loop ; : freq ( time count -- pcs_hz) ( calculate hz) 10 * 10000 um* rot bin * ( denominator) dup >r um/mod ( remainder quotient) swap 2* r> ( quotient remainder*2 denominator) / + ; : .hz ( pcs_hz --) ( print hz) s>d <# # # ascii . hold #s #> type " Hz " count type ; : print_block ( --) cr trl# #t/blk mod 0= ( every block) if " Block number " count type trl# #t/blk / u. \ " total PCS spikes = " count type total_PCS_spikes_in_block u. \ 0 equ total_PCS_spikes_in_block \ cr \ " first cluster = " count type end_of_first_cluster_in_block u. \ \ \ \ \ \ \ \ \ \ \ " , trial = " count type trial_of_first_cluster_in_block u. cr " last cluster = " count type end_of_last_cluster_in_block u. " , trial = " count type trial_of_last_cluster_in_block u. cr " # pcs clusters = " count type #clusters u. ( NOTE: wrong count) cr " # pcs spikes = " count type #spikes u. cr " pcs time = " count type pcs_time u. cr 2 spaces ( compare block hz with session hz ...) " Block pcs Hz = " count type ( calculate block hz ...) pcs_time #spikes ( difference count) freq ( blockhz) ( select session hz ...) unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase ( blockhz sessionhz) ( print +/- if block is significantly different from session ...) 2dup unit_Hz_criterion * u> if ascii + emit then unit_Hz_criterion / swap u> if ascii - emit then ( print block hz ...) pcs_time #spikes ( difference count) freq .hz ( calculate & print hz) cr cr then ; : PCS_Hz_in_this_trial ( --) 2 PCS_clusters_this_trial u<= ( must have at least 2 clusters to calculate hz) if ( yes, at least one cluster in preCS period) 18 check_items drop ( make sure enough room at end of line or force next line) " (PCS = " count type ( find start of first cluster ...) toneon ( to) 0 ( fr) ?do array i + c@ 0<> if i leave then loop ( i) ( find end of first cluster ...) ( i) toneon swap ?do array i + c@ 0= if i ( i1) leave then loop ( i1) ( = beginning of valid counting period) ( find end of the last cluster ...) 0 ( to) toneon 1- ( correction for backwards loop) ( fr) ?do array i + c@ 0<> if i ( i2) leave then -1 +loop ( i2) 1+ ( correction) ( i1 i2') ( = beginning and end of valid counting period) swap 2dup - -rot ( i2'-i1=difference i2' i1) ( count units in valid counting period ...) dummy ( n) -rot ( difference dummy i2 i1) ?do array i + c@ + loop ( difference count) ( figure out PCS frequency ...) freq .hz ( calculate & print hz) ascii ) emit else ( not enough clusters to calculate PCS Hz -- need at least two clusters) " (cannot calculate PCS Hz)" count check_items type then noop ; : test_for_good_trial? ( --) ( is this a good trial? ...) dummy toneon ( to) 0 ( fr) ( count total number of spikes in PCS period ...) ?do array i + c@ + loop ( count) bad_units swap ( bad_units count) u<= ( too many PCS spikes?) if true equ bad_trial? else false equ bad_trial? then ; 0 equ analysis ( session analysis) 1 equ analysis ( block analysis) : PCS_block|session_analysis ( --) ( select for block or session analysis -- PCS_block_analysis vs. PCS_session_analysis) ( figure out PCS frequency) ( analysis is done for a block of trials or for the whole session) ( returns pcs_time, #spikes -- needed to calculate pcs frequency) ( returns pcs_hz or unit1_PCS_Hz ...) 0 equ end_of_first_cluster_in_block 0 equ end_of_last_cluster_in_block \ 0 equ trial_of_first_cluster_in_block ( debugging) \ 0 equ trial_of_last_cluster_in_block ( debugging) 0 equ pcs_time 0 equ #clusters 0 equ #spikes analysis case 0 of ( session analysis range) #trls ( to) 0 ( fr) endof 1 of ( block analysis range) trl# #t/blk + ( to) trl# ( fr) endof ( default ...) trl# #t/blk + ( to) trl# ( fr) endcase ?do ( set pointer called array based on unit# chosen ...) i equ trl# get_unit_data ( is this a good trial? ...) test_for_good_trial? bad_trial? not if ( yes, good trial) ( add in time for this trial ...) pcs_time toneon + equ pcs_time ( initialize ...) 0 equ start_range toneon equ end_range 0 equ bin# \ \ end_range start_range ?do ( find start of cluster or end of pcs period ...) begin bin# end_range u< array bin# + c@ 0= and while bin# 1+ equ bin# repeat ( if cluster is found then update cluster counter and find end of cluster ...) array bin# + c@ 0<> if ( update cluster counter ...) end_of_first_cluster_in_block 0<> if #clusters 1+ equ #clusters then ( NOTE: wrong count) ( find end of cluster or end of pcs period ...) begin bin# end_range u< array bin# + c@ 0<> and while ( do not count first cluster ...) end_of_first_cluster_in_block 0<> if #spikes array bin# + c@ + equ #spikes then ( update bin# counter ...) bin# 1+ equ bin# repeat ( determine if this is the first or the latest cluster found ...) end_of_first_cluster_in_block 0= if bin# equ end_of_first_cluster_in_block trl# equ trial_of_first_cluster_in_block ( debugging) else bin# equ end_of_last_cluster_in_block trl# equ trial_of_last_cluster_in_block ( debugging) then then bin# i - ( adjust loop counter) +loop then loop 2 #clusters u<= if ( yes, more than one cluster found; therefore, can correctly compute Hz) ( correct for finding first cluster ...) pcs_time end_of_first_cluster_in_block - equ pcs_time ( correct for finding last cluster ...) pcs_time toneon end_of_last_cluster_in_block - - ( <--two minus signs) equ pcs_time ( correct for total number of clusters ...) #clusters 1- equ #clusters ( NOTE: wrong count) ( calculate hz ...) pcs_time #spikes 10 * 10000 um* rot bin * ( denominator) dup >r um/mod ( remainder quotient) swap 2* r> ( quotient remainder*2 denominator) / + ( answer) analysis case 0 of ( session analysis hz) unit# case 1 of equ unit1_PCS_Hz endof 2 of equ unit2_PCS_Hz endof 3 of equ unit3_PCS_Hz endof 4 of equ unit4_PCS_Hz endof drop ( default) endcase endof 1 of ( block analysis hz) equ pcs_hz endof ( default ...) drop endcase then noop ; : PCS_session_analysis ( --) 0 equ analysis PCS_block|session_analysis ; : PCS_block_analysis ( --) 1 equ analysis PCS_block|session_analysis ; : cluster ( --) ( working_definition ) ( unit# must be set by user) ( cluster used to be called xxx when I was debugging the program) printing if printer +condensed then selectfile PCS_session_analysis ( header ...) " Unit analysis for file = " count type filename makelc count type cr " Data information type is" count type ( information u. ) information case 1 of " intracluster interval in bins (ici_info) " count type endof 2 of " duration in bins (duration_info) " count type endof 3 of " spikes as counts (spike_info) " count type endof 4 of " time in msec (time_info) " count type endof 5 of " raw bin# (bin_info = raw_info = start_info) " count type endof 6 of " latency in msec (latency_info)" count type endof 7 of " frequency in Hertz (hz_info = frequency_info = freq_info)" count type endof 8 of " latency (msec),frequency (Hz) ( special_info)" count type endof 9 of " test ( test_info)" count type endof " information chosen is out of range" count type abort ( default) endcase cr " Unit criterion = " count type unit_Hz_criterion u. " times" count type session case true of " session" endof false of " block" endof endcase count type " baseline." count type cr " Bad trial criterion = " count type bad_units u. " counts in baseline." count type cr " Analysis by " count type session case true of " session" count type endof false of " block" count type endof endcase cr cr " unit number " count type unit# u. cr " Trial_number# PCS / CS // UCS clusters " count type cr ( zero variables ...) 0 equ total_PCS_spikes_in_block 0 equ total_PCS_spikes_in_session 0 equ total_good_trials ( for every trial ...) #trls ( to) 0 ( fr) ?do ( analyze pcs for good trials and calculate pcs hz ...) i 1+ #t/blk mod 1 = ( first trial of the block?) if i 1+ equ trl# PCS_block_analysis then ( set data pointer ...) i 1+ equ trl# get_unit_data ( print trial type for every trial ...) trl# 1- trialtypetable 1+ + c@ case ascii 1 of ascii T emit endof ascii 2 of ascii P emit endof ascii 3 of ascii A emit endof endcase space ( analyze every trial ...) trl# s>d 4 d.r ascii # emit space ( print every trial number) is_this_a_good_trial? ( count PCS spikes and make sure it is a good trial) bad_trial? not if find_and_print_clusters then bad_trial? not if PCS_Hz_in_this_trial then ( print block information ...) print_block ( had enough? abort analysis ...) nuf? if leave then loop ( print session totals ...) cr " Total PCS spikes = " count type total_PCS_spikes_in_session u. cr " Total good trials = " count type total_good_trials u. cr " Session PCS frequency = " count type unit# case 1 of unit1_PCS_Hz endof 2 of unit2_PCS_Hz endof 3 of unit3_PCS_Hz endof 4 of unit4_PCS_Hz endof endcase .hz printing if page console then ; cr cr .( Specify unit for analysis -- e.g., unit1, unit2 ...) cr .( Specify parameters -- e.g., bob, xty, claire_tones ...) cr .( Specify computations -- e.g., special_info, hz_info, latency_info, spike_info, bin_info ...) cr .( Specify criterion level -- e.g., 3 equ unit_Hz_criterion ) cr .( Specify bad trial criterion -- e.g., 100 equ bad_units ) cr .( Specify type of analysis -- e.g., by_block or by_session) cr .( Set printer -- e.g., +printer, -printer, true equ printing, false equ printing) cr .( Start analysis with cluster<return>) cr cr .( Examples: unit2 bob hz_info 2 equ unit_Hz_criterion -printer cluster<return>) cr .( latency_info cluster<return>) cr .( unit1 +printer cluster<return> ... ) cr ( stop) ( the following words were created to compare two different ways of calculating the) ( frequency.) ( test_calc_hz is based on calculate_hz, found in dave.txt file, is used in cluster.txt to) ( calculate the frequency of individual clusters in each trial. frequency is rounded) ( and calculated to 1 Hz.) ( test_freq is based on freq, found in cluster.txt, and used in cluster.txt to calculate i. pcs) ( frequency for each trial and ii. pcs frequency for each block of trials. frequency is rounded ) ( and calculated to 0.01 Hz.) ( here test_calc_hz is scaled by multiplying it by 100 to make comparisons with test_freq.) ( a test was made using 200 10 test<return> has been tested.) ( the results show that there is surprisingly good agreement. that is, test_calc_hz -- which) ( has less precision -- seems to be a correctly rounded version of test_freq.) ( : test_calc_hz ) ( stack: time count --) ( equ spikes_in_cluster) ( equ cluster_duration) ( 0 equ ici) ( calculate_Hz ) ( 100 * ) ( .hz ;) ( : test_freq ) ( stack: time count --) ( comment: calculate & print hz) ( 10 * 10000 um* rot bin * ) ( stack: denominator) ( dup >r um/mod ) ( stack: remainder quotient) ( swap 2* r> ) ( stack: quotient remainder*2 denominator) (/+) ( .hz ;) ( : test ) ( stack: time count --) ( 2dup test_calc_hz 5 spaces test_freq cr ;) ( end)