CW generator

Cricri

Member
Hi All ,
my problem ( normal if I am here .. )
I try to do a CW generator for test with noise addition ( will be programmable when OK ..)
My source where there is a mistake as usual for me in attach
The output is a very bad note and the timing is bad , delay is not 5 sec for exemple .
Tried with different " setSampleRate_Hz " with bad results ...
So ???

Help ?
Comments ?
Thanks
Xtian
 

Attachments

  • Codeur_CW_TEST.ino
    3.1 KB · Views: 79
@Cricri: if you look at the radioCWModulator_F32.h source file, you will note that only certain sample rates are supported (there are output warnings sent to the Serial console when an unsupported sample rate is attempted), so I modified the top portion of your setup() function as follows (note that I also added the function call to set the headphone volume as well, for my own testing using headphones):

Code:
   sgtl5000_1.enable();
   sgtl5000_1.volume(0.8);                                 // to enable listening on headphones
   AudioMemory(100);                                       // pour le 16 bits
   AudioMemory_F32(100);                                   // pour le 32 bits
   note.setFrequency(600.0);                               // standard CW tone
   note.setSampleRate_Hz(11025.0);                         // certainly pb here ....
   noise.amplitude(0.01);
   note.amplitude(0.7);
   mix.gain(0, 0.5) ;                                      // note amp
   mix.gain(1, 0.1);                                       // noise amp
   note.setCWSpeedWPM(10);

See if this gets you what you were after . . .

Hope that helps . . .

Mark J Culross
KD5RXT

P.S. I don't have any prior experience with the OpenAudio F32 library, so this was an educational experience for myself as well !! MJC
 
Many Thanks Mark ,
Better than my version for the "note " but on ~2400 Hz ( 4 times the needed )
And the CWspeedWPM is wrong too , at 10 WPM the " dit " must be 120ms and it is ~30 ms

Best 73
Xtian
 

Attachments

  • freq.jpg
    freq.jpg
    241.8 KB · Views: 53
  • WPM.jpg
    WPM.jpg
    211.8 KB · Views: 53
Hi Defragster ,
Removed the line setFrequency ... had the same : 2400 Hz
If I setFrequency at 150 Hz I get 600 Hz !
Xtian
 
setFrequency at 150 Hz I get 600 Hz
Some odd 4::1 funny math somewhere? Pushing the Hz up 4X and at the same time the Time Down 4X

Again, not ever looked at this before - and quick glance at the github Examples I didn't see one for CW?

Are there any other examples used or seen before to run and compare?

On a CLEAN build in Verbose output are there ANY warnings given?

What version of TeensyDuino is in use? There have been recent toolchain updates that may be giving build warning or different behavior?
 
Hi
I use the last toolchains .
I use often the 32 bits Open Arduino , for exemple :

So ... O:)

I am sure that Bob Larkin can solve the problem .

BR
Xtian
 
setSampleRate_Hz(11025.0) will generate 11025 samples per second but you're playing it at 44100... so of course it's 4x too fast.
 
setSampleRate_Hz(11025.0) will generate 11025 samples per second but you're playing it at 44100... so of course it's 4x too fast.

I'll see in this way with the code from Franck B .

And DONE !
See attach working ,

Thanks All !

BR
Xtian
 

Attachments

  • Codeur_CW_TEST.ino
    4.2 KB · Views: 74
I just got here. Thanks, Mark. And it looks like all has been figured out. Great!

Xtian, one other thought, unrelated to sample rates. You are using the uniform distribution white noise. I don't know the end goal, so that may be what you want. But, there is also a Gaussian noise generator, that also has white noise spectrum but a Gaussian amplitude distribution. This corresponds to thermal noise, or due to the Central Limit Theorem, any noise with a large number of additive sources. The other class is
AudioSynthGaussian_F32. That link is to the design tool.

All the best, Bob
 
Hi Bob , All ,
I need to do a a sort " simulator " for testing CW ( Morse ) decoders in quite real world but on the bench .

