-
Notifications
You must be signed in to change notification settings - Fork 82
Adding support for the minghe mhs5200 #150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
36a1e49
added mhs5200
CatherineH 2e2a64a
added minghe function generator
CatherineH f1865dd
added absolute_import
CatherineH 945b1dc
Merge pull request #149 from Galvant/develop
CatherineH 0f7eff4
fixed scaling on frequency
CatherineH 84da64c
switched to abstract instrument class
CatherineH 07cf48a
fixed a few docstrings
CatherineH ac6aa9d
after testing with device
CatherineH fa654cc
Minghe MHS5200 - Add instrument to docs
scasagrande 87b8dec
isolating changes from cc1 test station:
CatherineH c459283
Revert "isolating changes from cc1 test station:"
CatherineH ffacae7
reverting changes and fixing duty cycle
CatherineH a3c800a
Merge branch 'develop' into ch-mhs-mhs5200
scasagrande 0066802
Update for new FunctionGenerator multichannel consistency update
scasagrande File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| #!/usr/bin/python | ||
| from instruments.minghe import MHS5200 | ||
| import quantities as pq | ||
|
|
||
| mhs = MHS5200.open_serial(vid=6790, pid=29987, baud=57600) | ||
| print(mhs.serial_number) | ||
| mhs.channel[0].frequency = 3000000*pq.Hz | ||
| print(mhs.channel[0].frequency) | ||
| mhs.channel[0].function = MHS5200.Function.sawtooth_down | ||
| print(mhs.channel[0].function) | ||
| mhs.channel[0].amplitude = 9.0*pq.V | ||
| print(mhs.channel[0].amplitude) | ||
| mhs.channel[0].offset = -0.5 | ||
| print(mhs.channel[0].offset) | ||
| mhs.channel[0].phase = 90 | ||
| print(mhs.channel[0].phase) | ||
|
|
||
| mhs.channel[1].frequency = 2000000*pq.Hz | ||
| print(mhs.channel[1].frequency) | ||
| mhs.channel[1].function = MHS5200.Function.square | ||
| print(mhs.channel[1].function) | ||
| mhs.channel[1].amplitude = 2.0*pq.V | ||
| print(mhs.channel[1].amplitude) | ||
| mhs.channel[1].offset = 0.0 | ||
| print(mhs.channel[1].offset) | ||
| mhs.channel[1].phase = 15 | ||
| print(mhs.channel[1].phase) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| .. | ||
| TODO: put documentation license header here. | ||
|
|
||
| .. currentmodule:: instruments.minghe | ||
|
|
||
| ====== | ||
| Minghe | ||
| ====== | ||
|
|
||
| :class:`MHS5200` Function Generator | ||
| =================================== | ||
|
|
||
| .. autoclass:: MHS5200 | ||
| :members: | ||
| :undoc-members: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
| Module containing MingHe instruments | ||
| """ | ||
| from __future__ import absolute_import | ||
| from .mhs5200a import MHS5200 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,235 @@ | ||
| #!/usr/bin/env python | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
| Provides the support for the MingHe low-cost function generator. | ||
|
|
||
| Class originally contributed by Catherine Holloway. | ||
| """ | ||
|
|
||
| # IMPORTS ##################################################################### | ||
|
|
||
| from __future__ import absolute_import | ||
| from __future__ import division | ||
|
|
||
| from builtins import range | ||
| from enum import Enum | ||
|
|
||
| import quantities as pq | ||
| from instruments.abstract_instruments import FunctionGenerator | ||
| from instruments.util_fns import ProxyList, assume_units | ||
|
|
||
| # CLASSES ##################################################################### | ||
|
|
||
|
|
||
| class MHS5200(FunctionGenerator): | ||
| """ | ||
| The MHS5200 is a low-cost, 2 channel function generator. | ||
|
|
||
| There is no user manual, but Al Williams has reverse-engineered the | ||
| communications protocol: | ||
| https://github.com/wd5gnr/mhs5200a/blob/master/MHS5200AProtocol.pdf | ||
| """ | ||
| def __init__(self, filelike): | ||
| super(MHS5200, self).__init__(filelike) | ||
| self._channel_count = 2 | ||
| self.terminator = "\r\n" | ||
|
|
||
| def _ack_expected(self, msg=""): | ||
| if msg.find(":r") == 0: | ||
| return None | ||
| # most commands res | ||
| return "ok" | ||
|
|
||
| # INNER CLASSES # | ||
|
|
||
| class Channel(FunctionGenerator.Channel): | ||
| """ | ||
| Class representing a channel on the MHS52000. | ||
| """ | ||
| # pylint: disable=protected-access | ||
|
|
||
| __CHANNEL_NAMES = { | ||
| 1: '1', | ||
| 2: '2' | ||
| } | ||
|
|
||
| def __init__(self, mhs, idx): | ||
| self._mhs = mhs | ||
| super(MHS5200.Channel, self).__init__(parent=mhs, name=idx) | ||
| # Use zero-based indexing for the external API, but one-based | ||
| # for talking to the instrument. | ||
| self._idx = idx + 1 | ||
| self._chan = self.__CHANNEL_NAMES[self._idx] | ||
| self._count = 0 | ||
|
|
||
| def _get_amplitude_(self): | ||
| query = ":r{0}a".format(self._chan) | ||
| response = self._mhs.query(query) | ||
| return float(response.replace(query, ""))/100.0, self._mhs.VoltageMode.rms | ||
|
|
||
| def _set_amplitude_(self, magnitude, units): | ||
| if units == self._mhs.VoltageMode.peak_to_peak or \ | ||
| units == self._mhs.VoltageMode.rms: | ||
| magnitude = assume_units(magnitude, "V").rescale(pq.V).magnitude | ||
| elif units == self._mhs.VoltageMode.dBm: | ||
| raise NotImplementedError("Decibel units are not supported.") | ||
| magnitude *= 100 | ||
| query = ":s{0}a{1}".format(self._chan, int(magnitude)) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| @property | ||
| def duty_cycle(self): | ||
| """ | ||
| Gets/Sets the duty cycle of this channel. | ||
|
|
||
| :units: A fraction | ||
| :type: `~quantities.Quantity` | ||
| """ | ||
| query = ":r{0}d".format(self._chan) | ||
| response = self._mhs.query(query) | ||
| duty = float(response.replace(query, ""))/10.0 | ||
| return duty | ||
|
|
||
| @duty_cycle.setter | ||
| def duty_cycle(self, new_val): | ||
| query = ":s{0}d{1}".format(self._chan, int(100.0*new_val)) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| @property | ||
| def enable(self): | ||
| """ | ||
| Gets/Sets the enable state of this channel. | ||
|
|
||
| :param newval: the enable state | ||
| :type: `bool` | ||
| """ | ||
| query = ":r{0}b".format(self._chan) | ||
| return int(self._mhs.query(query).replace(query, ""). | ||
| replace("\r", "")) | ||
|
|
||
| @enable.setter | ||
| def enable(self, newval): | ||
| query = ":s{0}b{1}".format(self._chan, int(newval)) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| @property | ||
| def frequency(self): | ||
| """ | ||
| Gets/Sets the frequency of this channel. | ||
|
|
||
| :units: As specified (if a `~quantities.Quantity`) or assumed to be | ||
| of units hertz. | ||
| :type: `~quantities.Quantity` | ||
| """ | ||
| query = ":r{0}f".format(self._chan) | ||
| response = self._mhs.query(query) | ||
| freq = float(response.replace(query, ""))*pq.Hz | ||
| return freq/100.0 | ||
|
|
||
| @frequency.setter | ||
| def frequency(self, new_val): | ||
| new_val = assume_units(new_val, pq.Hz).rescale(pq.Hz).\ | ||
| magnitude*100.0 | ||
| query = ":s{0}f{1}".format(self._chan, int(new_val)) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| @property | ||
| def offset(self): | ||
| """ | ||
| Gets/Sets the offset of this channel. | ||
|
|
||
| :param new_val: The fraction of the duty cycle to offset the | ||
| function by. | ||
| :type: `float` | ||
| """ | ||
| # need to convert | ||
| query = ":r{0}o".format(self._chan) | ||
| response = self._mhs.query(query) | ||
| return int(response.replace(query, ""))/100.0-1.20 | ||
|
|
||
| @offset.setter | ||
| def offset(self, new_val): | ||
| new_val = int(new_val*100)+120 | ||
| query = ":s{0}o{1}".format(self._chan, new_val) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| @property | ||
| def phase(self): | ||
| """ | ||
| Gets/Sets the phase of this channel. | ||
|
|
||
| :units: As specified (if a `~quantities.Quantity`) or assumed to be | ||
| of degrees. | ||
| :type: `~quantities.Quantity` | ||
| """ | ||
| # need to convert | ||
| query = ":r{0}p".format(self._chan) | ||
| response = self._mhs.query(query) | ||
| return int(response.replace(query, ""))*pq.deg | ||
|
|
||
| @phase.setter | ||
| def phase(self, new_val): | ||
| new_val = assume_units(new_val, pq.deg).rescale("deg").magnitude | ||
| query = ":s{0}p{1}".format(self._chan, int(new_val)) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| @property | ||
| def function(self): | ||
| """ | ||
| Gets/Sets the wave type of this channel. | ||
|
|
||
| :type: `MHS5200.Function` | ||
| """ | ||
| query = ":r{0}w".format(self._chan) | ||
| response = self._mhs.query(query).replace(query, "") | ||
| return self._mhs.Function(int(response)) | ||
|
|
||
| @function.setter | ||
| def function(self, new_val): | ||
| query = ":s{0}w{1}".format(self._chan, | ||
| self._mhs.Function(new_val).value) | ||
| self._mhs.sendcmd(query) | ||
|
|
||
| class Function(Enum): | ||
| """ | ||
| Enum containing valid wave modes for | ||
| """ | ||
| sine = 0 | ||
| square = 1 | ||
| triangular = 2 | ||
| sawtooth_up = 3 | ||
| sawtooth_down = 4 | ||
|
|
||
| @property | ||
| def channel(self): | ||
| """ | ||
| Gets a specific channel object. The desired channel is specified like | ||
| one would access a list. | ||
|
|
||
| For instance, this would print the counts of the first channel:: | ||
|
|
||
| >>> mhs = ik.minghe.MHS5200.open_serial(vid=1027, pid=24577, | ||
| baud=19200, timeout=1) | ||
| >>> print(mhs.channel[0].frequency) | ||
|
|
||
| :rtype: `list`[`MHS5200.Channel`] | ||
| """ | ||
| return ProxyList(self, MHS5200.Channel, range(self._channel_count)) | ||
|
|
||
| @property | ||
| def serial_number(self): | ||
| """ | ||
| Get the serial number, as an int | ||
|
|
||
| :rtype: int | ||
| """ | ||
| query = ":r0c" | ||
| response = self.query(query) | ||
| response = response.replace(query, "").replace("\r", "") | ||
| return response | ||
|
|
||
| def _get_amplitude_(self): | ||
| raise NotImplementedError() | ||
|
|
||
| def _set_amplitude_(self, magnitude, units): | ||
| raise NotImplementedError() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.