• I am Back

    agp.cooper03/15/2017 at 13:04 0 comments

    I am Back

    I have been on holidays and busy working on a couple of other projects.

    Anyway I fired up the CNC and made three more wooden slices for the modem case.

    Just one more wooden slice and the strip-board to go.

    I have to have a look at the strip-board layout and how I am going to route the USB cable.

    Also some code to communicate to the host computer and to set the modem as originate or answer.

    The other problem is that I will need to make a second modem to talk to!

    The Modem Box

    Here is the completed modem box (top view):

    No iPhone:

    Bottom view:


    So work remaining is to design the strip-board, the USB cable route and perhaps a varnish.


  • Bell 103A2 Modem Debug

    agp.cooper02/13/2017 at 14:34 1 comment

    Loopback Test

    I had some problems with the audio loopback so I had to drop back to a direct loopback.

    Here is the signal from the first stage lowpass:

    Not pretty but functional. Some noise is probably a good idea for testing and optimising.

    Here is the demodulator output:

    Basically identical results for Answer or Originate configuration. What is not shown here is the decoder jitter.

    Baud Rate Generator

    The jitter associated with the baud rate generator was the main problem. It was missing the timeout flag. Fixed. It now only misses the occasion interrupt tick from the sample clock.

    Demodulator Jitter

    The jitter associated with demodulator is likely to be jitter from the sine wave generator and/or from the phase transition. Suppressing the high frequency noise by adding an additional low pass had no effect:

    The only real hint is that jitter is much worse (x4?) with the higher frequencies suggesting jitter is from the sine wave generator.

    Turned off the binary signal (i.e. a single tone) and the jitter is clearly visible and in tune with the demodulator jitter. Here is the signal, even in this image you can see this signal moves around:

    Bandpass Filters

    Before I found the baud rate generator problem I reduced the band pass filter Q to good effect. After minimising the remaining jitter I will have to rework the band pass filters to see if I can increase the Q as I think suppressing the opposite channel still has merit.

    Sine Wave Generator Investigations

    Tried a 62.5kHz Fast PWM, 32 bit maths and a 256 sine wave lookup table (and variations in between). The sine wave looks great but slowly oscillates. The demodulator hates it! After double checking I find the frequency is off which means the Arduino cannot keep up (even with just the sine wave generator running). Back to 31.37 kHz.

    Now I was caught out in that I thought the Phase Correct PWM frequency is half of the Fast PWM frequency of 62500 Hz. It is not! It is actually 31372.5 Hz. It pays to check the manual.

    I have come to the conclusion that the jitter is mostly due to background interrupts by the Arduino bootloader. This probably means that I am losing interrupt ticks. I did drop the PWM to 7813 Hz to have a look, but the wave form was pretty poor:

    Data In Versus Data Out

    Here is the Data In (blue) versus Data Out (yellow). Note that Data Out is delayed by about a bit:

    You might say what jitter? That was the low channel (1170 Hz), the high channel (2125 Hz) is not so good:

    In reality the background jitter is just like a noise floor. It just sets a minimum for degradation by the telephone system. I could spend weeks investigating jitter and trying solutions but I feel I have a fair solution right now so I will move on.

    Audio Loopback

    Now that I think I have the code working properly, here is the results of the audio (speaker and microphone) loopback for the low channel:

    The signal looks to be all over the place but it detects okay with the usual jitter.

    Here is the high channel:

    Detection is good with the speaker to about 30 cm away. Without the speaker connected you get the usual spike chatter.

    The microphone gain is far too high, someone talking in the room is stronger than the signal. But the next circuit board iteration has that fixed.


    So lots of progress today! A working modem!


  • Yet Another Project Log! Magic Numbers

    agp.cooper02/11/2017 at 09:17 0 comments

    The Search for Magic Numbers

    I have been searching for magic numbers. Yes I use Excel to help (i.e. goal seek, solver, macros (mostly brute-force) and data tables).

    The Sample Frequency Search

    Basically matching up the timer divider (i.e. Fsample = 16,000,000/64/n) and the delay number to find a correlation null at the centre frequency. We want a sample frequency that is between 7000 Hz and 10000 Hz to avoid aliasing within the telephone bandwidth and enough time for processing the signal between timer ticks. The correlation null need not be exactly zero. Here is the table for the 1170 Hz centre frequency:

    The frequency number (n) is at the top and the delay number (d) is on the left. The band is from 175 Hz to 250 Hz bandwidth. I have selected a cell near the middle (sample frequency 8069 Hz and a delay of 19). I chose this cell over the others as the table for the 12125 Hz centre frequency has a matching sample frequency (delay 18):

    Using the same sample frequency simplifies the low pass filter coding.

    The Search for the Perfect Bandpass Filter

    Here I used a brute-force Excel macro. I decide to use three stages and wanted a pretty close match in performance for the two centre frequencies. Here are the coefficients that I found:

    Modem Answer Originate Units
    Fsample 8069 8069 Hz
    Fcentre 1170 2225 Hz
    Divisor 8 8
    Q 1.78 2.16
    Gain 1.3 1.3
    A0 2 2
    A1 0 0
    A2 -2 -2
    B1 8 -1
    B2 -5 -5
    Other channel suppression -29 -36 dB

    When considering filter coefficients you must avoid division by using arithmetic shift right. Therefore the divisor must be a power of 2. A low divisor reduces the risk of integer overflow.

    These filters should reject the other channel by about 30dB. This should be enough. Here is the answer modem (i.e. Fc = 1170 Hz) calculated response:

    And the originate modem (i.e. Fc = 2125 Hz) calculated response:

    Note the alias above 5000 Hz.

    The Magic Biquad Frequency Analyser

    You may have noticed I have been using a really cool graphs of the bandpass frequency response. Here is where I got it from:

    The guy/gal who worked this out deserves a medal!

    A BandPass Magic Number Generator

    To date I have been using a brute-force (i.e. a dumb grid search) macro to find the integer parameters for my bandpass filters. If you don't know, integer problems are very hard (actually NP Complete). While it works, it is slow and being a bit of a perfectionist (it a genetic disorder) I have eventually got a quick spreadsheet method working. While it finds the best solution available, determining the quality of that solution (in practice the filter Q) is a bit difficult (there is a way but even a perfectionist can say why bother as it is a case of "take it" or "leave it" for the filter). Here is what it looks like:

    I used biquad frequency response as a check:

    You may be able to see that the filter Q is closer to 3.6 than the design of 2.2.

    I have posted the spreadsheet to the project if your interested.

    Modem Simulations

    Finally here is the answer modem simulation (the originate modem simulation is similar):


    • The blue is the input data and the red the output data.
    • The green signal is after the three stage bandpass (the input signal was 1022 pp).
    • The brown signal is after the lowpass filter.


    Update the Arduino code the test. If all good then finish off the case.


  • Generating Sine Waves

    agp.cooper02/09/2017 at 23:55 0 comments

    Generating Sine Waves

    Who thought this would be hard?

    I have spent a week trying to work this out. Here is the pseudo code so far:

    Calculate the Mark and Space ratios:

    • A= int(Fsample/Fmark+0.5)
    • B= int(Fsample/Fpace+0.5)

    Find the lowest common multiple N of A and B:

    • N = LCM(A,B)

    Where N is the sine (iSin[]) lookup array size.

    To generated the sine wave step through the array using Phase:

    • Phase=Phase +N/A, for the mark frequency

    Note: B=N/A


    • Phase=Phase +B


    • Phase=Phase +A, for the space frequency

    The Phase needs to roll back to the start on overflow:

    • if (Phase>=N) then Phase=Phase-N

    The sine wave is:

    • Sine=iSin[Phase]

    To reduce the sine look up array size by a constant (C) we can divide the Phase by the constant (C):

    • Sine=iSin[Phase/C]


    • Sine=iSin[Phase>>M], as the maths is much faster

    The sample frequency is restricted and depends on the Arduino clock (16 MHz), the pre-scaler (timer dependent) and the PWM type.

    So I have spent a day trying different combinations of Fsample and M to minimise the array size and the error. Nothing great found!


    I thinks I need help (at least my partner thinks so)!

    I found a paper (http://www.analog.com/static/imported-files/tutorials/MT-085.pdf) that although a bit complicated, shows a way out of this mess:

    Set N to a power of 2, say 65536 (an unsigned int):

    • B=65536*Fmark/Fsample
    • A=65536*Fspace/Fsample

    Then phase is:

    • Phase=Phase+B


    • Phase=Phase+A

    Choose a sine array size that is a power of 2 , say 64.

    • Sine=iSin[Phase>>(16-6)]


    • Sine=iSin[Phase>>10]

      Phase rollover is implicit with an unsigned int.

      Here is the code for the ISR:

      // TRANSMIT: 
      //   Phase Correct PWM frequency 31250 Hz
      //   Originate modem Mark  frequency    1270 Hz (=2244) 
      //   Originate modem Space frequency    1070 Hz (=2663) 
      //   Answer modem    Mark  frequency    2225 Hz (=4666) 
      //   Answer modem    Space frequency    2025 Hz (=4247) 
      const byte iSin[64] = {
        128,116,103, 91, 79, 68, 57, 47,
         38, 30, 22, 16, 11,  6,  3,  2,
          1,  2,  3,  6, 11, 16, 22, 30,
         38, 47, 57, 68, 79, 91,103,116
      volatile byte DataOut=0;
      ISR(TIMER2_OVF_vect) {
        static unsigned int phase=0;
        OCR2A = iSin[(phase>>10)]; // Output on D11
        if (true) { // Set true for Originate Modem
          if (DataOut==0) {
            phase+=2244;             // Fspace (Originate modem)
          } else {
            phase+=2663;             // Fmark (Originate modem)
        } else {
          if (DataOut==0) {
            phase+=4247;             // Fspace (Answer modem)
          } else {
            phase+=4666;             // Fmark (Answer modem)

      Now is that not sweet code!


      I used Phase Correct PWM instead of Fast PWM as it generates less interrupts rather than the phase correct feature.

      Final note, don't put the iSin array inside the ISR like I did! It took ages to workout why the PWM was off frequency!


    • Backward Channel Considerations

      agp.cooper02/01/2017 at 11:28 0 comments

      The Forward Channel

      I have simulated many options but I have not really done much better than the current setup. The backward channel without any additional filtering is suppressed nearly 20 dB. Really I have to wait until I physically test the modem with the presence of the backward channel before spending too much more time.

      The Backward Channel

      The backward channel is 387 Hz (space) and 487 Hz (mark). If I lowpass the signal (e.g. 585 Hz) and then down sample to 3300 Hz (from 13200 Hz) then the existing modem code will work fine for backward channel. The main problem is that the 2200 Hz frequency is aliased as 500 Hz. So I will need a good lowpass filter before the down sampling.

      More thought is required.

      Filter Madness

      Spent a lot of time playing with filter parameters to avoid proper division (can only use arithmetic shift right). Looking at cascading single pole filters. Easier to design, numerically efficient and works more or less the same. Here is a 5 single pole versus the current two pole lowpass:

      Code for the 558 Hz 2 pole lowpass:

      • LP0=(S0+S1+S1+S2+41*LP1-13*LP2)>>5;
      • About 7 us.

      And for the 5 single pole version:

      • A0=(S0+A1)>>1;
      • B0=(A0+B1)>>1;
      • C0=(B0+C1)>>1;
      • D0=(C0+D1)>>1;
      • E0=(D0+E1)>>1;
      • About 6 us.

      So the five single poles works better and is faster!

      Modem Output

      If I want to configure the modem for both forward and backward output then I will need to review the output filter. One option is to increase the number of steps for the DAC for the backward channel.

      More thought is required.

      More Code

      Rewrote the code so the the modem can be send mode or answer mode. I have not tested it yet but I need to consider the digital to analog conversion (DAC) and the output lowpass filter. The question is do I really need to try so hard to filter out the DAC quantization. Here is the what I am thinking:

      At 2 bit 2200 Hz is fine:

      And at 1200 Hz the wave form is still okay:

      But at 387 Hz:

      This will probably not work will (but I have not tried).

      But if I use three bit, the wave form is greatly improved:

      So perhaps 4 bit is the way to go. The advantage of the above circuit is that the amplitude does not vary very much and the power level is probably about right (125 uW) but can be increased in necessary.

      Four Bit Version

      Here is a four bit version showing 387 Hz and 2200 Hz:

      With the four bit version the resistor ladder network does not have to compensate for the lack of bits. The 25 R resistors are the uP source impedance. The power level is about 0.1 mW which will probably need to be scaled back.

      PWM Check

      Just to double check, I reconsidered PWM. First the ripple was about the same for the same RC values using a PWM frequency of 31.25 kHz for only the 387 Hz case. However, ripple frequency for the PWM much higher will present as a 4850 Hz alias for the answer modem (i.e. 2200/1200 Hz) and a 1750 Hz alias for the send modem (i.e. 487/387 Hz) so will not present a problem (if any gets through the phone line filters). For the answer modem the sensitivity to the 4850 Hz signal is attenuated about 20 dB (the attenuation is similar for the send modem). So the PWM option will work as well.

      Now at this time you may be wondering why I did not go with PWM in the first place? Well basically I could not model the PWM frequency affect on the modem response then!

      I like simple so back to PWM:

      The PWM filter works for low frequencies but the ISR generates a square wave for 2.2kHz. Pretty ugly. Added another capacitor across the speaker to clean it up. Looks more like a triangle wave but good enough. Here is the PWM circuit:

      AM Demodulator

      I had a play with the decoder and reworked it as an AM demodulator:

      If I wanted to create my own protocol I could mix binary FSK with binary ASK!

      Bell 103A Work

      The first observation is that there are a number of configurations that need to be tested and it is rather a headache! First is to determine suitable sampling rates for the originate and answer decoders. Integer multiplies work best and the sample rates determined were: 22 kHz (2200/2000 Hz)...

      Read more »

    • A Modem Case

      agp.cooper01/29/2017 at 12:55 0 comments

      A Modem Case

      Spent the day designing a case for the modem. Basically a piece of 18 mm thick MDF.

      I chose MDF as it has a soft edge when cut and should suit this application. The design consists of a top layer for the iPhone and mounts for the microphone and speaker. The second layer (to do) will hold the electronics etc. The iPhone will be fully below the top of the MDF so that the modem case can have a lid. Here is the top layer:

      This morning I backed out of the "carved" modem case and redesigned a plywood version:

      Th disks are temporary feet.

      Here are the cut pieces:

      And assembled with the microphone and speaker in place (to be glued later):

      And the iPhone happily sitting on top:

      Now to design the electronics compartment. The simplest power supply and serial interface is to use the Arduino/Nano USB plug and a USB cable. I will also need a switch (on the base) for send or receive mode.

      Half duplex means you need two modems and iPhones on each end (unless I can get the back channel to work).

      Testing Speakers

      Even though I have made the top of the case for the small speaker I had not actually tested the speaker. I assumed that the smaller speaker with less inertial would be better - wrong!

      Here is the small (26.7 mm diameter) speaker signal as recorded by the Nano:

      Looks good except for the AM modulation. Here is the signal after the bandpass:

      Looks even better except for the AM modulations. Here is the signal after the lowpass:

      See how the AM modulation upsets the decode and in fact the decode fails (repeatedly at this point). Here the medium (39.5 mm) speaker signal:

      It looks worse but look at the signal after the bandpass:

      It is pretty good. Here is the signal after the lowpass:

      No problems. All of the above is repeatable. No difference with a Zobel network and no hint of issues when measuring the speaker terminals.

      So I will have to rework the case for the larger speaker.


      I have some 6.4 mm thick plywood in the shed so I will cut the electronics enclosure and the base tomorrow. I will cut the strip-board the same size as the other pieces and sandwich it near the base.

      I don't have bolts long enough for the complete sandwich pile but that can be fixed later.

      Designed the rest of the case. Decided to glue the top sandwiches and conceal the bolts for the bottom sandwiches.


      Cheap Chinese CNC Machine

      I have a cheap Chinese CNC machine, so I can make neat little wooden objects (such as the modem case) but I can tell you these machines are hard to use and are very slow:

      • They overheat (the heat-sinks for the drivers are not sufficient for continuous operation).
      • The cables break after a short while.
      • They are not rigid enough to go fast.
      • The USB driver, USB controller or driver interface occasionally stops working.
      • Even if the driver power switch is off the spindle motor is still live!
      • The table is not level.
      • They don't come with sensible instructions are usage recommendations.

      On the user side:

      • Makes design mistakes.
      • Does not properly secure the work piece.

      So tonight I had one success out of three attempts. Not happy! I will have another go tomorrow, five pieces remain. Here is the stack so far:

      I have re-cut the speaker hole to fit the 40 mm diameter speaker and added a 6.4 mm thick cover to hide the assembly bolts. The iPhone will now sit just below the top of the case.

      Speaker Tests

      I tested the modem at 1200/2200 Hz and not too bad.

      Tested the modem at 400/500 Hz and evidence of strong AM modulation upsetting the demodulator:

      I suppose it is too much to ask for a speaker not to resonated at any frequency of interest. Not keen on a two speaker design.

      I wonder if paper cone speakers are better? I will have to buy a couple and try them.

      I suspect stopping the speaker from resonating may be a bit of an ask so I need to look at suppressing AM modulation in software or going directly to a FM discriminator. Looking at he above, it looks like close to 100% AM modulation, that may be difficult to remove.

      Thoughts on Speakers

      Unsoldered a small paper speaker from my 2 transistor...

      Read more »

    • Trial and Error

      agp.cooper01/25/2017 at 00:54 0 comments

      Trial and Error

      Optimising the code is tricky as there are so many parameters. One approach is to extract the data from the Arduino and model the code in Excel. Once the Excel model faithfully mirrors the Arduino the the parameters can be tested. Here are some examples (cut down to fit the Hackaday webpage width):

      First the input signal recorded from the Arduino (note the pre-amplifier bias shift):

      Now with the bias removed:

      Now mixed:

      Now after the LP filter (and this still amazing me):

      Now with the DC bias removed:

      Now after non-return to zero detection:

      You will note that the out put data is delayed by about 1 bit and the duty cycle is somewhat jittery, That is because the signal is 100mv pp and the background noise is about 50mv pp. If the signal is higher the duty cycle jitter disappears. The main problem with the detector is that it is sensitive to background impulse noise (false highs).

      More Code improvements

      Spent the last few days testing code. I think I am at the end (can't think of anything else to try). The final version consists of a bandpass, switching mixer and a low pass:

      • Bandpass: Fc=1625 Hz, Q=1, Gain=4
      • Switching mixer: Delay=6, Gain=4
      • Low pass: Fc=585 Hz (critically damped)

      The DC bias problems at the switching mixer are solved by the bandpass filter much better than the DC bias filter.

      The DC bias problems after the low pass was solved by increasing the gain (i.e. an integer maths problem).

      Here are the signals:

      The input signal:

      After the bandpass filter:

      After switch mixing:

      After the lowpass filter:

      And finally the demodulated signal (shown against the buad clock):

      The input signal about 0.77v pp and the demodulator works down to 0.001mv pp (+/1 LSB of the ADC!).

      Execution Time

      The measured execution time of the ISR (including the ISR overhead of 2.6 us) was:

      • 33.3 us total
      • 8.6 us to drive the output wave form
      • 20.1 us to decode the input signal (including 17.2 us for the ADC conversion)

      The total time between interrupts is 75.7 us.

      A very tight fit if I want to use a 150 baud back channel as per the specification.

      Here is the current code:

      // Bell 202 modem
      #define Fspace     1200
      #define Fmark      2200
      #define Fsample   13200
      #define Baud       1200
      #define sampleTicks  66     // sampleTicks = Fsample / Fmark * Fsample / Fspace
      // 2 bit Sine table for Fsample equal to 13200 Hz 
      const byte sin2Bit[sampleTicks] = {
      // Define various ADC prescaler
      const byte PS_16=(1<<ADPS2);
      const byte PS_32=(1<<ADPS2)|(1<<ADPS0);
      const byte PS_64=(1<<ADPS2)|(1<<ADPS1);
      const byte PS_128=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
      void setup() {
        pinMode(A0,INPUT);                               // Audio input
        pinMode(12,OUTPUT);                              // Digital data output
        pinMode(11,OUTPUT);                              // Audio output bit 1
        pinMode(10,OUTPUT);                              // Audio output bit 0 
        pinMode(LED_BUILTIN,OUTPUT);                     // Test loop speed
        // Set ADC prescaler (assume a 16 MHz clock)
        ADCSRA&=~PS_128;                                 // Remove bits set by Arduino library
        ADCSRA|=PS_16;                                   // 16 prescaler (1 MHz)
        // About 17.2 us to return an ADC value but only good for 6 bits (probably more)
        cli();                                           // Disable interrupts
        // ATmega48A/PA/88A/PA/168A/PA/328/P
        // Use Timer 0 for sample rate (13.2 kHz)
        // Note delay() and millis() will no longer work (use microseconds() instead) 
        TIMSK0 = 0;                                      // Timer interrupts OFF
        TCCR0A = (2 << WGM00);                           // CTC mode
        TCCR0B = (2 << CS00);                            // prescaler 8, 2 MHz clock
        TIMSK0 = (1 << OCIE0A);                          // COMPA interrupt
        OCR0A = 151;                                     // Sample rate: 2 MHz/152 = 13.2 kHz
        sei();                                           // Enable interrupts 
      // Total execution time 33.3 us including interrupt overhead of 2.6us
      volatile byte DataIn=0;
      volatile byte DataOut=1;
      volatile byte baudTick=11;
      ISR(TIMER0_COMPA_vect) {
        static byte Phase=0;
        static int SX0=0,SX1=0,SX2=0;
        static int BP0=0,BP1=0,BP2=0,BP3=0,BP4=0,BP5=0,BP6=0;
        static int MX0=0,MX1=0,MX2=0;
        static int LP0=0,LP1=0,LP2=0;
        // Audio output (8.6 us)
      Read more »

    • Modem Version 2

      agp.cooper01/23/2017 at 02:56 0 comments

      Modem Version 2

      Here it is:

      Testing the Output

      Here is a 1200Hz output at the DAC:

      An after the low pass filter:

      The designed peak to peak voltage is 3v. The output is offset to maximise the emitter follower voltage swing.

      Same again for 2200Hz:

      And after the low pass filter:

      The designed peak to peak voltage is 2v.

      Here is a binary signal after the low pass filter:

      Note the amplitude modulation.

      Here is a random signal after the low pass filter:

      So at this point all good.

      On the Receiving Side

      The modem did pick up and demodulate a 500 uW audio signal from the speaker at about 1 cm away from the microphone but the microphone and transistor amplifier are rather non-linear with 1 to 2 volt voltage swings and is demodulating the amplitude modulation on the input signal:

      Note that the top of the signal has less range than the bottom of the signal.

      Demodulation Updates

      Had some problems demodulating the audio signal. Found some coding errors introduced in the last code update. Fixed. I also reworked the high pass to more aggressively remove the DC bias and to undo the low pass mark/space amplitude differences.

      Here is the audio signal (~0.7 vpp) after the pre-amp and the demodulated signal (note that the demodulated signal is delayed by about 1 bit:

      Have to be happy about this!

      More work is required because demodulation fails at less than 0.5 vpp. With about 500 uW of speaker power and the speaker about 1 cm away from the microphone, the audio signal amplitude post the pre-amp is about 1 vpp (about where I want it).

      Perhaps I need to consider some automatic gain control (AGC)?

      Fine Tuning the Code

      Debugging interrupt service routines (ISR) on an Arduino is hard work. You cannot just print debug information from inside the ISR. There are ways around this.

      Anyway, I exported the variable data, line by line, checking and correcting. Had to relearn operator precedence order, and changed the DC bias code to something I found on the Internet (thanks: sam-koblenski.blogspot.com.au/2015/11/everyday-dsp-for-programmers-dc-and.html). Added another DC bias adjustment to the correlation output. It works very well now, down to just above the noise level (i.e. the fan of my oscilloscope delivers 100 mV pp post the pre-amplifier). Here is the demodulator code:

        // Decode the data
        Sx=analogRead(A0)-512;                  // 18 us
        X0=Sx+(3*X1>>2);Y0=X0-X1;               // Remove DC offset
        Z0=(Y6>=0)?Y0:-Y0;                      // Switching mixer
        F0=(Z0+Z1+Z1+Z2+F1*40-F2*12)>>5;        // 600 Hz low pass filter (8 us)
        G0=F0+(3*G1>>2);H=G0-G1;                // Remove DC offset
        DataIn=(H>0)?1:0;                       // Test correlation
      Note: all variables are 16 bit integer.

      I don't think I need any more sensitivity but if I did, then filtering off of the high frequency noise would help (i.e. the demodulator is sensitive to any frequency above 1700 Hz as the mark frequency). I could roll off the microphone a little faster by adding a 2.2uF across the microphone pins. Actually, that did not work, it made it worse - parasitic oscillation? Here is the current strip-board layout:

      Other options to reduce the noise is a high-pass in hardware or software.



    • ​Working Out the Audio Path

      agp.cooper01/22/2017 at 01:57 0 comments

      Working Out the Audio Path

      Microphone Estimate Check

      Here is my estimate for speaking into a microphone 25 mm away:

      Speaking into a microphone Estimate
      Voice at 1 m60.0dB SPL (1 W / 1 m)
      No Power Adjustment0.0dB
      SPL (uP) -> V rms (the magic number!)-74.0dB
      Microphone Sensitivity-63.0dB
      Microphone Rated at 1k Load0.0dB
      Assume an effective 25 mm mouth to microphone spacing32.0dB
      Amplifier Gain (x1)0.0dB
      Voltage (rms)-45.0dB
      Voltage (rms)5.623mV rms
      Voltage (pp)15.905mV pp

      So is the mathematics right?

      Jack Smith (www.cliftonlaboratories.com/microphone_output_level.htm) piblished:

      "The image below is at a speaking level more typical of what I would use in a normal QSO. Although there are a few peaks of 40 mV or more, the majority of the speech is around 20 mV peak-to-peak."

      So my estimate is reasonable.

      iPhone Output Level

      Next, what is the output level of the iPhone in normal handset mode?

      Hard to find on the Internet but a "dial tone" was quoted at 80 dB. This sounds okay, 80 dB is the level where you raise your voice to be heard and beyond that you risk long term hearing damage.

      On that basis I can expect 4 vpp from the microphone (assuming I use the standard 1k load resistance, the microphone sensitivity is proportional to the load resistance within limits):

      Dial Tone Estimate
      Telephone Dial Tone80.0dB SPL (1 W / 1 m)
      No Power Adjustment0.0dB
      SPL (uP) -> V rms-74.0dB
      Microphone Sensitivity-63.0dB
      Microphone rated at 1k load0.0dB
      Assume an effective 10 mm speaker to microphone spacing0.0dB
      Amplifier Gain (x1)0.0dB
      Voltage (rms)-57.0dB
      Voltage (rms)1.413mV rms
      Voltage (pp)3.995mV pp

      Here I have had to assume an effective speaker to microphone distance of 10 mm.

      Modem Speaker to iPhone Estimate

      Here I have made two calculations: the first is normal speaking into an iPhone and the second the modem. The main difference is the power and distance from the "speaker" to the microphone:

      Voice to Iphone
      Speaker Sensitivity60.0dB SPL (1 W / 1 m)
      No Power Adjustment0.0dB
      Distance Correction (50 mm)26.0dB
      Sound Level86.0dB
      Speaker to Iphone
      Speaker Sensitivity80.0dB SPL (1 W / 1 m)
      Power Adjustment (4 mW)-48.0dB
      Distance Correction (10 mm)40.0dB
      Sound Level72.0dB

      There is a difference af 14 dB (x5) but this is well within the AGC range of the iPhone.

      So the current design is workable.

      iPhone to Modem Microphone Estimate

      This question is more about the amount of gain required for the modem microphone:

      Modem Receive Estimate
      iPhone Output80.0dB SPL (1 W / 1 m)
      No power adjustment0.0dB
      SPL (uP) -> V rms-74.0dB
      Microphone Sensitivity-63.0dB
      Microphone rated at 1k load0.0dB
      Assume an effective 10 mm speaker to microphone spacing0.0dB
      Amplifier Gain (x200)46.0dB
      Voltage (rms)-11.0dB
      Voltage (rms)0.283V rms
      Voltage (pp)0.799V pp

      As the target average uP signal is about 0.7 vpp in order to maximise the dynamic range (5 v down to 0.1 v), a microphone gain of x200 is required. An LM386 would work well here.

      The AM4011 Microphone

      Checking the bias current for the AM4011 microphone:

      Voltage across microphone Microphone Current
      2.2 v0.31 mA
      4.4 v0.32 mA
      7.7 v0.36 mA

      Based on the above measurements, a 5v supply and a 10k load resistor will work fine (approximately 2 volts across the microphone). This suggests a 20 dB gain improvement over the 1k load resistor test condition.

      This suggest I will have to reduce the microphone amplifier back to maintain 1 vpp:

      Modem Receive Estimate
      iPhone Output 80.0 dB SPL (1 W / 1 m)
      No power adjustment 0.0 dB
      SPL (uP) -> V rms -74.0 dB
      Microphone Sensitivity (rated at 1k load) -63.0 dB
      10k Microphone Load Resistor 20.0 dB
      Assume an effective 10 mm speaker to microphone spacing 0.0 dB
      Amplifier Gain (x25) 28.0 dB
      Voltage (rms) -9.0 dB
      Voltage (rms) 0.353 V rms
      Voltage (pp) 0.999 V pp

      We will see if the microphone amplifier can be dropped back to a gain of only 28 dB!

      Microphone Test In-Circuit

      I assembled Modem V2 and checked the microphone circuit. The microphone worked well but only had 0.9v across it? Checked the circuit for wiring errors and incorrect component...

      Read more »

    • The Audio Interface

      agp.cooper01/16/2017 at 05:32 9 comments

      The Audio Interface

      Connecting the microprocessor (uP) to an 8 ohm speaker and to an 8 ohm speaker used as a microphone is tricky. Tricky if you want it clean (no PWM in the out put) and simple (i.e. low part count and garden variety components).

      Op Amps

      The problems here are simple power supply, voltage swing, input noise and output current capacity (i.e. output impedance).

      The old single supply contenders (from my local electronics store) are:

      • LM324
      • LM3900
      • CA3140

      With a newer:

      • LMC6482 or LMC6384.

      None of these are low noise but the LMC6482/4 is rail to rail and rated at 600 ohm output impedance. So none of them will drive an 8 ohm speaker directly.

      One option is to add a push-pull transistor circuit to the output:


      An LM386 will drive an 8 ohm speaker directly and has a 50k imput impedance, gain is programmable from 20 to 200.

      For this application, an LM386 has merit. The gain bandwidth (5Mz) and input impedance is high enough for a multi-feedback band pass. Here is a schematic of a Sallen Key band pass:

      I have used an ideal OpAmp instead of the real thing as TinaTi does not have it.

      The gain of the 386 has been set to x20. As the 386 has an output voltage swing of the supply voltage less 2 volts, the 5v PWM input has been attenuated for an output of 2.5 volts peak to peak. I added a 1u capacitor to the attenuator network to roll off the high frequency faster. I have not shown the zobel network or the other 386 circuity.


      No problems, here is a narrow band speaker driver/buffer:

      Note that the 25R is the atmega328p output impedance but the 100R is to limit the current to the maximum permitted.

      And here is the frequency response:

      The buffer has a -7bB loss but the 31kHz PWM frequency is attenuated a further -28dB.

      Quiescent current is about 13 mA according to the simulation.

      A speaker microphone input circuit would look like this:

      Source: www.next.gr/uploads/51/sp_mic.gif

      This image is a common base followed by a common collector (an emitter follower). (The emitter follower is rather useless here!)

      Transformers and LC Filters

      Good audio transformers are bulky and expensive.

      I did spend some time looking at LC impedance matching but high Q (low resistance) components are also quite bulky. I have some suitable toroids (FT-68-??) that are good to 300kHz with an Al of 1.06 uH per turn.

      Here is the type of design I have looked at:

      Due to impedance matching the circuit delivers x3.4 the power to the speaker than using just a 100R to limit the current. Other than the steep high frequency roll off it does not seem worth it.

      A good place to put the LC filter is on the output of the audio amp:

      A 470uH toroid is just 21 turns on the above toroid. Here is the frequency response:

      Two Options Done

      I have designed a transistor and a LM386 versions.

      The Transistor Version

      Here is the transistor version strip-board design:

      Here is the final PWM buffer:

      And the final pre-amp:

      The problem with the transistor version is that at this level of complexity it will need to be debugged (built and tested in stages).

      The LM386 Version

      Back to the LM386 version:

      Here is the PWM buffer (less the Zobel network):

      Basically a three pole RC LP filter and attenuator. The output voltage is 2v pp for a 67% setting on the potentiometer. The maximum output voltage without sever distortion is about 2.2v peak to peak.

      The LM386 spice model came from https://hackaday.io/g4lvanix

      (https://github.com/g4lvanix/Spice-models/blob/master/sub/LM386.sub), thanks.

      Still Not Good Enough!

      The LM386 version is at the near foolproof stage, the lesson appears to be that PWM is a "tough nut to crack".

      Two thoughts:

      1. The power output for a an acoustic iPhone modem needs only to be a few mW rather than a max power of 75 mW available from the LM386 (except for experiments using a "loud" speaker).
      2. A simple resistor ladder for direct digital to analog conversion would simplify the filtering requirements (and free up a timer).

      Solving the DAC Maths

      To solve this problem I created a simple spreadsheet and modelled a HP RC filter...

      Read more »