Ok for the Gaussian Noise generator , will try it ( I am there for that ! O:) )

And I will add a " fading generator " in the loop .... one day

The target : something like " Moon Bounce aleas "

Thanks Bob for your work !
Without you and some others I am nothing ..

PS if you can add some comments on the right part "info " about setSampleRate
for my understanding these fonction act on the total sample rate , that was my mistake .

BR / 73

Xtian / F1VL
 
Did a quick Build on @KenHahn Mini unit and THIS worked to sound sand repeat ( though didn't confirm Dit/Dah )
note.sendStringCW("P A R I S ");

The I rebuilt with string missing trailing space and presents long silence after like 2 chars - then finally repeats that:
note.sendStringCW("P A R I S");

It seems sending the next string too soon terminates - maybe gets confused when there is no terminating 'space':

This is working:
Code:
void CW() {
  if ( 512 == note.getBufferSpace() ) {
    note.sendStringCW("P A R I S");
    note.enableTransmit(1);
  }
}

And sounds like this is working:
Code:
void CW2() {
  char mySz[] = "PARISO";
  int ii = 0;
  if ( 512 != note.getBufferSpace() ) return;
  while ( NULL != mySz[ii] ) {
    note.sendCW(mySz[ii]);
    ii++;
  }
}
 
Last edited:
@Cricri and @Bob Larkin ::
Calling this CW2() without the 512 test shows transmit errors. Too many E==DOTs not 4 - but an increasing number of them over 10 as it runs before the three "Dah Dah Dah"=="O" comes out?

Code:
void CW2() {
  char mySz[] = "EEEEO";
  int ii = 0;
  // if ( 512 != note.getBufferSpace() ) return;
  while ( NULL != mySz[ii] ) {
    note.sendCW(mySz[ii]);
    ii++;
  }

Seems with String or 'Char' the buffer count/empty isn't quite right?
changing to this WORKS {ONLY with the 512 count}: char mySz[] = "EEEEO ";

But just adding a 'SPACE' - plays the space and doesn't get to the "O", just throws in a space?

**test notes may not be accurate and complete other than YMMV and there is a problem.
 
@Bob Larkin : It looks like IndexR is crossing over IndexW because this is called EVERY loop() to add to the queue.

indexR staying ZERO some time because it fills before first character emits?
Code:
44 space    size 9
0 indexR    indexW 477

35 space    size 9
0 indexR    indexW 486

26 space    size 9
0 indexR    indexW 495

17 space    size 9
0 indexR    indexW 504

9 space    size 9
1 indexR    indexW 1

512 space    size 9
1 indexR    indexW 10

503 space    size 9
1 indexR    indexW 19

494 space    size 9
1 indexR    indexW 28

Change to <= : if(space <= size) return false;
Code:
   bool sendStringCW(char* _pStr)
      {
      uint16_t space = getBufferSpace();
      uint16_t size = strlen(_pStr);
      Serial.print(space); Serial.print(" space    size "); Serial.println(size);
      if(space <= size)  return  false;
      for(int kk=0; kk<(int)strlen(_pStr); kk++)
         sendCW( (uint16_t)*(_pStr+kk) );
      Serial.print(indexR); Serial.print(" indexR    indexW "); Serial.println(indexW);
      return true;
      }

With that change it looks like this:
Code:
22 space    size 6
2 indexR    indexW 498

18 space    size 6
4 indexR    indexW 504

12 space    size 6
4 indexR    indexW 510

7 space    size 6
5 indexR    indexW 4

3 space    size 6

5 space    size 6

6 space    size 6

7 space    size 6
11 indexR    indexW 10

3 space    size 6

5 space    size 6

6 space    size 6

7 space    size 6
17 indexR    indexW 16

Test for above code using:
Code:
void loop() {

  CW();
}

void CW() {
  //if ( 512 == note.getBufferSpace() )
  {
    // note.sendStringCW("P A R I S");
    note.sendStringCW("EEEEO ");
    note.enableTransmit(1);
Serial.println();
if ( 20 >= note.getBufferSpace() ) delay(1000);
  }
}
 
Last edited:
It was pulled - thanks! Also, Xtian, I will add more words to the Design Tool side notes. It has a list of allowable sample rates, but is not clear that it only changes the CW rate and tone frequency, and not the sample rate. It will be a little while, as I bunch up the Design Tool changes and additions. Bob
Oh, also I note that there is another change coming up to allow the input to be a simple boolean "key down" that could be controlled by a digital pin in the INO. If enabled, this disables the text sending, but it does include the key-click filtering. That will be along soon.
 
It was pulled - thanks!
Cool! - Thanks Bob. Very good buffer management - what I found was not what I was expecting - just that trivial "=" for "<=" on $string insert.

@Cricri - you'll want to get the updated copy. But of course limiting the amount stuffed into the buffer also likely part of the real usage so this wouldn't have triggered.
 
Can someone try setting setI2SFreq and setSampleRate_Hz to 44100? It didn't work for me. Nor did 96000
I've been meddling with the library and trying to figure out how it works.
One of the things I don't understand is that a comment in radioCWmodulator_F32.cpp says:
Code:
// We always generate CW at 12 ksps.
But when setSampleRate_Hz is called, the variable timeSamplesMs is set to a value based on that sample rate, it's not fixed at 12kHz.

Found a small bug. I also tried a sample rate of 88000Hz but it printed the error that it wasn't supported.
In radioCWmodulator_F32.h it tests for that range of rates with:
Code:
sample_rate_Hz>88000.0f
which should be:
Code:
sample_rate_Hz>=88000.0f

Pete
 
But when setSampleRate_Hz is called, the variable timeSamplesMs is set to a value based on that sample rate, it's not fixed at 12kHz.
I don't see it either! Let me look at this. I have a weekend obligation, so it may be next week before I can address this. So, it looks like a problem for sample rates above 12K. The idea was that 12K is very adequate for any reasonable CW speed and the key-click reduction is already 145 coeffs. So, interpolating up for higher sample rates seemed to be the thing to do. But, it needs fixing! Bob
 
I have found a fix for it. Since it generates the CW at whatever sample rate is requested, the interpolation isn't needed. As a simple workaround remove the code related to interpolation including the interpolation filter. I've tried this and it works at all frequencies from 11025 up to 100000. Unfortunately, it doesn't work at 8000 - which may just be a buffer under/over-run that needs fixing.
I'll try to post code today and , if possible, I'll do a PR.

Pete
P.S. Although it works at all frequencies, the Gaussian filter doesn't work well at all frequencies. At 44100, there is a noticeable (but not annoying) thump at beginning and end of a code element.
 
Hi Pete - Thanks for looking at this. Yes, the Gaussian filter was what drives the generation of the CW waveform at a lower frequency. If we want to support, say, 96 ksps it pushes the coefficient count up to 8*145, which seems big, but I guess is OK in that there is not a lot of other activity during CW transmit. And, the choice of sample rates and Gaussian filters could be at compile time for most applications.

But, if we stay with the 12 ksps generation + interpolation up to 24, 48 or 96 ksps, we would seem to have lower processor use and support most users. For example, if the base sample rate was 48 ksps, for each update() we would generate 128/4 = 32 data points, run these through the Gaussian FIR, fill in the zeros and LP filter and output 128 samples. The signal energy is close (like a few hundred Hz, max) to the sine wave frequency. If this is to be SSB modulation, the sine wave frequency would only need to be in the 600 to 1000 Hz range, so all is simple to filter. If a direct signal at an IF frequency, like 15 kHz, is desired, it might need some special filtering/frequency conversion. For now, it would seem reasonable to not support sine wave frequencies over a few kHz.

Sorry for the random thoughts, but I was wondering how to keep the excellent key click suppression of the Gaussian filter. All ideas are appreciated.

Bob
 
Back
Top