guides:radio_modules:lmt2
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
guides:radio_modules:lmt2 [2013/06/12 17:50] – created upu | guides:radio_modules:lmt2 [2016/09/08 14:47] (current) – Removed purchase link to HAB Supplies. upu | ||
---|---|---|---|
Line 1: | Line 1: | ||
===== LMT2 ===== | ===== LMT2 ===== | ||
+ | |||
+ | ==== Overview ==== | ||
+ | |||
+ | The Radiometrix LMT2 is a more advanced version of the NTX2. Its major advantage over the NTX2 is its frequency agility being able to switch channels between 433.850 to 434.650Mhz. Additionally its temperature stability is much better due to the inclusion of a TCXO. | ||
+ | |||
+ | ==== Details ==== | ||
+ | |||
+ | It is possible to linearise the input of the LMT2 by placing a 500k resistor in front of the TXD pin, this has the effect of turning the LMT2's input op amp gain to 1:1 effectively bypassing it. At this point an input voltage of between 0 - 3V on the TXD pin will result in an almost linear increase in output frequency meaning its possible, as with the NTX2, to product RTTY (or other modes). | ||
+ | |||
+ | The frequency change is about 0.000573v per Hz above 0.5V input. I.e about 0.244v will result in a shift in frequency of 425Hz. Below is the frequency response graph : | ||
+ | |||
+ | {{: | ||
+ | |||
+ | LMT2 modules can be powered directly from the batteries having its own internal regulator (3.1V to 15V in). The manufacturers datasheet is here [[http:// | ||
+ | |||
+ | ==== Legislative ==== | ||
+ | |||
+ | The regulatory requirements for airborne operation in Europe on this frequency are that the channel bandwidth must be less than 25Khz and less that 10mW ERP. There are no duty cycle requirements in this frequency band. | ||
+ | Use of this module in the United States requires operation under an amateur license. | ||
+ | |||
+ | ==== Frequency Stability ==== | ||
+ | |||
+ | The LMT2 temperature stability is very good due to the TCXO. Adequate insulation is still recommended, | ||
+ | |||
+ | ==== Where to buy the LMT2 ==== | ||
+ | |||
+ | *[[http:// | ||
+ | |||
+ | ==== Other Notes & Further Reading ==== | ||
+ | |||
+ | Radiometrix are understandably unable to offer technical support on these modules when used in high altitude ballooning therefore please direct all technical support queries regarding the operation of these modules to the UKHAS mailing list or preferably the # | ||
+ | |||
+ | ==== Frequency Selection ==== | ||
+ | |||
+ | LMT2 frequency selection can be done in a very granular basis by amending the values of the N & R registers. | ||
+ | |||
+ | Frequency = N register value x Comparison frequency where 64 <= N <= 65535 | ||
+ | |||
+ | Comparison Frequency = 13MHz (reference oscillator)/ | ||
+ | |||
+ | Comparison Frequency must > 10khz. | ||
+ | |||
+ | Frequency = (13Mhz * N)/R | ||
+ | |||
+ | Example : | ||
+ | |||
+ | 434.121Mhz | ||
+ | |||
+ | Picking R as 1282 Gives Comparison frequency of 10140.40562Hz | ||
+ | |||
+ | So N= 434.121Mhz/ | ||
+ | |||
+ | The actual frequency with these values is 434.120904Mhz so an error of 96Hz. | ||
+ | |||
+ | To aid the calculation of these values Daniel Richman has provided the following code : | ||
+ | |||
+ | <code c> | ||
+ | |||
+ | /* From python fractions.Fraction.limit_denominator | ||
+ | * Originally contributed by Sjoerd Mullender. | ||
+ | * Significantly modified by Jeffrey Yasskin < | ||
+ | * Ported to C by Daniel Richman */ | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | struct frequency_rational | ||
+ | { | ||
+ | uint16_t n; | ||
+ | uint16_t r; | ||
+ | }; | ||
+ | |||
+ | static inline uint32_t hcf(uint32_t a, uint32_t b) | ||
+ | { | ||
+ | while (b) | ||
+ | { | ||
+ | uint32_t temp; | ||
+ | temp = a; | ||
+ | a = b; | ||
+ | b = temp % b; | ||
+ | } | ||
+ | return a; | ||
+ | } | ||
+ | |||
+ | /* 5 seconds on google suggests avr-gcc doesn' | ||
+ | static inline int64_t abs64(int64_t v) | ||
+ | { | ||
+ | if (v < 0) | ||
+ | return -v; | ||
+ | else | ||
+ | return v; | ||
+ | } | ||
+ | |||
+ | /* I ported this blindly from the python fractions module without looking up | ||
+ | * how it works. Besides, I'm more interested in the proof than the why | ||
+ | * the implementation is correct */ | ||
+ | |||
+ | #define max_denominator 1300 | ||
+ | |||
+ | struct frequency_rational frequency_magic(uint32_t on) | ||
+ | { | ||
+ | struct frequency_rational r; | ||
+ | |||
+ | uint16_t p0 = 0, q0 = 1, p1 = 1, q1 = 0, k; | ||
+ | uint32_t q2, a, n, d, h; | ||
+ | uint32_t od = 13000000; | ||
+ | int64_t compare_p0, compare_p1, compare_n; | ||
+ | |||
+ | h = hcf(on, od); | ||
+ | on /= h; | ||
+ | od /= h; | ||
+ | |||
+ | n = on; | ||
+ | d = od; | ||
+ | |||
+ | if (d <= max_denominator) | ||
+ | { | ||
+ | r.n = n; | ||
+ | r.r = d; | ||
+ | return r; | ||
+ | } | ||
+ | |||
+ | for (;;) | ||
+ | { | ||
+ | uint32_t tempd, tempp1, tempq1; | ||
+ | |||
+ | tempd = d; | ||
+ | a = n / d; /* gcc should optimise this to one call to divmod. */ | ||
+ | d = n % d; | ||
+ | n = tempd; | ||
+ | |||
+ | /* if a > max, then q2 > max since after first loop q1 > 1. | ||
+ | * This check ensures it doesn' | ||
+ | if (a > max_denominator) | ||
+ | break; | ||
+ | q2 = q0 + ((uint32_t) (((uint16_t) a) * q1)); | ||
+ | if (q2 > max_denominator) | ||
+ | break; | ||
+ | |||
+ | tempp1 = p1; | ||
+ | tempq1 = q1; | ||
+ | p1 = p0 + ((uint16_t) a) * p1; | ||
+ | q1 = q2; | ||
+ | p0 = tempp1; | ||
+ | q0 = tempq1; | ||
+ | } | ||
+ | |||
+ | k = (max_denominator - q0) / q1; | ||
+ | |||
+ | p0 = p0 + k * p1; | ||
+ | q0 = q0 + k * q1; | ||
+ | |||
+ | /* which of p0/q0 p1/q1 is closest. */ | ||
+ | compare_n | ||
+ | compare_p0 = ((uint64_t) od) * ((uint64_t) p0) * ((uint64_t) q1); | ||
+ | compare_p1 = ((uint64_t) od) * ((uint64_t) q0) * ((uint64_t) p1); | ||
+ | |||
+ | if (abs64(compare_p0 - compare_n) < abs64(compare_p1 - compare_n)) | ||
+ | { | ||
+ | r.n = p0; | ||
+ | r.r = q0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | r.n = p1; | ||
+ | r.r = q1; | ||
+ | } | ||
+ | return r; | ||
+ | } | ||
+ | |||
+ | /* borrowed from Adam's gist */ | ||
+ | int main(int argc, char* argv[]) | ||
+ | { | ||
+ | uint32_t freq_target_hz, | ||
+ | struct frequency_rational r; | ||
+ | |||
+ | if(argc != 2) { | ||
+ | printf(" | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | freq_target_hz = atoi(argv[1]); | ||
+ | printf(" | ||
+ | |||
+ | r = frequency_magic(freq_target_hz); | ||
+ | |||
+ | freq_out = (13000000L * (uint32_t)r.n) / (uint32_t)r.r; | ||
+ | error_out = abs(freq_out - (freq_target_hz)); | ||
+ | printf(" | ||
+ | r.n, r.r, freq_out, error_out); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | 8-Bit Arduino/AVR Version here : | ||
+ | <code c> | ||
+ | |||
+ | /* From python fractions.Fraction.limit_denominator | ||
+ | * Originally contributed by Sjoerd Mullender. | ||
+ | * Significantly modified by Jeffrey Yasskin < | ||
+ | * Ported to C by Daniel Richman | ||
+ | * Ported to AVR with help from Daniel Richman by Anthony Stirk */ | ||
+ | |||
+ | #define max_denominator 1300 | ||
+ | unsigned long startTime; | ||
+ | char txstring[120]; | ||
+ | int32_t freq_target_hz, | ||
+ | uint64_t freq_out; | ||
+ | uint16_t best_r = 0, best_n = 0; | ||
+ | int wibble=0; | ||
+ | struct frequency_rational | ||
+ | { | ||
+ | uint16_t n; | ||
+ | uint16_t r; | ||
+ | }; | ||
+ | static inline uint32_t hcf(uint32_t a, uint32_t b) | ||
+ | { | ||
+ | while (b) | ||
+ | { | ||
+ | uint32_t temp; | ||
+ | temp = a; | ||
+ | a = b; | ||
+ | b = temp % b; | ||
+ | } | ||
+ | return a; | ||
+ | } | ||
+ | static inline int64_t abs64(int64_t v) | ||
+ | { | ||
+ | if (v < 0) | ||
+ | return -v; | ||
+ | else | ||
+ | return v; | ||
+ | } | ||
+ | void setup() { | ||
+ | Serial.begin(9600); | ||
+ | Serial.println(" | ||
+ | } | ||
+ | void loop() { | ||
+ | freq_target_hz = 434201241L; | ||
+ | struct frequency_rational r; | ||
+ | sprintf(txstring," | ||
+ | Serial.println(txstring); | ||
+ | startTime = millis(); | ||
+ | while(wibble< | ||
+ | r = frequency_magic(freq_target_hz); | ||
+ | wibble++; | ||
+ | } | ||
+ | sprintf(txstring," | ||
+ | Serial.println(txstring); | ||
+ | freq_out = (uint64_t)(13000000L * (uint64_t)r.n) / (uint32_t)r.r; | ||
+ | error_out = freq_target_hz - freq_out; | ||
+ | |||
+ | sprintf(txstring," | ||
+ | Serial.print(txstring); | ||
+ | Serial.print(error_out); | ||
+ | Serial.println(" | ||
+ | wibble=0; | ||
+ | } | ||
+ | |||
+ | |||
+ | struct frequency_rational frequency_magic(uint32_t on) | ||
+ | { | ||
+ | struct frequency_rational r; | ||
+ | |||
+ | uint16_t p0 = 0, q0 = 1, p1 = 1, q1 = 0, k; | ||
+ | uint32_t q2, a, n, d, h; | ||
+ | uint32_t od = 13000000; | ||
+ | int64_t compare_p0, compare_p1, compare_n; | ||
+ | |||
+ | h = hcf(on, od); | ||
+ | on /= h; | ||
+ | od /= h; | ||
+ | |||
+ | n = on; | ||
+ | d = od; | ||
+ | |||
+ | if (d <= max_denominator) | ||
+ | { | ||
+ | r.n = n; | ||
+ | r.r = d; | ||
+ | return r; | ||
+ | } | ||
+ | |||
+ | for (;;) | ||
+ | { | ||
+ | uint32_t tempd, tempp1, tempq1; | ||
+ | |||
+ | tempd = d; | ||
+ | a = n / d; /* gcc should optimise this to one call to divmod. */ | ||
+ | d = n % d; | ||
+ | n = tempd; | ||
+ | |||
+ | /* if a > max, then q2 > max since after first loop q1 > 1. | ||
+ | * This check ensures it doesn' | ||
+ | if (a > max_denominator) | ||
+ | break; | ||
+ | q2 = q0 + ((uint32_t) (((uint16_t) a) * q1)); | ||
+ | if (q2 > max_denominator) | ||
+ | break; | ||
+ | |||
+ | tempp1 = p1; | ||
+ | tempq1 = q1; | ||
+ | p1 = p0 + ((uint16_t) a) * p1; | ||
+ | q1 = q2; | ||
+ | p0 = tempp1; | ||
+ | q0 = tempq1; | ||
+ | } | ||
+ | |||
+ | k = (max_denominator - q0) / q1; | ||
+ | |||
+ | p0 = p0 + k * p1; | ||
+ | q0 = q0 + k * q1; | ||
+ | |||
+ | /* which of p0/q0 p1/q1 is closest. */ | ||
+ | compare_n | ||
+ | compare_p0 = ((uint64_t) od) * ((uint64_t) p0) * ((uint64_t) q1); | ||
+ | compare_p1 = ((uint64_t) od) * ((uint64_t) q0) * ((uint64_t) p1); | ||
+ | |||
+ | if (abs64(compare_p0 - compare_n) < abs64(compare_p1 - compare_n)) | ||
+ | { | ||
+ | r.n = p0; | ||
+ | r.r = q0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | r.n = p1; | ||
+ | r.r = q1; | ||
+ | } | ||
+ | return r; | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
guides/radio_modules/lmt2.1371059454.txt.gz · Last modified: 2013/06/12 17:50 by upu