Introduction
For our final project we made a digital vocoder, which could be accomplished over this semesterβs remote desktop environment. A vocoder is a synthesizer that generates sounds which are modulated by an input signal. It was originally designed to reduce the bandwidth of voice signals over the telephone, but was never introduced practically. It instead made its way into music production, where it produces robotic, artificial vocal sounds made popular by artists like Daft Punk. For our project, we store samples for a periodic sound (carrier signal) to be modulated by our voice input (modulation signal). The carrier signal must contain a sufficient amount of frequency content so that it can be modulated and still sound somewhat like the input. By varying the size of our stride through the saved array of samples, the carrier signal pitch can be varied. The userβs keyboard acts as an instrument, with each key press corresponding to a different stride size; simultaneous key presses are supported, which means both single notes and chords can be played and modulated by our voice.
High-level design
The idea behind the vocoder is to use the power of the frequency content in the modulation signal to adjust the corresponding frequency content power in the carrier signal. By doing this, we βimprintβ the sounds of the modulation signal onto the carrier signal. Both the ADC and DAC operate at the same frequency, since there is a 1:1 correspondence between input and output samples.
Sampling frequency
To determine what sampling frequency to use, we did some research investigating the frequency range of human speech. According to DPA Microphones (a website we looked at), speech is 95% intelligible if only the first 4 kHz in voice is preserved. This is an important metric because this means that at a sampling frequency of 8 kHz, there is enough information to be able to distinguish about 95% of speech. We found in testing that as speech intelligibility decreases, the more βblurryβ the sounds become, as if you were listening to someone talk under water or through the walls of a building. From an embedded perspective, the faster the sampling frequency, the less time we have to process each sample between DAC outputs (the deadline).
Digital filter design
We decided early on that the minimum number of filters we needed was 8, since fewer filters would not give enough resolution to the different frequencies in your voice. The tradeoff here with the number of filters here is that computation time increases linearly with the number of filters.
With 8 filters, we then needed to determine the passband of each filter since the widths of each filter does not need to be uniform. In fact, humans do not process audio on a linear scale, so we looked at the mel scale to set our frequency ranges. The mel scale is a scale of pitches that individuals perceive to be equal in distance from one another. We use the Beranek 1949 mel scale data from Stevens and Volkmann 1940 to determine frequency ranges that are perceived to be the same width, even though they are not in reality. Our frequency ranges ended up being for a sampling frequency of 8 kHz (frequencies go up to 4 kHz): [20, 160), [160, 394), [394, 670), [670, 1000), [1000, 1420), [1420, 1900), [1900, 2450), [2450, 3120).
After determining the frequency bin widths, we used Pythonβs scipy.signal.iirfilter function to generate coefficients for each of our filters. We decided to use a second-order butterworth filter in our vocoder implementation. This is because the butterworth filter has the flattest pass band, meaning that the frequencies in the passband are equally weighted. We chose a second-order filter to balance the number of samples we need to save/computations per sample with the speed of roll off. With a second order filter we have 5 coefficients, and the coefficients in the numerator demonstrate symmetry. We also only use 4 coefficients in the denominator for our computations.
In our prototyping, we found that without enough precision the filter is not stable. We found that we needed to do computations with a minimum of 5 decimal places for the filter to be stable. This prompted us to use a custom fixed point implementation, since the _Accum datatype is a s15.16 datatype, which is only about 4 decimal places of resolution. To increase our resolution as much as possible, we determined our numerical range and any remaining bits would be used as decimal places. Since the max value we needed to store in our datatype came from the output of the ADC, the number of integer bits we need is 10. Accounting for a signed bit, this leaves 21 bits of precision, or approximately 7 decimal places of resolution.
RemoteΒ Lab Setup
The remote lab setup used the remote desktop connection service built into Windows. Using the remote desktop connection, we were able to develop on the lab computer as we would have over an in-person semester. The audio input and output were connected to the ADC and DAC on the Big Board respectively, allowing us to send and receive audio signals from the PIC32 over a Zoom call. The remote desktop connection also allowed us to send keyboard presses to the lab computer.
A typical lab workflow used Zoom for audio and video, as the lab setup had video cameras pointed to the TFT on the Big Board. We would connect to the lab computer through the remote desktop and program the PIC32 using the MPLAB X IDE. To work on the code simultaneously, we used the VS Code Live Share extension.
Program/hardware design
Software
This project was written entirely in C using the MPLAB X IDE with the PIC32 peripheral library (which we will refer to as plib) and Adam Dunkelsβ protothread libraryΒ [1]β[3]. Using protothreads, we were able to design our program with a threaded approach without the significant overheads of traditional multithreading. The PIC32 plib gave us library functions and macros for the peripherals such as the ADC, DAC, timers, and timer interrupts.
For our software, we have two main components driving our system. The user interfaces with the PIC32 through a Python GUI, which sends data to the microcontroller through a serial interface. Then, the program on the microcontroller runs logic depending on the serial input from the Python program.
Python
Our python program looks as shown below. The primary function of the Python gui is to send keyboard inputs to the PIC microcontroller.
To accomplish this, we use a keyboard event listener from pynput, a library that provides keyboard management utilities. Using a key listener thread, we are able to detect keyboard presses by fetching events from the operating system. On the Python GUI, we have a dummy text input to catch keyboard presses. In the background, the Python program uses callback functions to determine the current set of pressed keyboard keys. In our case, we map several keys to the 13 notes on a piano keyboard as below. Each of our keys maps to a number which we send to the PIC32 over serial along with whether the key was pressed down or released.
For example, say we press the βaβ key. The Python program will catch a key press event for key βa,β upon which it will send the string βkey01dβ to the PIC32 representing a key press event for key 01 down. Upon release, a string βkey01uβ will be sent to the PIC32.
C program
The program on the microcontroller performed the filtering and modulation of our signals in real time. To sample our input signal, we set up the ADC to sample on a timer interrupt. This timer interrupt also triggered the filtering protothread on each new ADC read. Once our output signal was generated, we set our DAC to output the generated signal at the same frequency as our input sample. Thus, our program flow goes as follows.
Because our program flow is essentially a linear flow, we are constrained by the number of cycles between our ADC interrupts.
In our main thread, we set up our ADC, DAC, and timers as well as schedule our protothreads. The ADC is triggered using a timer, which we configure using the plib functions below. These functions enable the timer, set the timer interval and prescaler, configure the interrupt, and finally clear the interrupt flag.
OpenTimer3(T3_ON | T3_SOURCE_INT | T3_PS_1_1, CLOCK_SPD/Fs); |
Similarly, we set up another timer for profiling. This timer is configured with aΒ 0xffffΒ interval such that it overflows and no interrupt. Then, we can set the timer value before our code and read the value after to determine the number of cycles our code takes.
ADC and DAC
The ADC is set up with the following code, which configures the parameters for the format, clock, auto-sampling, buffers, and more. These are noted in the code comments.
// use ground as neg ref for A | use AN11 for input A Β Β // configure to sample AN11 EnableADC10();Β // Enable the ADC |
After setting up the ADC and DAC, we have the timer interrupt poll the ADC and set the DAC values. The filtering processing occurs in the protothread that sets a variable for the next output sample, so our interrupt thread sets the DAC value immediately after the ADC read.
adc_data = int2fix11_21(ReadADC10(0)); Β Β // read the result of conversion from the idle buffer DAC_data_A = current_amplitude; |
Filtering
For the digital filters, we implemented a functionΒ cButterΒ that computes an output signal sample by sample from an input signal and some history buffers. Because we filter multiple different signals simultaneously (as in interleaved between samples), we keep separate history buffers using pointers.
With each sample, we filter the input signal through our filter banks to find the amplitudes of each frequency band using a lowpass filter on the filtered signal. With the amplitudes of each frequency band from our input (modulator) signal, we gain the output of the frequency bands of the generated (carrier) signal to get our output signal.
fix11_21 sample = cButter(adc_read, coefficients[i], prev_x[i], prev_y[i], &(p_x_head[i]), &(p_y_head[i])); |
From this code snippet, we see that because we are using different coefficients and history buffers per filterΒ i, we need to pass in the respective coefficients and buffers for each filter. We hold the coefficients and buffers in multidimensional arrays, which we then pass the pointers to perform operations in place. While this does give a little bit of extra overhead due to branching from loops, it makes our logic much simpler as we can utilize helper functions likeΒ cButterΒ andΒ lowpass.These functions were developed with help from Bruce Landβs digital filter implementations found on his DSP page for ECE4760Β [5], [6].
For our cButter function, the history buffers hold the previous input and output values. However, in our cButter function we iterate through the buffer with each index for each previous sample in time. To reduce unnecessary assignments, we implement a circular buffer that shifts a head pointer on each new sample. Then, we index into the buffers using a modulus operation that returns the correct sample for that index.
*prev_y_head = (β(*prev_y_head) <Β 0) ? NUM_COEFFICIENTS βΒ 1: *prev_y_head; #define circ_index(i, head) ((((head) + i) % NUM_COEFFICIENTS) prev_y[*prev_y_head] = yy; |
For example above, this code snippet shows the accumulation of the denominator terms after shifting and assigning shifting the circular buffer.
A similar pointer solution was also implemented for ourΒ lowpassΒ function; but, because our lowpass filter only has a history of one sample, we only needed to use a single variable with an in place reassignment.
For the numerator terms in the digital IIR filter, we actually have symmetric terms because we use a second order Butterworth bandpass filter. Thus, we take advantage of the symmetric coefficients to reduce iteration. We see that our numerator terms are multiples of the factors (1, -2, 1). With this, we only need to multiply once after adding the previous x terms.
yy = multfix11_21(b[0], (prev_x[circ_index(0, *prev_x_head)] β (prev_x[circ_index(2, *prev_x_head)]<<1) + prev_x[circ_index(4, *prev_x_head)])); |
Fixed point
As floating point operations are costly, we needed to use fixed point arithmetic with enough precision for our filters. With some testing, we decided to implement our own fixed point solution, a fixed signed 11.21 integer calledΒ fix11_21. This was done using macro definitions to perform casts and arithmetic operations on a typedef signed int. With 11.21, we have enough range for our ADC reads as well as enough precision for our filters.
typedefΒ signedΒ intΒ fix11_21; |
Carrier Signal
Our carrier signal is a sequence of samples stored in memory that we sample at different offsets to produce different frequency signals. Our original signal is 6200 samples, which we iterate through at different rates using the following macro definition.
#define LOOP(i, offset, length) (i=(i+offset)%length) |
This macro loops through the saved carrier signal so that we are not limited by the length of our carrier signal. This allows us to generate sounds of arbitrary length.
When generating the carrier signal, we allow multiple simultaneous key presses to play chords. With multiple keys, we generate the different frequencies using different offsets when iterating through the original carrier signal sequence. As seen in the snippet above, we use a LOOP macro that increments using the offset. Because of the offset, we need a higher resolution carrier signal, having more samples, to ensure that we still have enough frequency information when skipping over several samples at a time.
To save on memory, we could have saved pre-filtered sequences of the carrier signal rather than filter on each sample. This will save us an expensive filter operation at the cost of significantly higher memory usage. However, seeing that we already reached around 80% of memory usage with just our original carrier sequence, we could not afford to save pre-filtered sequences.
With memory usage close to our maximum memory, we noticed that our filters would not function correctly if we tried to use more memory than we could allocate. We reached a maximum memory usage of around 82% with 6200 samples of the carrier signal in memory.
The carrier signal is also scaled to be between 0 and 1 so that we could figure out how to scale the output of our filter banks to fit within the DACβs value ranges. We did this in Python before saving the sample table, which allowed us to totally precalculate the carrier signal samples and save the table in flash instead of RAM.
Reading Serial Data from the Python Interface
The C program uses a serial protothread that reads strings from the UART interface. Parsing through these strings, the protothread sets flags for new events such as button presses or slider events from the Python GUI. In our program, we only use the new βkeyβ event, where we set boolean values in an array indicating that a note is pressed.
intΒ key_index = (PT_term_buffer[3] βΒ β0β) *Β 10Β + (PT_term_buffer[4] βΒ β0β); |
The keys array above tells us which of the keys are currently pressed, and therefore which frequencies we need to generate. This array is used in the following snippet, which generates the carrier signal.
for(j =Β 0; j < NUM_KEYS; j++) { |
To reduce the number of division operations, we use a lookup table for inverse values for the number of keys so that we can multiply instead. This allows us to scale our output according to the number of keys pressed, preventing overflow of our fix11_21 data type.
Other Optimizations
Besides the optimizations mentioned before, we tried some other optimizations for memory and speed. Initially, we had our carrier signal as floats which we converted to fix11_21 at runtime. Instead, we precomputed the fix11_21 integer equivalents to reduce memory usage. We could have done the same for the filter coefficients, but the arrays were not as large so we did not need to. There were other optimizations in mind, such as unrolling loops and reducing the number of filters; but, these ultimately did not end up remaining as some of the gains were marginal. We measured our optimization gains using timer profiling.
HardwareΒ connections
The audio input (-2 to +2 V) comes in through the input audio jack, and goes through a biased high pass filter to bring the voltage into an acceptable range for the ADC (0 to +3.3 V), and to remove the DC frequency content of the audio input signal. The new DC level of the signal after it goes through the bias circuit is around 1.65 V (3.3/2) since the pull up and pull down resistors (R3 and R4 in figure TODO) are of the same value. This circuitry is duplicated for each channel, one of which is connected to ADC channel 11 (RPB13). The other channel (connected to βADCβ is left disconnected for this lab.
The ADC is configured to only acquire one sample at a time (even though it can buffer up to 16 samples). We use most of the defaults in the ADC example code except that we turn on autosampling, which means we do not need to manually acquire ADC samples since ADC samples are automatically acquired as soon as the previous sample has been converted. The latest ADC sample is read in the timer 3 interrupt service routine. This sample is then used in computation in protothread_vocode, so we do not do computationally expensive work inside the interrupt service routine (though we did try it out to see if it removing the need for context switching would help us meet timing).
The audio output is 2-channel, with 1 channel coming from DACA and the other from DACB. In this project we only use single-channel output from DACA. The PIC32 communicates with the DAC over SPI, with the chip select on pin RB4, MOSI on pin RB5, and SCK on pin RB15. Since we are not using the TFT display for this project, we do not need to add a delay to see if the line is available. The schematic for the DAC can be seen in figure 9. The DACA output is updated in the timer 3 interrupt service routine.
To aid in debugging, the scope probes are attached to the audio input (RPB13) and to DACA. Without Zoom filtering (more in the results section), we saw that there was 60 Hz noise in our input.
Results
Our vocoder worked through Zoom, as the audio output from the lab computer was connected to the ADC input of our PIC32 and the audio input to the DAC output. Because of this, we had some issues with Zoom filtering and noise reduction. With the latest version of Zoom, we must enable βOriginal Soundβ in the audio settings to bypass any audio processing done by the Zoom client. However, we noticed that enabling this setting on both ends will produce echos and noise. Therefore, we only enable this setting on the lab computer.
The only exception to the aforementioned settings is when we tested our filters using a tone generator and humming. Because Zoom filters out echos and continuous noise, we would see that Zoom filters out generated tones. Therefore, during most of our development we used βOriginal Soundβ on both computers.
In the end, even with our optimizations, we were unable to make our computations fast enough to meet our timing requirements with an 8 kHz sampling rate. So we reduced the sampling rate to 3 kHz, which also reduces our speech intelligibility to below 40%. This required us to determine new filter ranges, recalculate filter coefficients for the updated ranges and sampling frequency, and change our carrier frequency stride offsets.
With the reduced sampling rate, we encounter aliasing from the frequencies above half our sampling frequency, also known as the folding frequency or Nyquist frequency. For example, with our sampling frequency of 3kHz, any frequencies above 1.5kHz will become aliased back down to a smaller frequency. Unfortunately, this means that without a highpass filter to attenuate the frequencies above our Nyquist frequency, we have higher frequencies folded back down to the smaller frequencies. This gives us inaccurate results as we see those frequency components in those lower frequencies which would otherwise have been of smaller magnitude. We did not come to realize this effect until our demo, so we did not test to see the effects of the aliasing.
Take a look at some video demos of our vocoder!
This is a test for our filtering, where we use a tone generator to test the attenuation of frequencies outside our pass band.
Conclusion
During this lab, we encountered several issues that took vigorous debugging to resolve. Firstly, we realized that digital filtering is not an easy task for those unfamiliar with DSP and the grit of C. While the initial prototyping with Python went relatively smoothly, we had a lot of issues with memory, speed, and logic in our C program. Furthermore, the results of the vocoder were initially quite bad. Through incremental improvements of speed, carrier signal generation, and overall optimizations on filter design, we were able to somewhat achieve our goal of a vocoder producing speech using a carrier signal. We learned that the carrier signal needs to have enough frequency content, such that it can be modulated to produce the desired harmonics of the modulator signal. Next, we needed to sacrifice the higher frequency bins due to a reduced sampling rate. However, the frequency ranges of 1kHz to 2kHz are some of the most important, as they are the sounds for consonants. Therefore, our generated output from the vocoder has hints of speech, but is not intelligible due to the lack of those frequencies. As described by Bruce, it sounded like what one would hear through the walls of an apartment.
Overall, the project was successful. We had satisfactory results from our vocoder and were able to make some pretty cool sounds using our voice.
With some further testing after our demo, we found some further improvements to our setup. With theΒ constΒ keyword, we can save all of our samples to flash rather than in memory. This could have reduced our memory usage to 6%, meaning that we can likely reach a sampling frequency of at least 4kHz with pre-filtered carrier sequences. Furthermore, we likely could have optimized the frequency ranges of our filters to better suit the important frequency ranges of the human voice. By reducing unnecessary filter operations, we could increase our sampling rate even further.
Appendix
The group approves this report for inclusion on the course website.
The group approves the video for inclusion on the course youtube channel.
Code
vocoder.h
#defineΒ NUM_FILTERSΒ 8
#defineΒ NUM_COEFFICIENTSΒ 5
#defineΒ NUM_KEYSΒ 13Β // enough for an octave
#defineΒ CARRIER_SIGNAL_LENGTHΒ 6200
// fixed point implementation
typedefΒ signedΒ intΒ fix11_21;
#defineΒ multfix11_21(a,b) ((fix11_21)(((( signed long long)(a))*(( signed long long)(b)))>>21))
#defineΒ float2fix11_21(a) ((fix11_21)((a)*2097152.0))Β // 2^21
#defineΒ fix2float11_21(a) ((float)(a)/2097152.0)
#defineΒ fix2int32(a) ((int)((a)Β >>Β 21))
#defineΒ int2fix11_21(a) ((fix11_21)((a)Β <<Β 21))
#defineΒ divfix11_21(a,b) ((fix11_21)((((signed long long)(a)<<21)/(b))))
constΒ fix11_21Β carrier[CARRIER_SIGNAL_LENGTH] =
{
Β Β 912992, 912992, 919989, 880568, 901899, 1047808, 1168288, 1168800, 1122042, 1090471, 1061972, 1040640, 1054122, 1079549, 1075965, 1046954, 1008557, 963505, 908384, 841659, 775787, 756674, 826471, 921183, 951730, 969478, 1016066, 1024940, 1001219, 968966, 915552, 927156, 1032619, 1118458, 1160609, 1172555, 1108219, 1036033, 1052927, 1088082, 1068286, 1079378, 1180063, 1264195, 1248154, 1176821, 1115557, 1130915, 1202931, 1192521, 1127502, 1159926, 1226822, 1223068, 1193545, 1144056, 1071187, 1054463, 1111632, 1175285, 1197641, 1189791, 1214365, 1284674, 1317951, 1289111, 1299008, 1387407, 1467955, 1505328, 1530072, 1579903, 1715231, 1853801, 1831445, 1740317, 1736221, 1773423, 1795437, 1729053, 1551063, 1465224, 1488945, 1385700, 1232283, 1258905, 1416759, 1549356, 1573418, 1534851, 1562326, 1635536, 1660622, 1641338, 1576319, 1483825, 1423926, 1372730, 1305664, 1262830, 1240987, 1210610, 1171360, 1134158, 1117775, 1147810, 1227164, 1288087, 1259758, 1206515, 1226993, 1282967, 1296790, 1275970, 1249007, 1194740, 1092519, 1015213, 1066067, 1212146, 1317098, 1329897, 1320169, 1348327, 1389113, 1398670, 1386895, 1398670, 1446794, 1466931, 1396451, 1286892, 1232625, 1241669, 1245423, 1191839, 1117434, 1090983, 1096102, 1074771, 1028353, 992857, 989615, 1026135, 1097638, 1171360, 1197299, 1180063, 1164705, 1140984, 1097468, 1081085, 1110266, 1160609, 1196275, 1202248, 1263683, 1408226, 1448842, 1303787, 1170336, 1137742, 1077160, 968966, 913504, 908384, 897633, 887565, 866062, 790122, 722714, 769644, 857530, 837905, 764183, 790975, 897292, 940979, 883298, 819645, 835004, 886199, 870329, 803091, 793364, 849168, 893196, 912309, 928692, 940979, 967771, 1020162, 1061118, 1068286, 1063166, 1070504, 1073405, 1027671, 984666, 1047637, 1141155, 1129380, 1094054, 1135694, 1156001, 1100369, 1059924, 1064190, 1072040, 1073747, 1057193, 1032449, 1070504, 1171872, 1227846, 1192009, 1142349, 1159756, 1226310, 1228700, 1121018, 1043371, 1113168, 1230406, 1252420, 1200712, 1194910, 1280066, 1368464, 1361638, 1279383, 1228870, 1268974, 1354300, 1432630, 1481266, 1468979, 1456862, 1543725, 1630757, 1601064, 1560278, 1597139, 1644410, 1629392, 1556012, 1520516, 1558913, 1555329, 1503280, 1506010, 1531096, 1545772, 1600723, 1658915, 1662499, 1662328, 1743047, 1872231, 1904826, 1843561, 1828544, 1814721, 1714719, 1646799, 1683830, 1734002, 1737927, 1720862, 1719156, 1697995, 1594408, 1458398, 1378362, 1367611, 1390649, 1372048, 1307370, 1307029, 1355153, 1313514, 1200371, 1149858, 1194569, 1249519, 1220679, 1104635, 1004974, 1030060, 1157196, 1245253, 1229553, 1193374, 1220679, 1283650, 1288940, 1235014, 1217607, 1219996, 1169483, 1137742, 1147810, 1101734, 1042176, 1026817, 948658, 830225, 844560, 940467, 912139, 778517, 737561, 838758, 950024, 992687, 976304, 879544, 735684, 696433, 797289, 878349, 857359, 826130, 842342, 870499, 919647, 1011117, 1042517, 946952, 872718, 911456, 947464, 953778, 969478, 927668, 884493, 944563, 975621, 909579, 881762, 883810, 832273, 792682, 819986, 853434, 835857, 829201, 916064, 1003950, 1005144, 1009752, 1034497, 1020844, 1023746, 1048831, 1025964, 976645, 940296, 934665, 967430, 986543, 983301, 1009581, 1051391, 1097809, 1171019, 1227846, 1230747, 1227505, 1279554, 1398499, 1524953, 1572224, 1521710, 1431947, 1361467, 1310613, 1261294, 1247130, 1280919, 1290646, 1264537, 1295595, 1378703, 1407714, 1375120, 1329043, 1266072, 1228188, 1274776, 1343208, 1364539, 1379386, 1432971, 1517444, 1593214, 1608231, 1575637, 1574442, 1625638, 1675810, 1697995, 1715401, 1729565, 1694240, 1598845, 1535704, 1585193, 1678540, 1725470, 1742706, 1727176, 1669496, 1672055, 1743559, 1734002, 1647993, 1632976, 1687073, 1684513, 1585705, 1475634, 1408226, 1339965, 1290988, 1317780, 1350716, 1343037, 1328531, 1261124, 1137230, 1087570, 1160609, 1264195, 1305835, 1292012, 1307541, 1353447, 1348498, 1307029, 1276482, 1224263, 1150199, 1106000, 1073235, 990639, 868963, 775958, 739097, 738414, 762305, 798143, 797289, 717424, 614350, 613838, 727663, 814355, 805822, 786538, 787391, 758551, 756674, 842000, 910603, 928351, 1004803, 1083645, 1051391, 1011117, 1019479, 966577, 881933, 894903, 994223, 1086375, 1115386, 1094225, 1081426, 1095590, 1117093, 1153612, 1211805, 1273922, 1331944, 1370512, 1335699, 1227164, 1160950, 1212658, 1294913, 1299008, 1247813, 1256687, 1384335, 1538946, 1588265, 1535875, 1499014, 1530926, 1549185, 1485873, 1395257, 1353105, 1393891, 1489628, 1524441, 1469149, 1431435, 1406690, 1292694, 1118628, 1024769, 1104294, 1252762, 1239621, 1054975, 921354, 952583, 1047466, 1052756, 973403, 948488, 990298, 1013165, 1012994, 996100, 978693, 1017602, 1101393, 1192862, 1256516, 1250031, 1248666, 1305323, 1326142, 1342354, 1442357, 1512666, 1482119, 1447818, 1454302, 1457374, 1389625, 1255321, 1179040, 1201054, 1236891, 1254127, 1261806, 1295766, 1387236, 1420855, 1333310, 1283479, 1324777, 1323241, 1259588, 1201395, 1160268, 1157879, 1185354, 1152247, 1033814, 931252, 917599, 947464, 956679, 957874, 985178, 1021527, 1010435, 922036, 840976, 893196, 1023575, 1084669, 1128014, 1252762, 1344914, 1323924, 1312319, 1350204, 1354983, 1351058, 1390137, 1410274, 1355324, 1265219, 1208051, 1192521, 1165558, 1134499, 1164022, 1211805, 1197129, 1175115, 1213853, 1270680, 1313002, 1341842, 1327678, 1298838, 1320852, 1337917, 1281431, 1224774, 1207539, 1177504, 1179552, 1245423, 1258393, 1196787, 1175968, 1187231, 1154636, 1122383, 1162486, 1260612, 1341160, 1342696, 1295766, 1270339, 1266072, 1258393, 1258734, 1257540, 1229723, 1196787, 1194569, 1225798, 1260441, 1244741, 1183135, 1172384, 1234331, 1263513, 1233990, 1233648, 1289623, 1350375, 1387407, 1404301, 1405496, 1402253, 1406861, 1383994, 1305835, 1269315, 1353788, 1423756, 1354983, 1282284, 1339112, 1404472, 1322900, 1138936, 991492, 943197, 964700, 999513, 1030742, 1086204, 1194057, 1339283, 1429217, 1390820, 1312319, 1289964, 1268291, 1227164, 1213853, 1181429, 1133134, 1157196, 1174944, 1080232, 985007, 984325, 991321, 967089, 1005315, 1129550, 1207368, 1148663, 1045760, 1007875, 1014360, 1008045, 1004803, 1055828, 1129550, 1128697, 1075795, 1106853, 1226140, 1288940, 1235867, 1172213, 1201054, 1274264, 1295425, 1283991, 1290135, 1272899, 1212146, 1182111, 1224774, 1293377, 1353788, 1413175, 1446794, 1424438, 1386724, 1384676, 1394062, 1358225, 1275970, 1231089, 1285015, 1342525, 1295937, 1230235, 1244229, 1255833, 1188425, 1100881, 1047978, 1018285, 985007, 935859, 897974, 902753, 941150, 992687, 1031937, 1034155, 1030060, 1066921, 1140301, 1205491, 1207368, 1151223, 1123407, 1134499, 1117263, 1087228, 1075453, 1060777, 1069651, 1101904, 1114703, 1180917, 1322047, 1376997, 1335699, 1362150, 1417441, 1367611, 1288428, 1295937, 1361297, 1421196, 1424950, 1368976, 1366416, 1445940, 1436555, 1307712, 1232625, 1215901, 1178528, 1211293, 1305152, 1291329, 1225798, 1284162, 1383652, 1358908, 1268803, 1240645, 1246789, 1213853, 1146616, 1066238, 1004632, 996953, 982960, 905142, 846949, 880056, 938419, 944904, 928180, 961969, 1030742, 1063337, 1061972, 1053610, 1037739, 1043541, 1070675, 1071528, 1056170, 1080232, 1165217, 1258052, 1282114, 1257540, 1236379, 1221532, 1255492, 1344914, 1395086, 1385529, 1376485, 1405837, 1471880, 1479047, 1387577, 1357201, 1470344, 1605501, 1650724, 1599187, 1565739, 1641850, 1693046, 1610279, 1526147, 1534680, 1571712, 1592190, 1594920, 1575637, 1556012, 1572906, 1610620, 1603624, 1547138, 1493211, 1463006, 1474951, 1519321, 1513860, 1441674, 1370171, 1314538, 1271875, 1256175, 1212829, 1109243, 1047125, 1081938, 1094225, 1019821, 957362, 933129, 866745, 775787, 753943, 814184, 881421, 916917, 983471, 1096444, 1151052, 1104294, 1020332, 953949, 944051, 980570, 993540, 960433, 912139, 871523, 852922, 858212, 895756, 946952, 958556, 958897, 991833, 980400, 899852, 859066, 888759, 923231, 954119, 1000878, 1019650, 967601, 900876, 885175, 885346, 856676, 822887, 804627, 801044, 819303, 836710, 806163, 760087, 783296, 861625, 930910, 1013677, 1132963, 1231942, 1254980, 1211122, 1194398, 1257540, 1289452, 1235696, 1211805, 1255151, 1290476, 1300203, 1334163, 1435872, 1565568, 1661475, 1729907, 1733832, 1665059, 1678711, 1781103, 1778884, 1705162, 1737245, 1825472, 1824619, 1753115, 1704309, 1652942, 1535363, 1430582, 1424609, 1446964, 1428534, 1385700, 1331774, 1275458, 1228358, 1216583, 1272045, 1342184, 1359249, 1357030, 1353276, 1310783, 1270680, 1303275, 1374096, 1410274, 1417441, 1450548, 1516079, 1556523, 1520857, 1446111, 1439114, 1514543, 1546284, 1482460, 1422732, 1400718, 1354300, 1287916, 1244741, 1247301, 1304469, 1328361, 1239451, 1159244, 1196105, 1267779, 1340818, 1452767, 1517444, 1486897, 1481095, 1531608, 1502085, 1373072, 1281431, 1237744, 1145762, 1045077, 1033814, 1095249, 1149858, 1135011, 1072552, 1029548, 977157, 892855, 860601, 890295, 892684, 844389, 820498, 908896, 1049343, 1075965, 1000366, 963676, 959068, 897974, 812819, 807699, 862991, 855653, 775958, 695239, 621176, 557863, 505473, 446086, 424925, 445062, 466223, 541310, 655306, 688583, 675955, 731759, 815378, 823058, 776811, 783808, 857188, 924255, 955484, 952925, 961628, 1029036, 1073917, 1060265, 1105488, 1220508, 1311466, 1371195, 1408568, 1398840, 1341160, 1312490, 1415223, 1561814, 1573930, 1483143, 1400035, 1354129, 1371024, 1403277, 1379557, 1369317, 1429558, 1478023, 1447135, 1381092, 1365563, 1403448, 1426315, 1422732, 1421878, 1436213, 1491334, 1569152, 1585876, 1547479, 1583657, 1715572, 1770351, 1659256, 1514202, 1454132, 1464883, 1475463, 1407885, 1300203, 1301227, 1402083, 1416588, 1309248, 1248325, 1311125, 1393379, 1402083, 1371365, 1407373, 1504986, 1502085, 1413516, 1445087, 1535704, 1521881, 1520857, 1583487, 1576490, 1540482, 1569493, 1632293, 1691169, 1688438, 1598675, 1499867, 1432971, 1380751, 1334334, 1298155, 1287404, 1257540, 1181599, 1150711, 1173067, 1172555, 1191668, 1250372, 1282455, 1289964, 1283479, 1252250, 1233307, 1234672, 1220338, 1177845, 1103952, 1011970, 945587, 938078, 976645, 1030060, 1095420, 1159585, 1184500, 1197470, 1232966, 1247813, 1225628, 1181941, 1100027, 1033643, 1063337, 1109243, 1057876, 984325, 994393, 1027159, 1029377, 1055999, 1082621, 1056852, 1036715, 1015725, 927497, 831932, 766742, 704625, 719642, 800020, 788927, 729711, 784661, 899340, 970331, 1056511, 1197470, 1313855, 1364710, 1391332, 1394403, 1339283, 1270339, 1242010, 1203955, 1114021, 1030401, 1029377, 1123407, 1203443, 1164363, 1124772, 1206003, 1256516, 1180575, 1133134, 1151394, 1111802, 1053268, 1081597, 1117605, 1066067, 1005998, 1000878, 975792, 919477, 923231, 983642, 1019138, 1002414, 945075, 915210, 1001731, 1107365, 1061630, 979376, 1062313, 1186890, 1193886, 1191668, 1218119, 1187572, 1183477, 1260612, 1307541, 1320340, 1340477, 1293377, 1172725, 1067945, 1035862, 1100710, 1189279, 1175797, 1102587, 1093372, 1101904, 1033131, 962652, 988762, 1054804, 1092348, 1120676, 1140301, 1136206, 1125796, 1111632, 1109243, 1162145, 1259246, 1342696, 1370512, 1351228, 1334334, 1315732, 1265561, 1262318, 1361297, 1464542, 1515055, 1554817, 1575125, 1562838, 1556012, 1553452, 1522052, 1453108, 1387065, 1409762, 1515908, 1589118, 1613010, 1674786, 1772399, 1815574, 1755163, 1661304, 1642362, 1652942, 1587241, 1517103, 1544407, 1596968, 1591507, 1567445, 1543213, 1475122, 1442186, 1565739, 1701237, 1642362, 1512836, 1490310, 1484337, 1403448, 1329897, 1324777, 1329555, 1277848, 1210781, 1201395, 1210098, 1173237, 1141155, 1177162, 1231430, 1231771, 1210781, 1216754, 1206685, 1138765, 1039958, 964700, 935859, 889954, 795753, 752578, 803091, 897292, 1028012, 1144056, 1168288, 1127844, 1076989, 1061289, 1106171, 1124260, 1067774, 1034667, 1057705, 1041664, 954972, 886029, 883298, 901046, 951218, 1059071, 1142179, 1182965, 1236038, 1253103, 1205661, 1149346, 1118458, 1152247, 1221020, 1212146, 1126820, 1053268, 1046272, 1112997, 1178016, 1213341, 1277506, 1306688, 1242352, 1214023, 1274093, 1302933, 1259758, 1232454, 1263854, 1263342, 1149858, 1012994, 967771, 965724, 912821, 843195, 836369, 871865, 899169, 903777, 850704, 781760, 809576, 874254, 849338, 772203, 692850, 627148, 646603, 738926, 817256, 900364, 1052415, 1247983, 1387236, 1428363, 1464712, 1548332, 1587582, 1557547, 1534168, 1512836, 1455156, 1402253, 1372560, 1317951, 1273069, 1334163, 1452425, 1496966, 1482631, 1500208, 1532632, 1508399, 1439968, 1399352, 1387065, 1370171, 1395427, 1470856, 1504986, 1477341, 1445770, 1446623, 1489969, 1522905, 1485703, 1406861, 1314879, 1247301, 1260953, 1277336, 1224774, 1201395, 1223068, 1207368, 1201054, 1254297, 1307029, 1302763, 1236208, 1165387, 1126478, 1087228, 1093884, 1147810, 1079037, 904630, 841830, 898486, 977157, 1068969, 1115557, 1108901, 1165217, 1280578, 1331944, 1275800, 1173749, 1125113, 1124772, 1073576, 989615, 942856, 901387, 856335, 846096, 881933, 987738, 1117434, 1157537, 1126478, 1108219, 1123919, 1186719, 1245253, 1230918, 1200883, 1195764, 1179552, 1163510, 1143885, 1116751, 1126478, 1126478, 1086034, 1104806, 1173408, 1209586, 1248666, 1280407, 1253444, 1246959, 1292182, 1286892, 1238427, 1244400, 1260441, 1198323, 1143885, 1208904, 1327849, 1397304, 1408226, 1395427, 1412834, 1473416, 1506352, 1471026, 1410615, 1377509, 1372730, 1360614, 1347986, 1374266, 1439285, 1525465, 1586217, 1571200, 1566592, 1667106, 1755846, 1715401, 1642362, 1636048, 1643044, 1618300, 1585534, 1526147, 1445599, 1416588, 1409421, 1365904, 1347644, 1344743, 1294571, 1276824, 1305152, 1281431, 1248154, 1259929, 1249178, 1201566, 1167265, 1170507, 1204296, 1212999, 1170336, 1117946, 1054122, 967942, 923743, 949000, 959751, 908043, 865550, 887735, 937907, 953778, 893196, 845072, 994735, 1270168, 1380751, 1305152, 1283820, 1407885, 1532461, 1502256, 1370000, 1307370, 1311295, 1263171, 1174091, 1112656, 1086034, 1072894, 1045077, 1029206, 1090641, 1182965, 1224092, 1250202, 1263513, 1190644, 1084157, 1024087, 949512, 839270, 773398, 759575, 758039, 740121, 683464, 655818, 724762, 791658, 758892, 683123, 633804, 622029, 648821, 694386, 748312, 828689, 899169, 904289, 903947, 971184, 1020332, 971014, 928009, 987908, 1071016, 1091836, 1105147, 1192521, 1340306, 1454302, 1435701, 1314367, 1251738, 1289452, 1325289, 1352935, 1384164, 1348327, 1309248, 1375632, 1452425, 1449524, 1449012, 1523076, 1629392, 1661134, 1588265, 1532803, 1560449, 1571200, 1507375, 1432459, 1392356, 1367270, 1361979, 1407885, 1433653, 1362662, 1305323, 1350716, 1382628, 1342354, 1323924, 1355324, 1370000, 1324094, 1251226, 1229723, 1272899, 1322559, 1339965, 1308906, 1250543, 1218802, 1202419, 1160609, 1118799, 1105488, 1131086, 1203443, 1248325, 1211293, 1181941, 1205149, 1212999, 1208392, 1220508, 1209416, 1197811, 1250372, 1311637, 1301398, 1291841, 1378874, 1467101, 1439626, 1410786, 1484508, 1520686, 1431947, 1333651, 1288769, 1262147, 1248325, 1245935, 1267950, 1351740, 1429046, 1373584, 1243034, 1205149, 1260100, 1317951, 1377338, 1420513, 1400206, 1366928, 1363003, 1336040, 1259758, 1167947, 1096785, 1040128, 962311, 914869, 962140, 1004291, 968454, 958897, 999854, 1007704, 995247, 991321, 961287, 915381, 900534, 935006, 981765, 988591, 1009581, 1115898, 1210952, 1204467, 1172213, 1183647, 1234843, 1292865, 1307712, 1314879, 1358396, 1335357, 1209074, 1110096, 1068457, 1029377, 1046101, 1146104, 1221873, 1204126, 1177845, 1237232, 1301910, 1260270, 1205320, 1243034, 1271021, 1229894, 1226993, 1270851, 1271875, 1246277, 1242693, 1268803, 1309589, 1263342, 1104464, 1019309, 1063849, 1070334, 1013506, 984325, 999001, 1101051, 1271021, 1347303, 1315562, 1312831, 1332798, 1297473, 1239280, 1209586, 1213511, 1243205, 1260953, 1268803, 1340648, 1442186, 1445429, 1381263, 1344743, 1317439, 1326484, 1412493, 1465395, 1445087, 1471197, 1560278, 1606695, 1555670, 1445770, 1351058, 1282114, 1208904, 1152588, 1107365, 1039275, 988420, 980741, 992345, 1043883, 1119823, 1139448, 1108731, 1091665, 1082109, 1053780, 1033473, 1056852, 1111632, 1152418, 1162657, 1156513, 1157025, 1196105, 1237061, 1171360, 1053780, 1090300, 1253103, 1301056, 1210440, 1168971, 1233478, 1287575, 1234843, 1116069, 1048320, 1070846, 1121530, 1136718, 1120506, 1156001, 1272045, 1332286, 1259929, 1197470, 1240987, 1294742, 1285186, 1252250, 1243376, 1261977, 1271533, 1244741, 1224092, 1254639, 1308736, 1356518, 1412493, 1466931, 1479559, 1459081, 1442015, 1425633, 1425462, 1478706, 1532461, 1518639, 1452767, 1329897, 1193033, 1195081, 1286380, 1246959, 1121871, 1073917, 1039787, 954119, 903094, 900193, 866062, 778347, 669641, 590287, 599332, 674590, 712646, 724079, 807016, 896951, 879032, 814867, 773227, 732100, 713499, 734830, 783125, 886199, 1012482, 1091665, 1164022, 1244570, 1249348, 1215730, 1258564, 1333310, 1359931, 1366587, 1353617, 1307541, 1272045, 1230235, 1172043, 1186719, 1264025, 1298326, 1286892, 1274093, 1280749, 1310613, 1322217, 1314367, 1314709, 1280919, 1214706, 1177674, 1170848, 1194398, 1224263, 1175626, 1098833, 1129721, 1234331, 1299691, 1321364, 1343208, 1366075, 1369147, 1347474, 1316074, 1322559, 1407714, 1501232, 1503109, 1454644, 1439968, 1437408, 1398499, 1330921, 1289452, 1324948, 1399523, 1428193, 1430070, 1482972, 1551575, 1552598, 1484849, 1358396, 1221020, 1204637, 1265561, 1229553, 1188084, 1290817, 1411639, 1472904, 1564203, 1653454, 1682295, 1722739, 1794755, 1796803, 1684342, 1573930, 1576490, 1609938, 1567616, 1504645, 1490481, 1497648, 1483313, 1445599, 1428363, 1435872, 1390820, 1300203, 1285356, 1350887, 1371195, 1324948, 1301910, 1307370, 1273922, 1211805, 1179040, 1185524, 1210952, 1234502, 1248837, 1270168, 1280237, 1223239, 1135864, 1130745, 1192009, 1197129, 1151735, 1141837, 1135523, 1083474, 1022380, 969478, 946781, 1009923, 1089617, 1047978, 910773, 824252, 858724, 962652, 1041152, 1052927, 1015213, 953607, 902070, 874083, 835516, 775446, 738926, 740633, 729711, 685341, 680221, 752408, 813672, 823399, 863503, 937737, 975280, 1002755, 1064873, 1117093, 1127161, 1137912, 1197982, 1254127, 1211464, 1148663, 1167947, 1119311, 927327, 811453, 831420, 816744, 769814, 780053, 813672, 853434, 912992, 932958, 866062, 756845, 696775, 736025, 841488, 952754, 1021186, 1022892, 1000707, 1026476, 1099857, 1142520, 1106341, 1068798, 1131086, 1247983, 1322729, 1370512, 1437579, 1500037, 1535875, 1566251, 1599699, 1624273, 1633659, 1613863, 1567275, 1531438, 1499525, 1453449, 1451743, 1488774, 1471197, 1431947, 1441333, 1429728, 1346621, 1238939, 1159926, 1153442, 1185524, 1166241, 1099003, 1023575, 977328, 1040640, 1166070, 1213341, 1241498, 1357372, 1467272, 1475805, 1404984, 1299179, 1244912, 1296278, 1360614, 1350887, 1309589, 1294060, 1311978, 1356860, 1389113, 1371195, 1362662, 1439797, 1546114, 1581268, 1535363, 1450548, 1395598, 1416930, 1462835, 1494577, 1518297, 1469320, 1350546, 1293889, 1293036, 1255321, 1231259, 1248325, 1229211, 1189791, 1189791, 1217266, 1275458, 1359420, 1393550, 1360102, 1333992, 1341672, 1352252, 1366587, 1388601, 1392014, 1382458, 1385017, 1379727, 1362662, 1394403, 1464542, 1465907, 1394745, 1340136, 1280578, 1170166, 1075624, 1015213, 932617, 857700, 845755, 881762, 921354, 927668, 931422, 990639, 1069480, 1141155, 1233307, 1286721, 1251908, 1196617, 1157367, 1129038, 1133646, 1151394, 1165046, 1199689, 1219484, 1208221, 1259246, 1369147, 1404301, 1365734, 1379215, 1470173, 1566592, 1599528, 1562326, 1519833, 1490310, 1468125, 1525977, 1617447, 1588265, 1506522, 1499867, 1491334, 1441162, 1407885, 1376826, 1337064, 1299008, 1244570, 1189279, 1142008, 1111290, 1142349, 1166582, 1061460, 889442, 790975, 787050, 837905, 912992, 958215, 934494, 903606, 928863, 924767, 833468, 785685, 851898, 911285, 907190, 927668, 998830, 1083133, 1199006, 1267267, 1107707, 830055, 740291, 824935, 898145, 963676, 1036203, 1066579, 1100027, 1150711, 1142349, 1084498, 1058900, 1089788, 1126990, 1107707, 1062313, 1096614, 1196105, 1220849, 1148493, 1089447, 1076989, 1058559, 1006168, 939272, 924938, 979717, 1004291, 948488, 880227, 860090, 901046, 955655, 957362, 953778, 996953, 1025111, 1032278, 1054804, 1032961, 983471, 1009923, 1060095, 1060265, 1082109, 1124431, 1116239, 1114362, 1155319, 1171872, 1178016, 1215559, 1238939, 1220508, 1191668, 1191327, 1224774, 1230577, 1195252, 1195081, 1230747, 1256345, 1316756, 1422220, 1461641, 1417271, 1447476, 1575295, 1602600, 1511471, 1468979, 1461811, 1439626, 1468467, 1503962, 1483996, 1466248, 1447647, 1406349, 1389796, 1396963, 1406349, 1412322, 1385359, 1338429, 1314879, 1318463, 1324436, 1327678, 1381434, 1476146, 1490822, 1420001, 1367440, 1344914, 1327337, 1292182, 1228700, 1221532, 1298326, 1353617, 1351911, 1340818, 1343037, 1340989, 1290305, 1245594, 1321193, 1457033, 1524270, 1545602, 1549015, 1470514, 1347133, 1316586, 1366758, 1382628, 1386041, 1422561, 1446282, 1479730, 1539970, 1532973, 1463176, 1433312, 1446111, 1438773, 1383311, 1318122, 1306347, 1352423, 1425121, 1466589, 1419319, 1375290, 1444234, 1518980, 1467784, 1339624, 1253274, 1245423, 1236550, 1185183, 1176138, 1228700, 1271021, 1280578, 1225116, 1107707, 1050197, 1064190, 1006510, 888077, 860601, 904459, 884493, 830567, 841147, 888247, 935518, 982277, 988591, 992004, 1052415, 1084327, 1064702, 1094396, 1139789, 1120506, 1080402, 1074771, 1137571, 1240475, 1264025, 1250543, 1337747, 1408909, 1353276, 1350716, 1476999, 1564203, 1555329, 1543554, 1584852, 1643044, 1605160, 1439456, 1277677, 1183818, 1088252, 997124, 957020, 908043, 820498, 770155, 780224, 812136, 866233, 920842, 926132, 890636, 855141, 865380, 937737, 971867, 890978, 804115, 819474, 875278, 883810, 874083, 904289, 909920, 819133, 735684, 746435, 766572, 749848, 763329, 864015, 1033814, 1152418, 1146616, 1115898, 1128014, 1156684, 1209757, 1230577, 1149005, 1117434, 1266584, 1385359, 1287916, 1170507, 1207880, 1248837, 1186719, 1097809, 1003779, 946269, 977499, 977669, 923402, 982106, 1123407, 1178528, 1141325, 1097809, 1134670, 1247301, 1283479, 1217266, 1204126, 1274946, 1345597, 1359249, 1281943, 1214194, 1303616, 1436213, 1420001, 1339624, 1339965, 1374437, 1382287, 1364880, 1314709, 1280749, 1296449, 1270680, 1195764, 1205661, 1303787, 1365222, 1370683, 1404813, 1497478, 1559254, 1509423, 1421878, 1389625, 1383140, 1359249, 1308736, 1232113, 1175797, 1175797, 1238256, 1377338, 1509935, 1542189, 1590483, 1733490, 1782126, 1667960, 1603112, 1637925, 1602600, 1521881, 1545090, 1582633, 1505669, 1445770, 1518468, 1595944, 1569322, 1519321, 1533997, 1562838, 1532632, 1468125, 1397816, 1334334, 1321023, 1282455, 1124772, 1012824, 1047125, 1009411, 842342, 760087, 802409, 854117, 899510, 953949, 991833, 1010605, 1033131, 1044395, 989103, 901046, 940467, 1146104, 1292353, 1229211, 1146616, 1202931, 1279554, 1336552, 1427169, 1438432, 1366758, 1396622, 1493894, 1493382, 1409762, 1330921, 1278359, 1209586, 1109413, 1048320, 1028865, 1011629, 1061118, 1156855, 1178528, 1139448, 1092177, 1037227, 987226, 908043, 810600, 803091, 864868, 887223, 873742, 855994, 848144, 898657, 989956, 1033985, 1031254, 1055828, 1110778, 1173067, 1267438, 1355153, 1355836, 1299008, 1243717, 1196617, 1165899, 1137912, 1116069, 1131427, 1138083, 1135182, 1219143, 1349863, 1415564, 1431947, 1447818, 1485532, 1529560, 1494235, 1376655, 1292012, 1292012, 1344573, 1389113, 1376314, 1354471, 1392867, 1444405, 1436213, 1407544, 1446282, 1550721, 1640143, 1665571, 1639973, 1615569, 1614716, 1561302, 1427851, 1348839, 1396792, 1431094, 1335016, 1214023, 1200712, 1220849, 1177333, 1139619, 1119482, 1042347, 989786, 1023916, 1018285, 956508, 961799, 1006339, 1000366, 975109, 954290, 911115, 889783, 930910, 966577, 938078, 895244, 937737, 1090983, 1236720, 1304128, 1396963, 1484679, 1393038, 1210440, 1115727, 1037398, 938760, 924255, 957020, 940467, 918111, 968113, 1062996, 1094225, 1012994, 881762, 792511, 812989, 891319, 881933, 820839, 874083, 999683, 1041493, 993028, 927839, 869475, 847803, 940296, 1116751, 1207709, 1206685, 1250202, 1281943, 1245594, 1268632, 1312490, 1243205, 1172384, 1193886, 1219314, 1230747, 1237744, 1193033, 1131086, 1090471, 1034497, 990468, 1011629, 1070675, 1116581, 1110437, 1065897, 1043883, 1038763, 1046101, 1112997, 1172896, 1161974, 1196617, 1306517, 1337064, 1257199, 1195081, 1208733, 1244912, 1291500, 1410445, 1561472, 1629734, 1653113, 1720180, 1792707, 1816769, 1806700, 1797997, 1782809, 1703797, 1560449, 1402424, 1257199, 1170336, 1142008, 1126137, 1140131, 1168459, 1193716, 1276824, 1329385, 1251738, 1203272, 1256687, 1275970, 1226310, 1168971, 1171531, 1250372, 1320681, 1360614, 1378191, 1336552, 1317268, 1345767, 1301056, 1254809, 1325801, 1409762, 1423414, 1393550, 1360273, 1366758, 1412322, 1487580, 1538434, 1455668, 1317268, 1261977, 1222044, 1184842, 1249519, 1366075, 1432630, 1424609, 1377679, 1357542, 1343037, 1284674, 1208562, 1129038, 1078866, 1100710, 1135011, 1169483, 1256857, 1334334, 1346450, 1333139, 1301056, 1239621, 1160438, 1086716, 1067603, 1117775, 1198153, 1264195, 1282626, 1269486, 1251396, 1212829, 1182282, 1218802, 1278701, 1290305, 1297643, 1359420, 1405325, 1359249, 1272728, 1197641, 1135352, 1111461, 1114362, 1129721, 1203443, 1267950, 1217095, 1158561, 1214706, 1310954, 1339283, 1280749, 1195422, 1157537, 1144397, 1112485, 1114362, 1189449, 1278018, 1321023, 1357201, 1435872, 1481948, 1423585, 1356860, 1368464, 1378191, 1299691, 1174603, 1105318, 1129721, 1177504, 1180917, 1165046, 1155489, 1124260, 1081767, 1077672, 1107365, 1144056, 1194569, 1228017, 1198323, 1152418, 1137912, 1097297, 1001049, 908555, 865380, 897121, 984325, 1025281, 994564, 965212, 926303, 866062, 839782, 795241, 696092, 645750, 607694, 491650, 427655, 485848, 556669, 633975, 743534, 839099, 929375, 1014530, 1079378, 1156343, 1176138, 1078184, 1013848, 1059583, 1098321, 1149687, 1286039, 1363857, 1319145, 1316586, 1338088, 1218460, 1071358, 1089276, 1211293, 1303104, 1295595, 1210610, 1170166, 1145421, 991833, 809918, 776128, 835174, 871353, 874254, 885858, 929545, 976987, 1004291, 1024940, 1080232, 1204467, 1307712, 1304981, 1297473, 1325801, 1315903, 1306858, 1295425, 1215389, 1177674, 1260953, 1360273, 1406690, 1401741, 1391502, 1434336, 1464542, 1451231, 1496795, 1570517, 1558401, 1497136, 1455668, 1442527, 1471538, 1513178, 1482119, 1382799, 1368976, 1503280, 1594408, 1534339, 1494918, 1568469, 1627515, 1567275, 1421196, 1342184, 1402424, 1444575, 1416588, 1457374, 1506864, 1454132, 1413858, 1415394, 1382799, 1412663, 1543554, 1613180, 1563691, 1501061, 1483143, 1460275, 1405154, 1414199, 1541335, 1646287, 1608743, 1511471, 1479218, 1484849, 1425633, 1325289, 1272557, 1239280, 1188767, 1158220, 1131769, 1097638, 1110096, 1156343, 1203443, 1266755, 1295595, 1267608, 1293206, 1368976, 1354129, 1296278, 1343549, 1418295, 1373584, 1267950, 1234160, 1289623, 1360102, 1389966, 1407032, 1425292, 1375802, 1246789, 1133134, 1102758, 1137400, 1177845, 1180746, 1144056, 1099686, 1082791, 1064361, 1019138, 1034667, 1128697, 1191327, 1221020, 1242181, 1205149, 1171360, 1176821, 1146786, 1169654, 1308565, 1390478, 1388089, 1431435, 1475293, 1450889, 1406008, 1336723, 1226140, 1144738, 1141325, 1173408, 1187743, 1194740, 1229723, 1270680, 1254980, 1180063, 1136206, 1160609, 1147127, 1053268, 994735, 1019821, 1063849, 1081597, 1038080, 970331, 1000025, 1095420, 1144909, 1206856, 1285868, 1263342, 1215047, 1203614, 1059071, 826471, 752578, 794388, 804798, 812136, 826983, 831420, 840464, 828860, 826642, 865380, 849680, 781589, 765036, 738243, 636364, 569638, 594042, 651040, 714181, 765548, 773910, 741145, 675273, 613326, 637558, 714352, 708379, 655647, 672542, 688754, 655647, 681245, 732271, 690631, 661108, 760940, 868963, 883640, 907360, 1005656, 1081256, 1099515, 1153783, 1237744, 1245765, 1195593, 1196275, 1262489, 1352593, 1469320, 1571882, 1558913, 1459081, 1387236, 1317780, 1223580, 1216583, 1302933, 1359931, 1363003, 1331432, 1283991, 1319657, 1441333, 1478535, 1405837, 1397816, 1465054, 1455497, 1386041, 1359931, 1346621, 1331603, 1383994, 1501403, 1619836, 1683319, 1682124, 1685537, 1724446, 1737586, 1700042, 1674103, 1728883, 1810625, 1818476, 1816428, 1838101, 1753115, 1620860, 1599528, 1595774, 1527683, 1488604, 1509765, 1540823, 1544236, 1558913, 1648505, 1726664, 1724446, 1704991, 1632976, 1535533, 1590142, 1713695, 1702773, 1638266, 1655673, 1725640, 1767109, 1727347, 1633829, 1543042, 1479218, 1477170, 1505498, 1489457, 1495430, 1604648, 1714207, 1711647, 1627856, 1517785, 1429217, 1419148, 1406008, 1272387, 1146957, 1158220, 1169483, 1111290, 1073917, 1050026, 1038592, 1094225, 1136547, 1073405, 966918, 894903, 853775, 832273, 842854, 873571, 910773, 960263, 971696, 928692, 946610, 1043541, 1104635, 1123236, 1125113, 1079208, 1050197, 1114021, 1170848, 1089276, 934835, 884322, 972038, 1083133, 1120335, 1062313, 989274, 985007, 989786, 939272, 871182, 808723, 774251, 762647, 701382, 640289, 669300, 689095, 654282, 688754, 779200, 811112, 814013, 825276, 794388, 764695, 802068, 818792, 813160, 956850, 1204126, 1323582, 1320852, 1327678, 1329385, 1307541, 1295083, 1251908, 1181770, 1201736, 1319487, 1374266, 1296961, 1211805, 1210098, 1211464, 1139448, 1061801, 1046442, 1069992, 1111632, 1153612, 1166411, 1185866, 1248837, 1304981, 1293377, 1219314, 1175285, 1239792, 1317780, 1287575, 1212999, 1216413, 1287063, 1273240, 1096444, 932788, 931934, 985178, 1001731, 1005144, 981765, 962993, 1023916, 1111973, 1102758, 1007363, 972038, 1039616, 1117605, 1201224, 1307370, 1330238, 1244400, 1179381, 1195764, 1215389, 1174603, 1135011, 1161804, 1205491, 1240475, 1307370, 1390137, 1424268, 1365904, 1265731, 1222897, 1219484, 1235355, 1326996, 1393379, 1311466, 1199518, 1164363, 1140813, 1097297, 1091665, 1157196, 1247301, 1294230, 1276653, 1225969, 1233990, 1337747, 1433142, 1466931, 1466419, 1422902, 1390649, 1402424, 1358225, 1268974, 1248666, 1282114, 1287916, 1232454, 1189108, 1267950, 1370000, 1349863, 1325972, 1399352, 1444063, 1403107, 1359761, 1317098, 1227676, 1157708, 1203784, 1321876, 1403789, 1440138, 1487580, 1528195, 1482972, 1399694, 1401059, 1426486, 1399011, 1428705, 1500891, 1468296, 1396792, 1383311, 1358737, 1323753, 1312831, 1258905, 1188596, 1200030, 1239451, 1255151, 1339453, 1475293, 1530243, 1526147, 1512836, 1435701, 1366587, 1412834, 1475634, 1463859, 1421196, 1384505, 1402083, 1474440, 1473416, 1368293, 1272387, 1210781, 1123919, 1008899, 905654, 851728, 880056, 982789, 1055487, 999001, 899169, 902582, 990810, 1073747, 1109755, 1092007, 1111290, 1233136, 1313343, 1253785, 1189279, 1194398, 1190473, 1139960, 1069992, 1042859, 1098321, 1136718, 1066409, 972208, 950365, 973403, 976816, 962311, 987567, 1035691, 1012312, 925279, 877325, 923572, 1039104, 1135523, 1167606, 1219143, 1331774, 1407714, 1386895, 1333139, 1329043, 1383823, 1441333, 1469149, 1500037, 1560619, 1598675, 1532120, 1397134, 1340306, 1386212, 1390137, 1279725, 1170507, 1181087, 1262489, 1296790, 1264366, 1206515, 1147981, 1117775, 1112144, 1084327, 1059241, 1109755, 1215389, 1297814, 1339453, 1360443, 1371024, 1383311, 1381092, 1324094, 1255833, 1268120, 1334504, 1359249, 1348668, 1368464, 1381775, 1298838, 1184500, 1165387, 1154807, 1031425, 935689, 999683, 1094225, 1098833, 1050026, 989615, 955655, 988250, 1003608, 910944, 842683, 938419, 1052245, 1020162, 930910, 906166, 950535, 1002926, 980058, 915040, 920159, 961116, 959068, 921866, 833297, 725956, 726810, 828689, 892684, 885517, 910944, 1026135, 1140643, 1162316, 1124089, 1098662, 1118628, 1149005, 1109584, 1007534, 926473, 925279, 1019479, 1103440, 1079208, 1086375, 1210610, 1252250, 1119482, 996953, 1020674, 1128526, 1202590, 1221532, 1227164, 1240645, 1287404, 1344061, 1336893, 1297473, 1283991, 1270339, 1271363, 1313514, 1351570, 1376485, 1417100, 1461641, 1468296, 1433312, 1449524, 1520004, 1445258, 1184330, 984325, 981936, 1068627, 1123919, 1125284, 1101393, 1095420, 1151052, 1206344, 1141667, 1059241, 1143373, 1269997, 1253615, 1187913, 1181941, 1201736, 1269144, 1421196, 1544578, 1543383, 1527342, 1585705, 1608573, 1548332, 1513519, 1534509, 1572906, 1636218, 1696629, 1703285, 1668813, 1617617, 1557718, 1520516, 1524782, 1534851, 1513860, 1484849, 1498331, 1573077, 1671543, 1715572, 1669496, 1587924, 1539800, 1517785, 1452084, 1338429, 1290988, 1356689, 1410103, 1357542, 1273922, 1253785, 1266072, 1236891, 1184842, 1156855, 1162145, 1236550, 1344573, 1337747, 1208221, 1093201, 1037056, 1026647, 1071016, 1157025, 1262147, 1341501, 1354641, 1342013, 1343378, 1346621, 1326142, 1249007, 1167435, 1162828, 1149175, 1077672, 1073576, 1116751, 1101563, 1114703, 1175968, 1130062, 983813, 887053, 868110, 860260, 862479, 929716, 1020503, 1041835, 1048831, 1114533, 1166070, 1168971, 1168800, 1167435, 1171360, 1177504, 1158391, 1160609, 1222897, 1289964, 1296790, 1255151, 1287233, 1439797, 1537240, 1480924, 1371707, 1277848, 1237915, 1245765, 1185695, 1079037, 1077672, 1175285, 1253103, 1248666, 1208904, 1205320, 1174432, 1084498, 1051221, 1068457, 1065555, 1099515, 1153271, 1159926, 1189961, 1262489, 1272387, 1200371, 1133134, 1104976, 1060436, 1000195, 994052, 1012482, 999513, 992004, 989956, 970331, 994052, 1090641, 1179893, 1175456, 1119482, 1136376, 1200371, 1201224, 1190985, 1224774, 1221191, 1159585, 1081426, 1004974, 992687, 1056852, 1090641, 1055316, 1027500, 1042859, 1050879, 998660, 911456, 873059, 912480, 965041, 959751, 904971, 857700, 825447, 793535, 808211, 856164, 847973, 846949, 937907, 976133, 917088, 943880, 1031254, 1025281, 992857, 998318, 974427, 921013, 875960, 863844, 917088, 997465, 1048661, 1068798, 1054634, 1014701, 968283, 926473, 938931, 1022722, 1103099, 1117434, 1075965, 1057193, 1120676, 1200542, 1241840, 1279725, 1305835, 1330921, 1408909, 1445429, 1357884, 1294571, 1367611, 1491163, 1574954, 1582463, 1540653, 1565227, 1640655, 1593726, 1444575, 1388601, 1431094, 1409591, 1259588, 1093543, 1075624, 1184330, 1243717, 1217436, 1189791, 1185524, 1221361, 1289111, 1328019, 1366075, 1482460, 1656697, 1797485, 1836223, 1796291, 1771717, 1800045, 1838271, 1851411, 1884347, 1997661, 2097152, 2062168, 1981961, 1946636, 1888955, 1786734, 1686049, 1623249, 1628880, 1638266, 1575125, 1507375, 1509765, 1561131, 1606525, 1600040, 1565909, 1546455, 1514202, 1454814, 1397816, 1393209, 1487580, 1579903, 1525977, 1421537, 1436213, 1524782, 1538264, 1454644, 1408909, 1454985, 1435701, 1281090, 1134329, 1080232, 1119482, 1251055, 1347474, 1290476, 1212317, 1255833, 1307541, 1236379, 1150711, 1199689, 1297473, 1271875, 1157367, 1083986, 1037910, 976475, 946952, 953778, 959921, 980741, 1037056, 1146957, 1293036, 1365734, 1321023, 1258393, 1252250, 1282455, 1282626, 1230577, 1201907, 1218460, 1208051, 1172555, 1147127, 1107365, 1039446, 960775, 888077, 815890, 758551, 791146, 880227, 893025, 838246, 769644, 702918, 726298, 779371, 690973, 581243, 617592, 663156, 594554, 499330, 482435, 541822, 580560, 529876, 433116, 351715, 298130, 279870, 315878, 386869, 477315, 640801, 826130, 864356, 810430, 853434, 951730, 988079, 964017, 904118, 868451, 915381, 983642, 986714, 930398, 887906, 886199, 847632, 744899, 677832, 709232, 800532, 911627, 1040981, 1158220, 1206344, 1218631, 1246789, 1244058, 1219655, 1226652, 1211293, 1174603, 1182282, 1186890, 1171701, 1202419, 1266414, 1331091, 1392526, 1441674, 1494235, 1532291, 1526659, 1522393, 1513348, 1448330, 1375802, 1340648, 1308565, 1271363, 1250031, 1264025, 1308736, 1319487, 1289793, 1339624, 1487238, 1560790, 1508741, 1496795, 1548844, 1494235, 1352764, 1307712, 1349692, 1364539, 1372048, 1418807, 1480924, 1540823, 1592702, 1618300, 1628539, 1657038, 1706527, 1729395, 1686732, 1636218, 1662840, 1707722, 1653625, 1558742, 1564544, 1642703, 1672226, 1658233, 1684513, 1742876, 1749873, 1687585, 1620006, 1582121, 1557206, 1559937, 1614204, 1664888, 1649359, 1614545, 1632976, 1657038, 1603282, 1515226, 1493723, 1542359, 1612327, 1692875, 1751750, 1725299, 1632464, 1571029, 1580415, 1605330, 1591507, 1535704, 1456862, 1394915, 1385188, 1378362, 1310783, 1226993, 1191839, 1204637, 1244400, 1260100, 1225969, 1230065, 1315050, 1363857, 1322729, 1302933, 1325460, 1258734, 1129038, 1116581, 1185866, 1184500, 1172555, 1222556, 1255492, 1251396, 1244229, 1227505, 1200883, 1138083, 1056170, 1032961, 1013506, 929375, 865209, 851386, 860090, 893537, 873571, 801897, 805993, 824082, 740803, 651381, 614350, 566567, 505644, 443355, 383968, 393184, 468953, 492674, 440113, 456496, 611107, 775275, 836027, 842683, 904118, 1046613, 1149687, 1107707, 1009240, 949853, 889100, 837393, 862649, 944392, 1032619, 1098150, 1116239, 1126478, 1200542, 1312319, 1353617, 1302080, 1267267, 1295083, 1286721, 1202078, 1142520, 1154636, 1150029, 1084327, 1031254, 1028865, 1036033, 1018114, 958215, 895756, 910603, 974427, 1011970, 1020332, 982960, 918965, 925279, 977157, 971696, 926132, 903435, 933129, 1008728, 1056170, 1065214, 1122724, 1201566, 1201566, 1166582, 1194740, 1272899, 1353447, 1440992, 1538946, 1617958, 1648505, 1629392, 1571882, 1482972, 1418295, 1445770, 1503792, 1509594, 1525635, 1596798, 1651236, 1656014, 1643556, 1629392, 1575978, 1467272, 1394233, 1390990, 1382628, 1400718, 1459422, 1453449, 1416247, 1426486, 1447818, 1484849, 1502597, 1448500, 1438773, 1481266, 1413175, 1254980, 1162486, 1203102, 1283820, 1245423, 1172043, 1233307, 1310442, 1272899, 1178016, 1069480, 989444, 966406, 983983, 1054292, 1101734, 1067262, 1047808, 1000366, 873571, 881250, 1045589, 1127332, 1131598, 1172213, 1199518, 1205320, 1260612, 1351399, 1394233, 1363515, 1331262, 1320169, 1268632, 1211976, 1231771, 1269144, 1247130, 1228358, 1276653, 1314538, 1258564, 1162998, 1107877, 1097126, 1105147, 1083303, 1023916, 1016578, 1056511, 1032108, 1009581, 1120676, 1259417, 1282967, 1252762, 1254468, 1265219, 1268291, 1297643, 1350375, 1358396, 1315220, 1326654, 1404301, 1399182, 1266584, 1149175, 1133475, 1161121, 1183988, 1216754, 1250202, 1246447, 1199859, 1144226, 1142349, 1232625, 1345597, 1386724, 1372048, 1341842, 1286892, 1261124, 1326996, 1388089, 1364368, 1366416, 1439114, 1461299, 1415564, 1386553, 1393379, 1450207, 1520686, 1471368, 1343890, 1347644, 1471026, 1503792, 1424609, 1409591, 1497990, 1547138, 1517615, 1501744, 1503280, 1478876, 1472904, 1500208, 1488604, 1443381, 1449354, 1480754, 1465395, 1468125, 1517615, 1495942, 1424950, 1443210, 1480071, 1407544, 1309930, 1271021, 1204979, 1088764, 1048320, 1099686, 1131086, 1146274, 1178016, 1152759, 1078525, 1038592, 1016749, 972038, 920159, 905824, 940808, 938760, 901217, 978523, 1120847, 1134499, 1061972, 1051903, 1110096, 1141667, 1062996, 954460, 969649, 1046272, 1043883, 996441, 967942, 943880, 910944, 853946, 759063, 650528, 571004, 546942, 559058, 571174, 618275, 740803, 853605, 860431, 834150, 892855, 996441, 1039616, 1033131, 1020674, 985861, 967089, 1001390, 970843, 835174, 762135, 775446, 753773, 773739, 928692, 1068798, 1070334, 1006510, 960604, 945757, 968454, 1018797, 1067091, 1131769, 1233819, 1281773, 1242864, 1275800, 1408056, 1446282, 1377850, 1379045, 1455497, 1488433, 1475975, 1477511, 1499696, 1534339, 1550039, 1492017, 1435019, 1507546, 1604306, 1551575, 1432288, 1398499, 1444575, 1495088, 1473586, 1383140, 1309248, 1237061, 1118117, 1035350, 1025111, 1025964, 1046784, 1072040, 1034497, 1012312, 1104976, 1208904, 1198665, 1127502, 1106512, 1138083, 1139107, 1079378, 1028865, 1057705, 1150199, 1220679, 1220167, 1192350, 1165899, 1126649, 1120676, 1164705, 1169142, 1124601, 1113850, 1135182, 1179210, 1312490, 1492529, 1575125, 1561643, 1532973, 1457716, 1354983, 1338259, 1354641, 1325289, 1389284, 1571029, 1638096, 1561984, 1576149, 1699019, 1713012, 1618982, 1620177, 1677175, 1611986, 1520004, 1542018, 1558742, 1479730, 1396451, 1331603, 1226140, 1132451, 1135864, 1171019, 1141837, 1108219, 1155319, 1234331, 1264366, 1253785, 1266243, 1292012, 1250714, 1152759, 1079378, 1093543, 1231259, 1360614, 1328873, 1304299, 1410445, 1440821, 1362662, 1351570, 1383994, 1401400, 1435531, 1439797, 1401571, 1393379, 1432630, 1480924, 1496795, 1511130, 1591507, 1665571, 1637242, 1573930, 1533656, 1476487, 1406690, 1345255, 1267267, 1175115, 1122042, 1124260, 1123065, 1094054, 1109413, 1175797, 1194910, 1178357, 1213341, 1244741, 1199518, 1153783, 1185012, 1289964, 1414370, 1454985, 1422390, 1453108, 1520686, 1503450, 1452255, 1432118, 1391161, 1310101, 1196958, 1050709, 930228, 910944, 999342, 1101051, 1111973, 1094396, 1148322, 1189791, 1142008, 1065385, 971696, 844048, 748824, 739438, 809918, 880568, 833638, 718960, 698823, 756333, 753432, 674419, 637558, 720837, 801726, 759916, 764012, 933641, 1046442, 974768, 881933, 872377, 927156, 1007022, 1029548, 973744, 930740, 952925, 995247, 977669, 873230, 768620, 758551, 806675, 826130, 826130, 854287, 888589, 908214, 919477, 910432, 942344, 1081938, 1198153, 1179722, 1139448, 1154636, 1182965, 1206344, 1182623, 1106853, 1072723, 1090300, 1110949, 1165046, 1222215, 1188425, 1110266, 1115386, 1194740, 1217948, 1158903, 1144226, 1225798, 1310954, 1327166, 1274434, 1234160, 1297643, 1353959, 1252932, 1133305, 1152588, 1183477, 1100710, 988591, 960263, 1020844, 1085692, 1089447, 1067774, 1078354, 1121871, 1172043, 1202590, 1191156, 1150370, 1152588, 1241669, 1335699, 1375290, 1442869, 1552940, 1610620, 1634682, 1685196, 1692363, 1607207, 1504474, 1427681, 1340306, 1253274, 1209245, 1169142, 1103440, 1071187, 1074771, 1069480, 1092348, 1162657, 1225628, 1239963, 1172896, 1051391, 1010947, 1093884, 1154466, 1110949, 1086887, 1192862, 1349692, 1449012, 1502427, 1569322, 1699531, 1855166, 1900730, 1872060, 1939298, 2021552, 1956704, 1844756, 1792024, 1734002, 1649359, 1601576, 1626491, 1669496, 1646969, 1623931, 1683660, 1678540, 1513007, 1380410, 1399011, 1432288, 1395257, 1357713, 1361638, 1363345, 1333651, 1297985, 1288087, 1328361, 1428534, 1538776, 1593726, 1604136, 1599869, 1573930, 1572394, 1639290, 1658403, 1548332, 1462835, 1496966, 1541677, 1550892, 1544919, 1513519, 1532632, 1638266, 1714548, 1715743, 1684854, 1645092, 1640997, 1653966, 1619836, 1600552, 1647823, 1661816, 1554305, 1380922, 1296961, 1351911, 1403107, 1364880, 1310783, 1294060, 1291670, 1254127, 1185354, 1151564, 1141155, 1104123, 1052074, 983983, 929204, 948317, 977328, 921525, 796607, 691997, 697969, 761794, 770155, 776128, 805651, 767937, 707355, 686194, 634828, 556498, 526634, 539262, 544553, 498647, 382432, 221166, 73892, 0, 13822, 82425, 131914, 113825, 113654, 180550, 189253, 113484, 89592, 168775, 276116, 302055, 277140, 399839, 647115, 765377, 765207, 832102, 906678, 859066, 788415, 810771, 836027, 802750, 780395, 748141, 698481, 733636, 821863, 911456, 1063849, 1182794, 1145592, 1065214, 1043712, 1052074, 1054292, 1033814, 1028694, 1056852, 1073917, 1095761, 1136547, 1179040, 1289111, 1463518, 1568981, 1579220, 1583316, 1623590, 1675980, 1699360, 1691339, 1688097, 1710794, 1735197, 1723422, 1696800, 1658915, 1545090, 1428705, 1458569, 1556012, 1581951, 1584681, 1611644, 1618641, 1611474, 1621542, 1626150, 1629392, 1674103, 1715572, 1693216, 1663523, 1647823, 1599699, 1571882, 1583316, 1575978, 1616423, 1730931, 1777860, 1732637, 1702602, 1725982, 1795096, 1862504, 1865064, 1847828, 1882641, 1941346, 1976671, 1982985, 1959776, 1928205, 1931789, 1942881, 1884518, 1803970, 1800045, 1804141, 1718814, 1606866, 1531267, 1455156, 1377679, 1352423, 1385017, 1419489, 1412151, 1386553, 1372901, 1348156, 1311978, 1308906, 1319657, 1292865, 1258222, 1250543, 1233990, 1197641, 1170336, 1122553, 1013165, 929033, 1010093, 1196446, 1270339, 1212146, 1192521, 1201907, 1111461, 1006851, 1051221, 1173579, 1198494, 1116239, 1014872, 909408, 806846, 762135, 779029, 838246, 940638, 1006339, 963505, 899681, 900022, 903094, 847291, 797460, 828689, 851386, 760599, 677662, 723909, 809064, 863332, 907702, 957703, 1076819, 1243546, 1293377, 1204126, 1091665, 991321, 917088, 902241, 938078, 990810, 1023916, 1051562, 1092348, 1061801, 966577, 976987, 1092007, 1134499, 1095078, 1105147, 1181599, 1230065, 1247471, 1324094, 1431094, 1462664, 1430752, 1380751, 1315050, 1255151, 1208051, 1168118, 1145421, 1121018, 1115727, 1180405, 1242864, 1220167, 1187572, 1217948, 1233307, 1170848, 1136035, 1208562, 1261294, 1200542, 1124601, 1091495, 1048320, 970843, 876131, 817597, 837905, 874424, 867086, 867086, 895244, 874424, 792340, 763671, 842854, 923743, 915552, 853775, 801897, 789269, 803945, 802068, 789610, 822546, 897633, 951218, 962993, 999513, 1105147, 1189620, 1180063, 1183135, 1279895, 1371024, 1405666, 1456692, 1510106, 1513348, 1537581, 1628198, 1695264, 1675980, 1629563, 1636730, 1654819, 1554988, 1388431, 1364710, 1485020, 1566421, 1559083, 1521028, 1483655, 1467101, 1445429, 1368635, 1288257, 1294913, 1334334, 1277165, 1146786, 1089617, 1148151, 1233990, 1261977, 1205491, 1111461, 1068627, 1108389, 1186036, 1254809, 1299691, 1309077, 1265731, 1205149, 1190985, 1196958, 1163339, 1134329, 1176309, 1248837, 1283138, 1290646, 1308053, 1317098, 1306858, 1324094, 1372218, 1403277, 1441845, 1512666, 1527683, 1442527, 1334846, 1249007, 1195081, 1208562, 1248837, 1256175, 1256175, 1216583, 1092519, 1000707, 997465, 987396, 1002243, 1076477, 1061801, 971867, 1016578, 1166753, 1237744, 1228700, 1209416, 1178869, 1147127, 1117946, 1073747, 1054292, 1111120, 1221020, 1321023, 1374949, 1392867, 1396622, 1379557, 1327507, 1259246, 1221703, 1230918, 1226652, 1157025, 1061801, 1001219, 997977, 1030742, 1023746, 952242, 894391, 902753, 957020, 1007363, 1019991, 1047637, 1128014, 1167606, 1144568, 1195422, 1348156, 1445429, 1406690, 1376144, 1500379, 1672055, 1707039, 1634341, 1590654, 1597651, 1568469, 1466419, 1407544, 1499696, 1627344, 1590825, 1408909, 1314538, 1439797, 1621030, 1648164, 1570688, 1552257, 1588265, 1564203, 1453791, 1353447, 1384335, 1539288, 1642362, 1606013, 1577855, 1624102, 1602429, 1508570, 1506693, 1592531, 1626662, 1596968, 1581268, 1573930, 1541165, 1510789, 1471368, 1410957, 1432800, 1539629, 1574613, 1526830, 1507034, 1522564, 1502768, 1372389, 1179722, 1100027, 1137742, 1132281, 1045418, 960945, 961628, 1022892, 998489, 853263, 727663, 721178, 786197, 802580, 780736, 846096, 957020, 1001902, 971696, 825106, 648821, 656842, 737220, 695580, 684658, 784149, 828519, 797460, 775787, 756333, 722543, 659231, 542163, 424413, 388405, 422024, 480216, 575270, 690802, 767084, 802921, 804286, 748312, 657866, 572028, 526805, 572198, 674078, 736878, 739950, 723397, 752066, 871523, 1005656, 1045589, 1023063, 1025281, 1058900, 1120506, 1230577, 1332286, 1352935, 1330067, 1326996, 1383823, 1506181, 1547820, 1403789, 1243717, 1167435, 1051050, 921013, 923060, 1034838, 1170848, 1266584, 1248837, 1165558, 1151394, 1193716, 1166411, 1072552, 1024599, 1028694, 1020844, 1013506, 1015213, 1005486, 1025793, 1094737, 1171701, 1260782, 1342354, 1360785, 1365392, 1424268, 1482290, 1496624, 1536216, 1638266, 1726323, 1732978, 1687926, 1636560, 1595603, 1598504, 1639290, 1639973, 1604818, 1652260, 1787758, 1849705, 1774447, 1692704, 1691510, 1714889, 1693728, 1615911, 1563691, 1632464, 1710111, 1628368, 1487580, 1459422, 1509423, 1552940, 1585023, 1619324, 1668813, 1733320, 1777007, 1721886, 1547991, 1419660, 1449695, 1469832, 1398499, 1434848, 1607719, 1675639, 1550721, 1371024, 1252591, 1234160, 1295254, 1320340, 1223068, 1085351, 1008387, 961969, 901046, 860431, 869475, 902241, 919477, 908043, 880397, 876984, 947293, 1073405, 1170678, 1181941, 1122383, 1086034, 1160780, 1275117, 1295425, 1248837, 1247471, 1282455, 1264195, 1203955, 1182111, 1183477, 1167947, 1170507, 1188084, 1219996, 1340818, 1522734, 1624955, 1588948, 1486044, 1425292, 1387748, 1296619, 1248325, 1306347, 1333139, 1287404, 1241669, 1214365, 1258222, 1391673, 1514543, 1552598, 1503280, 1441333, 1435360, 1384505, 1223751, 1103440, 1119482, 1194398, 1249007, 1292012, 1384847, 1515737, 1575466, 1516591, 1416247, 1379727, 1394745, 1355153, 1269315, 1215218, 1169654, 1125625, 1113168, 1069480, 972720, 921866, 942856, 953607, 947293, 992175, 1042688, 1022380, 1013677, 1053610, 1018455, 892172, 780053, 737902, 745070, 689949, 560765, 549843, 694215, 818792, 857188, 827154, 751042, 692167, 655989, 629708, 649504, 704795, 763841, 797972, 779883, 795924, 900705, 958044, 921866, 917599, 955484, 957703, 946952, 967089, 983813, 966747, 963846, 1003950, 1035521, 1052586, 1092007, 1102928, 1040128, 965382, 941832, 968625, 994052, 969307, 931252, 936371, 967771, 1000195, 1042005, 1103782, 1161974, 1152247, 1094054, 1083303, 1097126, 1075283, 1071187, 1096785, 1091495, 1083815, 1135864, 1205320, 1207027, 1167606, 1170336, 1160097, 1092519, 1098662, 1192521, 1229894, 1218460, 1227846, 1237232, 1252079, 1268120, 1250543, 1232283, 1242010, 1255151, 1263683, 1280237, 1308394, 1300374, 1210440, 1121700, 1145250, 1249007, 1319145, 1304128, 1274093, 1315562, 1404813, 1479218, 1510106, 1509594, 1545090, 1626320, 1686390, 1726152, 1730248, 1634682, 1517615, 1483996, 1474951, 1465736, 1549697, 1700896, 1761307, 1711135, 1677004, 1684001, 1674957, 1665229, 1680759, 1731272, 1807724, 1808407, 1695947, 1601917, 1607890, 1667277, 1697141, 1643727, 1585023, 1618470, 1657379, 1570176, 1409421, 1351399, 1431606, 1477341, 1421366, 1382458, 1396451, 1426315, 1452596, 1416930, 1359761, 1386553, 1430582, 1388772, 1280919, 1159244, 1113850, 1205832, 1326484, 1364880, 1400888, 1522052, 1588606, 1465736, 1333651, 1359249, 1381604, 1290988, 1217607, 1226310, 1253956, 1249007, 1245082, 1325460, 1439797, 1470173, 1460617, 1466248, 1460617, 1490140, 1550551, 1548503, 1531267, 1547650, 1492187, 1376826, 1354129, 1421708, 1451743, 1412322, 1375802, 1380410, 1360273, 1273752, 1179381, 1090471, 1000025, 996782, 1086204, 1145250, 1145250, 1124089, 1092519, 1071016, 1028353, 955484, 961799, 1035862, 1007875, 860260, 755821, 774763, 789781, 666228, 491650, 386869, 347790, 404788, 534825, 594042, 586362, 625954, 722373, 820839, 835857, 754967, 708550, 736708, 758892, 751896, 720666, 684317, 647285, 562471, 495916, 541310, 582096, 533972, 496770, 489432, 482947, 545576, 646432, 678003, 715376, 829884, 887565, 862649, 882616, 903606, 859066, 831420, 810259, 754626, 756162, 811453, 841830, 890466, 967601, 1015384, 1068798, 1145933, 1180063, 1189791, 1237232, 1253956, 1157879, 1045248, 1047125, 1106683, 1088594, 1008728, 988250, 1059241, 1148322, 1197982, 1203784, 1186719, 1186890, 1225116, 1282284, 1335528, 1368635, 1385871, 1424097, 1478706, 1487238, 1436043, 1376997, 1362833, 1410957, 1461982, 1453449, 1433995, 1462323, 1517444, 1561814, 1556694, 1523246, 1569834, 1680929, 1723763, 1698848, 1687755, 1717620, 1785028, 1832981, 1831104, 1849705, 1886566, 1866600, 1818646, 1807383, 1827349, 1843391, 1823083, 1771717, 1729565, 1719156, 1753798, 1821547, 1854483, 1825302, 1790659, 1759600, 1695264, 1659939, 1695776, 1689803, 1623249, 1642703, 1740146, 1772399, 1736562, 1709940, 1709428, 1724446, 1718132, 1652601, 1578538, 1575637, 1613351, 1624614, 1631781, 1644580, 1592702, 1467955, 1351911, 1305664, 1322047, 1337747, 1319828, 1286039, 1212146, 1121018, 1113338, 1133134, 1042005, 877837, 737220, 677150, 741486, 808211, 727834, 596431, 537214, 546942, 648309, 802750, 885175, 890636, 926132, 1038592, 1116410, 1066921, 1059753, 1160268, 1095590, 840294, 675102, 631585, 614520, 628172, 639435, 673907, 807528, 953095, 971867, 883469, 837393, 900705, 960433, 953095, 950535, 967259, 993199, 1063849, 1130404, 1110608, 1066750, 1108731, 1179722, 1197641, 1253956, 1368123, 1394745, 1329897, 1277506, 1274093, 1341672, 1412663, 1399182, 1391844, 1440650, 1429558, 1342013, 1284162, 1293206, 1325972, 1348839, 1375120, 1393209, 1337405, 1203443, 1082962, 1043200, 1055658, 1053098, 1019309, 972720, 893708, 768449, 694215, 756674, 843877, 855823, 897292, 1003950, 1050709, 999001, 929033, 940979, 1040469, 1091324, 1062654, 1072894, 1127844, 1171360, 1202590, 1211805, 1222044, 1271533, 1327849, 1349692, 1330579, 1298838, 1286209, 1276482, 1278871, 1318122, 1344743, 1334846, 1330067, 1326142, 1290988, 1265049, 1339453, 1472221, 1486385, 1407202, 1425803, 1477853, 1398670, 1303957, 1327337, 1351228, 1254980, 1080232, 942685, 966065, 1127844, 1211805, 1149346, 1132451, 1244570, 1356689, 1373413, 1325630, 1306176, 1333139, 1311637, 1225457, 1160268, 1128697, 1100198, 1066921, 1000707, 932958, 967601, 1076648, 1092689, 981082, 893879, 913674, 956679, 950877, 944221, 997465, 1075112, 1122212, 1162998, 1220338, 1251908, 1227164, 1154124, 1104123, 1179722, 1292694, 1245253, 1125113, 1137742, 1198494, 1191839, 1212487, 1251055, 1193204, 1120164, 1146616, 1170678, 1107195, 1095590, 1202590, 1240816, 1152930, 1124601, 1190132, 1229553, 1225798, 1226652, 1286892, 1386895, 1390820, 1306858, 1288087, 1352935, 1417100, 1396792, 1275800, 1202931, 1267608, 1341842, 1339453, 1323070, 1358225, 1431606, 1464712, 1412151, 1320511, 1273240, 1304299, 1340477, 1314709, 1296449, 1356518, 1431264, 1442527, 1408226, 1361638, 1309077, 1300715, 1341672, 1326142, 1226652, 1132963, 1107877, 1157025, 1232283, 1313685, 1403619, 1417953, 1367270, 1372048, 1393038, 1377509, 1374949, 1411810, 1537240, 1659768, 1590825, 1456350, 1419319, 1387748, 1345426, 1320681, 1283308, 1285698, 1335699, 1388089, 1420513, 1379557, 1338941, 1382628, 1391161, 1339794, 1329897, 1335187, 1321535, 1332115, 1394915, 1475122, 1494747, 1471368, 1464883, 1466589, 1512666, 1587753, 1580756, 1537922, 1535192, 1486897, 1399011, 1394233, 1457716, 1486727, 1473586, 1452596, 1428534, 1459934, 1563008, 1590313, 1489457, 1399694, 1370683, 1317951, 1187060, 1050879, 1023575, 1032278, 967771, 938419, 1002585, 1045930, 1038422, 1023746, 996441, 951218, 933129, 987738, 1015213, 915893, 867086, 1004291, 1111973, 1033643, 914357, 856164, 790122, 723738, 748995, 791828, 715717, 630050, 681245, 746093, 683976, 561618, 500012, 576465, 764865, 886882, 858042, 829031, 891490, 940126, 912821, 881421, 905824, 964870, 1020844, 1062996, 1084157, 1076989, 1061630, 1060777, 1053951, 1008557, 950365, 932105, 943027, 951901, 973062, 1004120, 1007875, 965382, 898657, 866745, 857871, 799849, 755650, 816573, 878861, 840976, 769814, 739097, 759746, 832102, 937907, 1032790, 1071699, 1073064, 1114191, 1169995, 1123065, 1018626, 984666, 948146, 854287, 851728, 924426, 925108, 943027, 1051221, 1109413, 1095932, 1106853, 1148663, 1210440, 1290135, 1336552, 1321705, 1311466, 1384335, 1496112, 1549015, 1555500, 1593043, 1659768, 1667960, 1595091, 1537581, 1539970, 1569664, 1620006, 1671373, 1732808, 1828203, 1868306, 1822571, 1791854, 1788099, 1775471, 1765914, 1760966, 1773082, 1800557, 1825643, 1857043, 1873938, 1866600, 1864040, 1865917, 1871890, 1827179, 1673421, 1534509, 1496454, 1465224, 1420001, 1386895, 1356348, 1387236, 1460958, 1435872, 1304981, 1216071, 1231430, 1249348, 1199859, 1171190, 1241840, 1342696, 1367270, 1340306, 1347133, 1330067, 1240133, 1208733, 1260953, 1266926
};
constΒ floatΒ float_coefficients[NUM_FILTERS][2][NUM_COEFFICIENTS] =
{
Β Β // filter 1 [20, 160)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.00362168, Β 0.Β Β Β Β , β0.00724336, Β 0.Β Β Β Β , Β 0.00362168},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β , β3.80927053, Β 5.4569114Β , β3.48477739, Β 0.83718165}
Β Β },
Β Β // filter 2 [160, 394)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.01274959, Β 0.Β Β Β Β , β0.02549918, Β 0.Β Β Β Β , Β 0.01274959},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β , β3.52986883, Β 4.79112946, β2.96439775, Β 0.7071495Β }
Β Β },
Β Β // filter 3 [394, 670)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.01726045, Β 0.Β Β Β Β , β0.0345209Β , Β 0.Β Β Β Β , Β 0.01726045},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β , β3.08395258, Β 3.99387956, β2.50847168, Β 0.66453183}
Β Β },
Β Β // filter 4 [670, 1000)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.02384756, Β 0.Β Β Β Β , β0.04769511, Β 0.Β Β Β Β , Β 0.02384756},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β , β2.29081663, Β 2.84592505, β1.7875107Β , Β 0.61352277}
Β Β },
Β Β // filter 5 [1000, 1420)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.03657484, Β 0.Β Β Β Β , β0.07314967, Β 0.Β Β Β Β , Β 0.03657484},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β , β1.03903945, Β 1.66582376, β0.75541344, Β 0.53719462}
Β Β },
Β Β // filter 6 [1420, 1900)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.0461318, Β 0.Β Β Β Β , β0.0922636, Β 0.Β Β Β Β , Β 0.0461318},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β ,Β 0.56944184,Β 1.39026504,Β 0.3944443Β ,Β 0.49181224}
Β Β },
Β Β // filter 7 [1900, 2450)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.05823671, Β 0.Β Β Β Β , β0.11647342, Β 0.Β Β Β Β , Β 0.05823671},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β ,Β 2.17492444,Β 2.42901494,Β 1.42161319,Β 0.44392035}
Β Β },
Β Β // filter 8 [2450, 3120)
Β Β {
Β Β Β Β // b coefficients
Β Β Β Β {0.02649567, Β 0.Β Β Β Β , β0.05299134, Β 0.Β Β Β Β , Β 0.02649567},
Β Β Β Β // a coefficients
Β Β Β Β {1.Β Β Β Β ,Β 3.27894229,Β 4.21362362,Β 2.51908478,Β 0.59565419}
Β Β }
};
constΒ intΒ offsets[NUM_KEYS] = {
Β Β Β 5,Β 6,Β 7,Β 8,Β 9,Β 10,Β 11,Β 12,Β 13,Β 14,Β 15Β ,16,Β 17
};
constΒ floatΒ float_inverseLUT[NUM_KEYS] = {
Β Β Β 0,Β 1,Β 0.5,Β 0.333333,Β 0.25,Β 0.2,Β 0.666667,Β 0.142857,Β 0.125,Β 0.111111,Β 0.1,Β 0.090909,Β 0.083333Β
};
vocoder_main.c
/*
Β * File: Β Β Β Β vocoder_main.c, adapted from the SECABB_python_target_v4_1_3_2.c template
Β * Β Β Β Β Β Β
Β * Author: Β Β Β Bruce Land
Β * Adapted by: Β Nicole Lin and Jonathan Gao
Β * For use with Sean Carrollβs Big Board
Β * http://people.ece.cornell.edu/land/courses/ece4760/PIC32/target_board.html
Β * Target PIC: Β PIC32MX250F128B
Β *
Β * This template instantiates threads to communicate events from a Python
Β * toggle switches (checkbox), Sliders and general text input/putput
Β *
Β * Start the python script or this program in either order
Β * (The python text is included as a comment at the end of this file)
Β * Clicking the Dot Color checkbox modifies a graphic red/green dot
Β * The slider sets a cursor position on the TFT
Β * The DDS checkbox turns DDS ON/OFF
Β * Scrollig and clicking a Listbox entry will set the DDS waveform if DDS-ON
Β * Typing anything in the Text input line causes the PIC to echo it into the receive window.
Β * Β Typing a command of the form βf 400β will result in a 400 Hz sinewave at the DACA output if DDS-ON
Β * Β Typing a command of the form βv 1.25β will set that voltage at the DACA output if DDS-OFF
Β * Β Typing a command of the form βhβ will echo back the form of the other commands
Β * Checking the reset_enable, then clicking RESET PIC does the expected IF the circuit is connected
Β */
// =============================================
// NOTE!! β to use serial spawned functions
// you MUST EDIT config_1_3_2 to
// (1) uncomment the line β #define use_uart_serial
// (2) SET the baud rate to match the PC terminal
// =============================================
////////////////////////////////////
// clock AND protoThreads configure!
// You MUST check this file!
#includeΒ βconfig_1_3_2.hβ
// threading library
#includeΒ βpt_cornell_1_3_2_python.hβ
#includeΒ <math.h>
////////////////////////////////////
// graphics libraries
// SPI channel 1 connections to TFT
#includeΒ βtft_master.hβ
#includeΒ βtft_gfx.hβ
#includeΒ βvocoder.hβ
////////////////////////////////////
// Audio DAC ISR
// A-channel, 1x, active
#defineΒ DAC_config_chan_AΒ 0b0011000000000000
// B-channel, 1x, active
#defineΒ DAC_config_chan_BΒ 0b1011000000000000
volatileΒ unsignedΒ intΒ DAC_data_A,Β DAC_data_BΒ ;// output values
volatileΒ SpiChannelΒ spiChnΒ = SPI_CHANNEL2 ;Β // the SPI channel to use
volatileΒ intΒ spiClkDivΒ =Β 4Β ;Β // 10 MHz max speed for port expander!!
// sample frequency and clock frequency defines
#defineΒ CLOCK_SPDΒ 40000000
#defineΒ FsΒ 3000
// absolute value
#defineΒ ABS(X) ((X)Β >Β 0Β ?Β (X)Β :Β β(X))
// calculate appropriate index by looping samples
#defineΒ LOOP(i,Β offset,Β length) (i=(i+offset)%length)
// low-pass filter weight, using shifts to speed computation
#defineΒ alpha(x) ((x)Β βΒ ((x)Β >>Β 8))
// === outputs from python handler =============================================
// signals from the python handler thread to other threads
// These will be used with the prototreads PT_YIELD_UNTIL(pt, condition);
// to act as semaphores to the processing threads
charΒ new_stringΒ =Β 0;
charΒ new_sliderΒ =Β 0;
charΒ new_listΒ =Β 0;
charΒ new_toggleΒ =Β 0;
// identifiers and values of controls
charΒ toggle_id,Β toggle_valueΒ ;
// current slider
intΒ slider_id;
floatΒ slider_value;Β // value could be large
// current listbox
intΒ list_id,Β list_value;
// current string
charΒ receive_string[64];
// vocoder data structures and variables
charΒ keys[NUM_KEYS];
intΒ num_keysΒ =Β 0;
fix11_21Β inverseLUT[NUM_KEYS];
fix11_21Β prev_x[NUM_FILTERS][NUM_COEFFICIENTS];
fix11_21Β prev_y[NUM_FILTERS][NUM_COEFFICIENTS];
intΒ p_x_head[NUM_FILTERS];
intΒ p_y_head[NUM_FILTERS];
intΒ pc_x_head[NUM_FILTERS];
intΒ pc_y_head[NUM_FILTERS];
fix11_21Β prev_carrier_x[NUM_FILTERS][NUM_COEFFICIENTS];
fix11_21Β prev_carrier_y[NUM_FILTERS][NUM_COEFFICIENTS];
fix11_21Β lp_ysamp[NUM_FILTERS];
fix11_21Β lp_ysig[NUM_FILTERS];
volatileΒ fix11_21Β adc_data;
volatileΒ fix11_21Β current_amplitude;
intΒ carrier_indices[NUM_KEYS] = {0,0,0,0,0,0,0,0,0,0,0,0,0};
intΒ key_countΒ =Β 0;
charΒ new_adcΒ =Β 0;
intΒ profile_time;
fix11_21Β coefficients[NUM_FILTERS][2][NUM_COEFFICIENTS];
// === string input thread =====================================================
// process text from python
staticΒ PT_THREAD(protothread_python_string(structΒ pt *pt))
{
Β Β Β PT_BEGIN(pt);
Β Β Β //
Β Β Β whileΒ (1)
Β Β {
Β Β Β Β Β // wait for a new string from Python
Β Β Β Β Β PT_YIELD_UNTIL(pt,Β new_stringΒ ==Β 1);
Β Β Β Β Β new_stringΒ =Β 0;
Β Β }Β // END WHILE(1)
Β Β Β PT_END(pt);
}Β // thread python_string
// === Python serial thread ====================================================
// you should not need to change this thread UNLESS you add new control types
staticΒ PT_THREAD(protothread_serial(structΒ pt *pt))
{
Β Β Β PT_BEGIN(pt);
Β Β Β staticΒ charΒ junk;
Β Β Β //
Β Β Β //
Β Β Β whileΒ (1)
Β Β {
Β Β Β Β Β // There is no YIELD in this loop because there are
Β Β Β Β Β // YIELDS in the spawned threads that determine the
Β Β Β Β Β // execution rate while WAITING for machine input
Β Β Β Β Β // =============================================
Β Β Β Β Β // NOTE!! β to use serial spawned functions
Β Β Β Β Β // you MUST edit config_1_3_2 to
Β Β Β Β Β // (1) uncomment the line β #define use_uart_serial
Β Β Β Β Β // (2) SET the baud rate to match the PC terminal
Β Β Β Β Β // =============================================
Β Β Β Β Β // now wait for machine input from python
Β Β Β Β Β // Terminate on the usual <enter key>
Β Β Β Β Β PT_terminate_charΒ =Β β\rβ;
Β Β Β Β Β PT_terminate_countΒ =Β 0;
Β Β Β Β Β PT_terminate_timeΒ =Β 0;
Β Β Β Β Β // note that there will NO visual feedback using the following function
Β Β Β Β Β PT_SPAWN(pt, &pt_input,Β PT_GetMachineBuffer(&pt_input));
Β Β Β Β Β // Parse the string from Python
Β Β Β Β Β ifΒ (PT_term_buffer[0] ==Β βbβ)
Β Β Β Β {
Β Β Β Β Β Β Β // subtracting β0β converts ascii to binary for 1 character
Β Β Β Β }
Β Β Β Β Β // slider
Β Β Β Β Β ifΒ (PT_term_buffer[0] ==Β βsβ)
Β Β Β Β {
Β Β Β Β Β Β Β sscanf(PT_term_buffer,Β β%c %d %fβ, &junk, &slider_id, &slider_value);
Β Β Β Β Β Β Β new_sliderΒ =Β 1;
Β Β Β Β }
Β Β Β Β Β // toggle switch
Β Β Β Β Β ifΒ (PT_term_buffer[0]==βtβ){
Β Β Β Β Β Β Β new_toggleΒ =Β 1;
Β Β Β Β Β Β Β // subtracting β0β converts ascii to binary for 1 character
Β Β Β Β Β Β Β toggle_idΒ = (PT_term_buffer[1] βΒ β0β)*10Β + (PT_term_buffer[2] βΒ β0β);
Β Β Β Β Β Β Β toggle_valueΒ =Β PT_term_buffer[3] βΒ β0β;
Β Β Β Β }
Β Β Β Β Β // listbox
Β Β Β Β Β ifΒ (PT_term_buffer[0] ==Β βlβ)
Β Β Β Β {
Β Β Β Β Β Β Β new_listΒ =Β 1;
Β Β Β Β Β Β Β list_idΒ =Β PT_term_buffer[2] βΒ β0β;
Β Β Β Β Β Β Β list_valueΒ =Β PT_term_buffer[3] βΒ β0β;
Β Β Β Β Β Β Β //printf(β%d %dβ, list_id, list_value);
Β Β Β Β }
Β Β Β Β Β ifΒ (PT_term_buffer[0] ==Β βkβ)
Β Β Β Β {
Β Β Β Β Β Β Β intΒ key_indexΒ = (PT_term_buffer[3] βΒ β0β) *Β 10Β + (PT_term_buffer[4] βΒ β0β);
Β Β Β Β Β Β Β // set bool for key press to true
Β Β Β Β Β Β Β keys[key_index] =Β PT_term_buffer[5] ==Β βdβΒ ?Β 1Β :Β 0;
Β Β Β Β Β Β Β // count total number of keys
Β Β Β Β Β Β Β num_keysΒ +=Β PT_term_buffer[5] ==Β βdβΒ ?Β 1Β : β1;
Β Β Β Β }
Β Β Β Β Β // string from python input line
Β Β Β Β Β ifΒ (PT_term_buffer[0] ==Β β$β)
Β Β Β Β {
Β Β Β Β Β Β Β // signal parsing thread
Β Β Β Β Β Β Β new_stringΒ =Β 1;
Β Β Β Β Β Β Β // output to thread which parses the string
Β Β Β Β Β Β Β // while striping off the β$β
Β Β Β Β Β Β Β strcpy(receive_string,Β PT_term_bufferΒ +Β 1);
Β Β Β Β }
Β Β }Β // END WHILE(1)
Β Β Β PT_END(pt);
}Β // thread blink
// timer thread is used for debugging
staticΒ PT_THREAD(protothread_timer(structΒ pt *pt))
{
Β Β Β PT_BEGIN(pt);
Β Β Β mPORTASetBits(BIT_0); Β Β //Clear bits to ensure light is off.
Β Β Β mPORTASetPinsDigitalOut(BIT_0); Β Β //Set port as output
Β Β Β whileΒ (1)
Β Β {
Β Β Β Β Β // yield time 1 second
Β Β Β Β Β PT_YIELD_TIME_msec(1000);
Β Β Β Β Β // toggle the LED on the big board, heartbeat
Β Β Β Β Β mPORTAToggleBits(BIT_0);
Β Β Β Β Β // print quantities that would otherwise print too quickly
Β Β Β Β Β printf(βADC read: %d\nβ,Β adc_dataΒ >>Β 21);
Β Β Β Β Β printf(βcurrent amplitude: %d\nβ, (current_amplitude));
Β Β Β Β Β printf(βProfile time: %d\nβ,Β profile_time);
Β Β Β Β Β printf(βNum keys: %d\nβ,Β num_keys);
Β Β Β Β Β // !!!! NEVER exit while !!!!
Β Β }Β // END WHILE(1)
Β Β Β PT_END(pt);
}
#defineΒ circ_index(i,Β head) ((((head)Β +Β i)Β %Β NUM_COEFFICIENTS))
// apply butterworth IIR filter to sample xx
inlineΒ fix11_21Β cButter(fix11_21Β xx,Β fix11_21Β filter_coefficients[2][NUM_COEFFICIENTS],Β fix11_21Β prev_x[NUM_COEFFICIENTS],Β fix11_21Β prev_y[NUM_COEFFICIENTS],Β int*Β prev_x_head,Β int*Β prev_y_head)
{
Β Β Β fix11_21*Β bΒ =Β filter_coefficients[0];
Β Β Β fix11_21*Β aΒ =Β filter_coefficients[1];
Β Β Β fix11_21Β yyΒ =Β 0;
Β Β Β intΒ k;
Β Β Β // circular buffer implementation for saving history
Β Β *prev_x_headΒ = (β(*prev_x_head) <Β 0) ?Β NUM_COEFFICIENTSΒ βΒ 1: *prev_x_head;
Β Β *prev_y_headΒ = (β(*prev_y_head) <Β 0) ?Β NUM_COEFFICIENTSΒ βΒ 1: *prev_y_head;
Β Β Β prev_x[*prev_x_head] =Β xx;
Β Β Β // for(k = 0; k < NUM_COEFFICIENTS; k++)
Β Β Β // {
Β Β Β // Β Β yy += multfix11_21(b[k], prev_x[filter_i][k]);
Β Β Β // }
Β Β
Β Β Β // one-liner implementing commented loop which takes advantage of symmetry of numerator coefficients
Β Β Β // this reduces the number of multiplications required
Β Β Β yyΒ =Β multfix11_21(b[0], (prev_x[circ_index(0, *prev_x_head)] β (prev_x[circ_index(2, *prev_x_head)]<<1) +Β prev_x[circ_index(4, *prev_x_head)]));
Β Β Β for(kΒ =Β 1;Β kΒ <Β NUM_COEFFICIENTS;Β k++)
Β Β {
Β Β Β Β Β yyΒ -=Β multfix11_21(a[k],Β prev_y[circ_index(k, *prev_y_head)]);
Β Β }
Β Β Β prev_y[*prev_y_head] =Β yy;
Β Β Β returnΒ yy;
}
// apply low pass filter to sample x with weight alpha
inlineΒ fix11_21Β lowpass(fix11_21Β x,Β fix11_21*Β lp_y1)
{
Β Β Β fix11_21Β lp_yyΒ =Β xΒ +Β alpha(*lp_y1Β βΒ x);
Β Β *lp_y1Β =Β lp_yy;
Β Β Β returnΒ lp_yy;
}
voidΒ __ISR(_TIMER_3_VECTOR,Β ipl2)Β Timer3Handler(void)
{
Β Β Β intΒ junk;
Β Β Β // you MUST clear the ISR flag
Β Β Β mT3ClearIntFlag();
Β Β Β // read in new audio input
Β Β adc_data =Β int2fix11_21(ReadADC10(0)); Β Β // read the result of conversion from the idle buffer
Β Β new_adc =Β 1;
Β Β Β // produce previous audio output
Β Β DAC_data_A = current_amplitude;
Β Β Β
Β Β Β // reset spi mode to avoid conflict with expander
Β Β Β SPI_Mode16();
Β Β Β // DAC-A CS low to start transaction
Β Β Β mPORTBClearBits(BIT_4);Β // start transaction
Β Β Β // write to spi2
Β Β Β WriteSPI2(DAC_config_chan_AΒ | (DAC_data_A &Β 0xfff) );
Β Β Β // test for done
Β Β Β whileΒ (SPI2STATbits.SPIBUSY);Β // wait for end of transaction
Β Β Β // MUST read to clear buffer for port expander elsewhere in code
Β Β junk =Β ReadSPI2();
Β Β Β // CS high
Β Β Β mPORTBSetBits(BIT_4);Β // end transaction
}
// vocoder thread
staticΒ PT_THREAD(protothread_vocode(structΒ pt *pt))
{
Β Β Β PT_BEGIN(pt);
Β Β Β while(1)
Β Β {
Β Β Β Β Β PT_YIELD_UNTIL(pt,Β new_adcΒ ==Β 1);
Β Β Β Β Β new_adcΒ =Β 0;
Β Β Β Β Β fix11_21Β adc_readΒ =Β adc_data;
Β Β Β Β Β intΒ i,Β j;
Β Β Β Β Β // reset timer for profiling
Β Β Β Β Β WriteTimer4(0);
Β Β Β Β Β // Apply IIR filter to the most recent ADC read
Β Β Β Β Β // Assume filter coefficients are in [num_filter][b, a][term] array
Β Β Β Β Β fix11_21Β yΒ =Β 0;
Β Β Β Β Β key_countΒ =Β 1;
Β Β Β Β Β fix11_21Β sigΒ =Β 0;
Β Β Β Β Β for(jΒ =Β 0;Β jΒ <Β NUM_KEYS;Β j++) {
Β Β Β Β Β Β Β ifΒ (keys[j] ==Β 1){
Β Β Β Β Β Β Β Β Β sigΒ +=Β multfix11_21(carrier[LOOP(carrier_indices[j],Β offsets[j],Β CARRIER_SIGNAL_LENGTH)],Β inverseLUT[num_keys]);
Β Β Β Β Β Β }
Β Β Β Β }
Β Β Β Β Β // for each filter,
Β Β Β Β Β // condition the modulation signal by: applying the butterworth filter and find the magnitude by putting it through a low pass
Β Β Β Β Β // condition the carrier signal by: applying the butterworth filter (so that only the frequencies in the pass band are modulated), and smooth it by putting it through a low pass
Β Β Β Β Β for(iΒ =Β 0;Β iΒ <Β NUM_FILTERS;Β i++)
Β Β Β Β {
Β Β Β Β Β Β Β fix11_21Β sampleΒ =Β cButter(adc_read,Β coefficients[i],Β prev_x[i],Β prev_y[i], &(p_x_head[i]), &(p_y_head[i]));
Β Β Β Β Β Β Β fix11_21Β amp_sampΒ =Β lowpass(ABS(sample), &(lp_ysamp[i]));
Β Β Β Β Β Β Β fix11_21Β filtered_sigΒ =Β cButter(sig,Β coefficients[i],Β prev_carrier_x[i],Β prev_carrier_y[i], &(pc_x_head[i]), &(pc_y_head[i]));
Β Β Β Β Β Β Β fix11_21Β amp_sigΒ =Β lowpass(ABS(filtered_sig), &(lp_ysig[i]));
Β Β Β Β Β Β Β yΒ +=Β amp_sigΒ !=Β 0Β ?Β multfix11_21(filtered_sig,Β divfix11_21(amp_samp,Β amp_sig)) :Β 0;
Β Β Β Β }
Β Β Β Β
Β Β Β Β Β // scale y and shift so itβs centered
Β Β Β Β Β current_amplitudeΒ = (int)((yΒ >>Β 19) +Β 2048);
Β Β Β Β Β // save time it took to calculate output for 1 sample
Β Β Β Β Β profile_timeΒ =Β ReadTimer4();
Β Β }
Β Β Β PT_END(pt);
}
// === Main Β ======================================================
voidΒ main(void)
{
Β Β Β intΒ i;
Β Β Β intΒ j;
Β Β Β intΒ k;
Β Β Β // convert float coefficients to fixed point
Β Β Β forΒ (iΒ =Β 0;Β iΒ <Β NUM_FILTERS;Β i++) {
Β Β Β Β Β forΒ (jΒ =Β 0;Β jΒ <Β 2;Β j++) {
Β Β Β Β Β Β Β forΒ (kΒ =Β 0;Β kΒ <Β NUM_COEFFICIENTS;Β k++) {
Β Β Β Β Β Β Β Β Β coefficients[i][j][k] =Β float2fix11_21(float_coefficients[i][j][k]);
Β Β Β Β Β Β }
Β Β Β Β }
Β Β }
Β Β Β // convert inverse LUT to fixed point
Β Β Β forΒ (iΒ =Β 0;Β iΒ <Β NUM_KEYS;Β i++) {
Β Β Β Β Β inverseLUT[i] =Β float2fix11_21(float_inverseLUT[i]);
Β Β }
Β Β ANSELA =Β 0;
Β Β ANSELB =Β 0;
Β Β Β // ======= ADC timer interrupt ===========
Β Β Β OpenTimer3(T3_ON | T3_SOURCE_INT | T3_PS_1_1,Β CLOCK_SPD/Fs);
Β Β Β ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_2);Β // configures Timer3 interrupt
Β Β Β mT3ClearIntFlag();
Β Β
Β Β Β OpenTimer4(T4_ON | T4_SOURCE_INT | T4_PS_1_1,Β 0xffff);
Β Β Β // ========== set up ADC ============
Β Β Β // configure and enable the ADC
Β Β Β CloseADC10();Β // ensure the ADC is off before setting the configuration
Β Β Β // define setup parameters for OpenADC10
Β Β Β // Turn module on | ouput in integer | trigger mode auto | enable autosample
Β Β Β // ADC_CLK_AUTO β Internal counter ends sampling and starts conversion (Auto convert)
Β Β Β // ADC_AUTO_SAMPLING_ON β Sampling begins immediately after last conversion completes; SAMP bit is automatically set
Β Β Β // ADC_AUTO_SAMPLING_OFF β Sampling begins with AcquireADC10();
Β Β Β #defineΒ PARAM1 Β ADC_FORMAT_INTG16Β |Β ADC_CLK_TMRΒ |Β ADC_AUTO_SAMPLING_ONΒ //
Β Β Β // define setup parameters for OpenADC10
Β Β Β // ADC ref external Β | disable offset test | disable scan mode | do 1 sample | use single buf | alternate mode off
Β Β Β #defineΒ PARAM2 Β ADC_VREF_AVDD_AVSSΒ |Β ADC_OFFSET_CAL_DISABLEΒ |Β ADC_SCAN_OFFΒ |Β ADC_SAMPLES_PER_INT_1Β |Β ADC_ALT_BUF_OFFΒ |Β ADC_ALT_INPUT_OFF
Β Β Β //
Β Β Β // Define setup parameters for OpenADC10
Β Β Β // for a 40 MHz PB clock rate
Β Β Β // use peripherial bus clock | set sample time | set ADC clock divider
Β Β Β // ADC_CONV_CLK_Tcy should work at 40 MHz.
Β Β Β // ADC_SAMPLE_TIME_6 seems to work with a source resistance < 1kohm
Β Β Β #defineΒ PARAM3 ADC_CONV_CLK_PBΒ |Β ADC_SAMPLE_TIME_6Β |Β ADC_CONV_CLK_TcyΒ //ADC_SAMPLE_TIME_5| ADC_CONV_CLK_Tcy2
Β Β Β // define setup parameters for OpenADC10
Β Β Β // set AN11 and Β as analog inputs
Β Β Β #defineΒ PARAM4 Β ENABLE_AN11_ANAΒ // pin 24
Β Β Β // define setup parameters for OpenADC10
Β Β Β // do not assign channels to scan
Β Β Β #defineΒ PARAM5 Β SKIP_SCAN_ALL
Β Β Β // use ground as neg ref for A | use AN11 for input A Β Β
Β Β Β // configure to sample AN11
Β Β Β SetChanADC10(ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN11);
Β Β Β OpenADC10(PARAM1,Β PARAM2,Β PARAM3,Β PARAM4,Β PARAM5);Β // configure ADC using the parameters defined above
Β Β Β EnableADC10();Β // Enable the ADC
Β Β ///////////// DAC setup
Β Β Β // SCK2 is pin 26
Β Β Β // SDO2 (MOSI) is in PPS output group 2, could be connected to RB5 which is pin 14
Β Β Β PPSOutput(2, RPB5, SDO2);
Β Β Β // control CS for DAC
Β Β Β mPORTBSetPinsDigitalOut(BIT_4);
Β Β Β mPORTBSetBits(BIT_4);
Β Β Β // divide Fpb by 2, configure the I/O ports. Not using SS in this example
Β Β Β // 16 bit transfer CKP=1 CKE=1
Β Β Β // possibles SPI_OPEN_CKP_HIGH; Β SPI_OPEN_SMP_END; Β SPI_OPEN_CKE_REV
Β Β Β // For any given peripherial, you will need to match these
Β Β Β // clk divider set to 4 for 10 MHz
Β Β Β SpiChnOpen(SPI_CHANNEL2, SPI_OPEN_ON | SPI_OPEN_MODE16 | SPI_OPEN_MSTEN | SPI_OPEN_CKE_REV ,Β 4);
Β Β // end DAC setup
Β Β Β // === setup system wide interrupts Β ========
Β Β Β INTEnableSystemMultiVectoredInt();
Β Β Β // === config threads ========================
Β Β Β PT_setup();
Β Β Β // === identify the threads to the scheduler =====
Β Β Β // add the thread function pointers to be scheduled
Β Β Β // β Two parameters: function_name and rate. β
Β Β Β // rate=0 fastest, rate=1 half, rate=2 quarter, rate=3 eighth, rate=4 sixteenth,
Β Β Β // rate=5 or greater DISABLE thread!
Β Β Β pt_add(protothread_serial,Β 0);
Β Β Β pt_add(protothread_python_string,Β 0);
Β Β Β pt_add(protothread_timer,Β 0);
Β Β Β pt_add(protothread_vocode,Β 0);
Β Β Β // === initalize the scheduler ====================
Β Β Β PT_INIT(&pt_sched);
Β Β Β // >>> CHOOSE the scheduler method: <<<
Β Β Β // (1)
Β Β Β // SCHED_ROUND_ROBIN just cycles thru all defined threads
Β Β Β //pt_sched_method = SCHED_ROUND_ROBIN ;
Β Β Β // NOTE the controller must run in SCHED_ROUND_ROBIN mode
Β Β Β // ALSO note that the scheduler is modified to cpy a char
Β Β Β // from uart1 to uart2 for the controller
Β Β Β pt_sched_methodΒ =Β SCHED_ROUND_ROBIN;
Β Β Β // === scheduler thread =======================
Β Β Β // scheduler never exits
Β Β Β PT_SCHEDULE(protothread_sched(&pt_sched));
Β Β Β // ============================================
}Β // main
// === end Β ======================================================
Schematics
Source: ECE 4760: Final Project Report