Open jk0 opened 9 years ago
Adding a modulation index is quite simple, so it will no problem to add new optional parameter. Timing is worse case, as there is no timing correction in this project - fm_transmitter uses internal system time counter to determine currently transmitted sound sample (frequency), so the transmission in "lossy", but the timings are kept. Ofcourse it is still possible to add some correction, but as the system clock is pretty accurate, I'm not sure if it's required.
FWIW, and I have absolutely no idea if this was right, but I lowered the 16.0 in the following line to 4.0 and was at least able to pick up the transmissions on the 2m band. They were very noisy and the sound quality was barely intelligible, but the signals were there:
https://github.com/markondej/fm_transmitter/blob/master/transmitter.cpp#L194
Again that might not be the right way to do it, but it does lead me to believe 2m support is possible with some additional tweaking.
The constant, you changed, is scaling factor for modulation index. It defines the bandwidth (more or less).
Where this scaling factor's value comes from?
In order to produce clock signal of given frequency you have to take one of a system's PLL frequencies and divide it with some factor. RPi PLL (D) is about 500MHz, so to create 300MHz signal you should divide this value by 1.66666(6). Call this "clock divisor". As its hard to operate on fractional numbers, divisors are passed as integer numbers shifted left 12 times (multiplied by 4096). You can calculate requested clock divisor value with this formula: DIVISOR = PLL_FREQ * 4096 / FREQUENCY.
https://github.com/markondej/fm_transmitter/blob/master/transmitter.cpp#L106
Every FM transmission has it's bandwith. Bandwith is in fact difference between maximal and minimal frequencies used to transmitt data. So maximal/minimal clock divisors can be computed: DIVISOR_MAX = PLL * 4096 / (FREQ - BANDWIDTH / 2) DIVISOR_MIN = PLL * 4096 / (FREQ + BANDWIDTH / 2) The difference between those will define how many discrete values clock divisor may obtain in order to transmitt data with given frequency and given bandwith (more equals better sound quality).
The scaling factor should be equal half of this difference.
Classic UKF radio signal has 200kHz wide band, so for 100MHz FM transmission there are 40 possible values of clock divisor in order to represent audio signal. 2-meter band radio use higher frequencies and much narrower bandwidth, so assuming 144 MHz carrier frequency and 100kHz bandwidth, there will be only 9 discrete values of clock divisor available. The sound quality would be poor (and scaling factor would be eaqual 4 like in your case).
Solution?
fm_transmitter, in order to transmitt data, creates new thread, where samples are transmitted with use of CPU (ARM), to clock controller. As PiFm project use a way much faster way to transfer clock divisor values - DMA controller, guys made smart feature: they are using discrete clock divisor too, but changing it's value more than once per sample. I.e. if they need to send value 1,5, they are sending 1 in first half of sample duration, and 2 in second half.
I dont want to use DMA, as I found it unrealiable on RPi2, but currently I wonder if it is possible to use GPU to make transmission process more realiable. If so, 2m band support would be possible too [if Broadcom documentation is wrong: "The maximum operating frequency of the General Purpose clocks is ~125MHz at 1.2V but this will be reduced if the GPIO pins are heavily loaded or have a capacitive load."]
Sorry for my English.
Thanks for the clarification -- most of it is way beyond me, but it makes sense. :)
The ultimate goal for me is to be able to use this as the transmitter in @sm0svx's svxlink software (https://github.com/sm0svx/svxlink), making the RPI an almost self-contained EchoLink/repeater controller node. I'm using a RTLSDR for receiver, so the last piece of the puzzle is getting this to support the 2m band and then figuring out how to redirect output to svxlink.
I think one option would be to have fm_transmitter read from a named pipe. Would that be much work to support?
Here is how pifm did it: https://github.com/rm-hull/pifm/commit/eb913eabb7d3357c917e446cd9118cbd9cfd3c34
@markondej any thoughts on the above comments?
Sorry, I didn't have much free time lately. Named pipes sounds good, I'll try to add them in new branch. Currently I'm working on use of the QPU's in order to control clocks, so sound quality would be better.
Hi @markondej, has there been any progress on 2m band support?
Hi, I've already managed to use one of the QPU's as a simple DMA controller, but QPU programming is quite hard as there are no examples and only little info available, so it takes time.
How's this coming along? :)
I've encountered some problems. For more info see:
https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=128309
Does this mean there is still hope? :)
Hi @markondej,
It looks like @JamesP6000 figured out how to TX on the 2M band here: https://github.com/JamesP6000/WsprryPi
Would this be helpful for implementing into fm_transmitter?
Added full DMA support and custom bandwidth settings. 2m band FM should now be supported but I don't have any receiver to confirm if it works like should
I would like to know if the program now supports frequencies below the FM range. I am interested in transmitting on the Citizens Band (CB) in the US which is 27 Mhz and also on the other Ham radio bands which are all below the FM radio range, ie. 80 m, 40 m, 20 m, 10 m, and 6 m. I think with some tweaks the Pi could be a very good digital platform for Ham radio if this can be done.
@markondej Very cool project. I am also trying to get this software to work with 2 meter band. It appears the issue is the bandwidth, using a pi zero w, if I enter a bandwidth below 10.49 khz, the squelch on my radio is open but the broadcast is silent. If it is at or above 10.49 the sound comes through. This is a bit more than the radio can handle for bandwidth and sometimes it closes the squelch. 2 meter band at 144.5 mhz, signal is typically 5 khz bandwidth and sometimes 2.5 khz if the narrow band is used. Running on the 200 khz normal fm frequencies, 89mhz it sounds great. I messed around with the dma settings but don't fully undstand what it is adjusting.
Any thoughts on brining the bandwidth down would be appreciated.
I am thrill to get your software working after messing around with a couple other pifm and sstv pieces, I was actually able to send an sstv picture with yours over 144.5mhz, a little grainy but it did work!!
I would like to know if the program now supports frequencies below the FM range.
I don't believe it currently supports AM or SSB modulation, which are commonly used on the lower bands.
I looked at this some more, for the idea of APRS on Raspberry Pi + a wire. As the modulation bandwidth is lowered, divisorRange gets lower and lower. I tried adding dithering, and it seemed to help a little, but eventually divisorRange reaches 1.
From what I can tell, this modulator is much like an SFCW radar transmitter - effectively there are discrete tones chosen by dividing PLLD(750MHz or 500MHz depending on model) with a 12-bit fractional divider. @markondej, is my understanding correct?
Ex: for my 2011 Raspberry Pi, with 500MHz PLLD, 500mhz(2^12)/144.390MHz is about 14183.8, so we could divide by 14183 or 14184, but when we do, we find the separation between tones to be about 10.2kHz apart: 500MHZ(2^12)/14183-500MHZ*(2^12)/14184 ). This is similar to driving a VCO with a DAC and being limited to only 2 codes.
Moving to a Pi version with 750MHz would get to around 6.8kHz between tones around 144.390MHz
Perhaps increasing the sample rate might help some too?
You can also do a harmonic transmitter, but you must use a high-pass filter as well, since you'd do so by tuning the transmitter below your target frequency by an integer factor and splattering on anything in between.
@rsaxvc Your understanding is correct. The problem is poor frequency divider resolution at high frequencies. There are some techniques allowing bypass this issue, like increasing sampling rate, as You mentioned, which allows subsampling. Subsampling gives us some other pros also, i.e. higher audio quality (lower tones), stereo and RDS mixing. On Raspberry Pi sampling rate can be maintained either via software (by using system clock - use "-d 255" to check this option) or hardware - PWM or PCM IRQ requests to DMA controller. Software way is slow so higher sampling freq is not reachable. Hardware implementation is more appropriate, but... PWM or PCM clocks at higher frequencies are glitchy. That's why there are some hardcoded constants in oryginal code by Oliver Mattos and Oskar Weigl (pifm.c, see: http://omattos.com/pifm.tar.gz):
clocksPerSample = 22500.0 / rate * 1373.5; // for timing, determined by experiment
That's also reason why I did not implemented resampler so far: those hardcoded values varies between base sampling rate, RPi board revision etc. and I wanted program running on any RPi board. I was planning to add this as an option in later releases but because of lack of time this didn't happend yet.
Would it be possible to add support for the 2m ham band? It looks like it's a pretty straightforward change, as seen here in PiFM:
http://www.instructables.com/id/Raspberry-Pi-security-Slow-Scan-Television-Camera/step4/Reducing-the-bandwidth/ http://www.instructables.com/id/Raspberry-Pi-security-Slow-Scan-Television-Camera/step5/Fixing-the-timing/
Let me know if there is anything I can do to help.
Thanks!