jg992, nl392

Gao, Lin

ECE 4760: Final Project Report

Jonathan Gao (jg992), Nicole Lin (nl392)

Monday Lab

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).

Figure 1. Block diagram demonstrating high-level system components. The modulation signal is sampled by the ADC, and then goes through the filter banks so we can determine the magnitude of the signal in each filter’s frequency range. The synthesized carrier signal (which depends on which keys are pressed) is also filtered, with magnitudes corresponding to the frequency bin powers. The result is then output to the DAC.

Figure 2. Graph showing how each frequency in human voice affects speech intelligibility. 95% of speech can be determined with frequencies at the 4 kHz band and below, making a sampling frequency of 8 kHz a good choice. Reducing the sampling frequency to 4 kHz knocks this down to 70%. Source: https://www.dpamicrophones.com/mic-university/facts-about-speech-intelligibility

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.

Figure 3. Linear filter comparison. Characteristics to note include the pass band ripple, stop band ripple, roll off speed, and overshoot. The butterworth filter has the flattest passband at the expense of having a slower roll-off.

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.

Figure 4. First-order butterworth filter response for the frequency ranges described in the report. These coefficients were generated using Python’s scipy.signal.iirfilter function.

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.

Figure 5. Python GUI. The GUI shows serial data from the PIC, and allows the user to send keyboard inputs to the PIC.

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.

Figure 6. Piano keys with the respective mapped keyboard keys. Source from [4]

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.

Figure 7. State diagram of the C program flow.

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);
ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_2);
// configures Timer3 interrupt
mT3ClearIntFlag();

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
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

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
new_adc =
1;

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]));
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;

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)
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;

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;
#define multfix11_21(a,b) ((fix11_21)(((( signed long long)(a))*(( signed long long)(b)))>>21)) //multiply two fixed 11: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))))

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');
keys[key_index] = PT_term_buffer[
5] == 'd' ? 1 : 0;
num_keys += PT_term_buffer[
5] == 'd' ? 1 : -1;

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++) {
 
if (keys[j] == 1){
   sig += multfix11_21(carrier[LOOP(carrier_indices[j], offsets[j], CARRIER_SIGNAL_LENGTH)], inverseLUT[num_keys]);
   }
}

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.

Figure 8. Schematic of audio input circuitry.

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.

Figure 9. Schematic of DAC circuitry.

Figure 10. Schematic of audio output circuitry.

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.

Figure 11. A diagram showing the effects of aliasing due to an insufficient sampling rate. Each of the two high frequency signals gives us a lower frequency at a lower multiple due to the smaller sampling rate not capturing the higher frequency oscillations.

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

 * control interface. The python GUI supports push buttons,

 * 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 on the LED button turns on the on-board LED

 * Clicking on the Clear LCD button clears the TFT

 * 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_button = 0;

char new_slider = 0;

char new_list = 0;

char new_toggle = 0;

// identifiers and values of controls

// curent button

char button_id, button_value;

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

        // There can be toggle switch, button, slider, and string events

        // pushbutton

        if (PT_term_buffer[0] == 'b')

        {

            // signal the button thread

            new_button = 1;

            // subtracting '0' converts ascii to binary for 1 character

            button_id = (PT_term_buffer[1] - '0') * 10 + (PT_term_buffer[2] - '0');

            button_value = PT_term_buffer[3] - '0';

        }

        // 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'){

            // signal the button thread

            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

BOM and project cost

PIC32 microcontroller with Big Board        $0

Individual contributions

For the most part we pair programmed using VS Code’s Live Share feature.

Nicole: Filter prototyping in Jupyter notebook, first draft python GUI, fixed point implementation, debugging, normalizing and importing samples for carrier signal

Jon: Updated python GUI + keyboard events, filter functions in C, fixed point implementation, debugging, software organization


References

[1]        “PIC32 Peripheral Library.” https://www.microchip.com/SWLibraryWeb/product.aspx?product=PIC32%20Peripheral%20Library (accessed May 17, 2021).

[2]        “Protothreads - Lightweight, Stackless Threads in C.” http://dunkels.com/adam/pt/ (accessed May 17, 2021).

[3]        “MPLAB® X IDE | Microchip Technology.” https://www.microchip.com/en-us/development-tools-tools-and-software/mplab-x-ide (accessed May 17, 2021).

[4]        by, “Printablee Piano Keyboard Chart Blank Worksheet Worksheets Pdf Letter And Numbers For Many Keys – Jaimie Bleck.” http://magic756.net/ (accessed May 18, 2021).

[5]        “ECE4760 PIC32 DSP.” https://people.ece.cornell.edu/land/courses/ece4760/PIC32/index_DSP.html (accessed Apr. 12, 2021).

[6]        “DSP for GCC.” https://people.ece.cornell.edu/land/courses/ece4760/Math/avrDSP.htm (accessed Apr. 12, 2021).